Compare commits

...

10 commits

Author SHA1 Message Date
Elijah
6f3b692c34 add version 2023-04-10 18:09:05 -04:00
Elijah R
3ef2980212
Create .github/workflows/dotnet.yml 2023-04-10 18:06:18 -04:00
a8254a23b5 * Catch WebSocket failure and add connectionfailed event
* Switch registercommand to string[] (idk why it wasnt)
2023-03-22 21:20:11 -04:00
Elijah R
d72094a68b
Update README.md 2023-03-09 15:42:10 -05:00
c793b9f1d8 Merge remote-tracking branch 'origin/master' 2023-03-09 15:38:50 -05:00
6d4c1dcca2 Add commands support 2023-03-09 15:38:39 -05:00
Elijah R
542fac1ac0
Update README.md 2023-03-08 19:46:08 -05:00
Elijah R
af6e22f803
Update README.md 2023-03-08 19:45:55 -05:00
Elijah R
3e9c25b72c
Update README.md 2023-03-08 19:24:52 -05:00
Elijah R
65c8d69434
Create README.md 2023-03-08 19:10:41 -05:00
4 changed files with 115 additions and 3 deletions

36
.github/workflows/dotnet.yml vendored Normal file
View file

@ -0,0 +1,36 @@
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
name: .NET
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
- name: publish to NuGet
id: publish_nuget
uses: tedd/publish-nuget-neo@v1
with:
NUGET_KEY: ${{SECRETS.NUGET_KEY}}
PROJECT_FILE_PATH: CollabVMSharp/CollabVMSharp.csproj
PACKAGE_NAME: CollabVMSharp

View file

@ -8,6 +8,7 @@ using System.Net;
using System.Net.WebSockets;
using System.Security.Authentication;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using SixLabors.ImageSharp;
@ -38,6 +39,7 @@ public class CollabVMClient {
private TurnUpdateEventArgs _currentturn;
private VoteUpdateEventArgs _currentvote;
private WebProxy? _proxy;
private Dictionary<string, Action<string, string[]>> commands;
// Tasks and related
private TaskCompletionSource<Node[]> GotNodeList;
private TaskCompletionSource<bool> GotConnectionToNode;
@ -61,6 +63,7 @@ public class CollabVMClient {
public event EventHandler<ChatMessage[]> ChatHistory;
public event EventHandler ConnectedToNode;
public event EventHandler NodeConnectFailed;
public event EventHandler<string> ConnectionFailed;
public event EventHandler<RectEventArgs> Rect;
public event EventHandler<string> Renamed;
public event EventHandler<UserRenamedEventArgs> UserRenamed;
@ -87,6 +90,7 @@ public class CollabVMClient {
}
this.username = username;
this.node = node;
this.commands = new();
this._rank = Rank.Unregistered;
this._perms = Permissions.None;
this._connected = false;
@ -126,6 +130,7 @@ public class CollabVMClient {
ChatHistory += delegate { };
ConnectedToNode += delegate { };
NodeConnectFailed += delegate { };
ConnectionFailed += delegate { };
Rect += delegate { };
Renamed += delegate { };
UserRenamed += delegate { };
@ -140,8 +145,15 @@ public class CollabVMClient {
/// <summary>
/// Connect to the CollabVM Server
/// </summary>
public async Task Connect() {
await this.socket.ConnectAsync(this.url, CancellationToken.None);
public async Task<bool> Connect() {
try {
await this.socket.ConnectAsync(this.url, CancellationToken.None);
}
catch (WebSocketException e) {
this.ConnectionFailed.Invoke(this, e.Message);
this.Cleanup(false);
return false;
}
this._connected = true;
if (this.username != null)
this.SendMsg(Guacutils.Encode("rename", this.username));
@ -151,6 +163,7 @@ public class CollabVMClient {
this.SendMsg(Guacutils.Encode("connect", this.node));
this.NOPRecieve.Start();
this.WebSocketLoop();
return true;
}
private async void WebSocketLoop() {
@ -224,7 +237,11 @@ public class CollabVMClient {
}
ChatHistory.Invoke(this, msgs.ToArray());
// I should probably add a config option for whether or not the message should be HTML encoded
} else Chat.Invoke(this, new ChatMessage {Username = msgArr[1], Message = WebUtility.HtmlDecode(msgArr[2])});
}
else {
Chat.Invoke(this, new ChatMessage { Username = msgArr[1], Message = WebUtility.HtmlDecode(msgArr[2]) });
this.ProcessCommand(msgArr[1], WebUtility.HtmlDecode(msgArr[2]));
}
break;
}
case "captcha": {
@ -791,6 +808,29 @@ public class CollabVMClient {
await this.SendMsg(Guacutils.Encode("admin", "23"));
}
/// <summary>
/// Register a command for users on the VM to run
/// </summary>
/// <param name="cmd">The command which triggers the callback. For example, "!ban" would match "!ban guest12345"</param>
/// <param name="callback">Function to be called when a user executes the command. The first parameter is a username and the last is an array of arguments</param>
public void RegisterCommand(string cmd, Action<string, string[]> callback) {
this.commands.Add(cmd, callback);
}
private void ProcessCommand(string username, string cmd) {
// I stole this from stackoverflow
var re = new Regex("(?<=\")[^\"]*(?=\")|[^\" ]+");
string[] args;
try {
args = re.Matches(cmd).Cast<Match>().Select(m => m.Value).ToArray();
}
catch {
return;
}
if (commands.ContainsKey(args[0]))
commands[args[0]](username, args.Skip(1).ToArray());
}
public Image GetFramebuffer() => framebuffer.CloneAs<Rgba32>();
private Task sendMouse() => this.SendMsg(Guacutils.Encode("mouse", mouse.X.ToString(), mouse.Y.ToString(), mouse.MakeMask().ToString()));

View file

@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>10</LangVersion>
<Version>2.0.1</Version>
</PropertyGroup>
<ItemGroup>

35
README.md Normal file
View file

@ -0,0 +1,35 @@
# CollabVMSharp
CollabVM client library in C#.
## Usage
The API is well documented with XML documentation, meaning hovering over a method or property in Visual Studio or another IDE should give a pretty good idea of how to do things. For a basic usage example, see below
### Example
```cs
using System;
using CollabVMSharp;
// Instantiate the client
var cvm = new CollabVMClient("wss://computernewb.com/collab-vm/vm0", "cvmsharptest", "vm0b0t");
// Connect to the VM
await cvm.Connect();
// Send a chat
await cvm.SendChat("What hath god wrought?");
// Add a command
cvm.RegisterCommand("!test", (username, args) => {
Console.WriteLine($"You said {String.Join(", ", args)}, {username}!");
});
// Queue a turn, wait until we get the turn
await cvm.GetTurn();
// Type a string into the VM
await cvm.TypeString("hey sexies");
// Login as an admin or mod
await cvm.Login("hunter2");
// Run a command in the QEMU monitor and get a response
Console.WriteLine(await cvm.QEMUMonitor("info block"));
// Send a message when someone takes a turn
cvm.TurnUpdate += async (_, e) => {
await cvm.SendChat($"You have the turn, {e.Queue[0].Username}!");
};
```