guacamole in progress

This commit is contained in:
2026-02-12 15:43:03 +01:00
parent 9a333bb1c8
commit 5801b29f22
6 changed files with 168 additions and 2 deletions

9
CollabVM/CollabVM.csproj Normal file
View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,40 @@
using System.Net;
using System.Net.WebSockets;
using System.Text;
namespace CollabVM.Server
{
public class CollabVMGuacamoleServer
{
public async void HandleSocket(WebSocket ws, IPEndPoint remote)
{
Console.Error.WriteLine("new WebSocket, who dis?");
#warning we probably don't need this much
Byte[] buf = new Byte[1024];
try
{
while (ws.State == WebSocketState.Open)
{
#warning probably needs a real ctoken
WebSocketReceiveResult recResult = await ws.ReceiveAsync(new ArraySegment<Byte>(buf), CancellationToken.None);
Console.Error.WriteLine(recResult.MessageType);
switch (recResult.MessageType)
{
case WebSocketMessageType.Close:
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
break;
case WebSocketMessageType.Text:
String msg = Encoding.UTF8.GetString(buf, 0, recResult.Count);
Console.Error.WriteLine(msg);
break;
default:
throw new NotSupportedException();
}
}
} finally
{
ws.Dispose();
}
}
}
}

View File

@@ -0,0 +1,109 @@
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace CollabVM.Server
{
// https://github.com/paulbatum/WebSocket-Samples/blob/master/HttpListenerWebSocketEcho/Server/Server.cs
public class CollabVMHttpServer
{
private HttpListener _listener = new();
private Dictionary<String, CollabVMGuacamoleServer> _servers = new();
private readonly IPEndPoint _serverEndPoint;
private readonly Boolean _allowList = false;
public CollabVMHttpServer(IPEndPoint endPoint, Boolean allowServerList = false)
{
this._serverEndPoint = endPoint;
this._allowList = allowServerList;
}
public CollabVMHttpServer(IPAddress address, UInt16 port = 6004, Boolean allowList = false) : this(new(address, port), allowList) { }
public CollabVMHttpServer(CollabVMGuacamoleServer server, IPEndPoint endPoint)
{
this._serverEndPoint = endPoint;
this._addServer("/", server);
}
public CollabVMHttpServer(CollabVMGuacamoleServer server, IPAddress address, UInt16 port = 6004) : this(server, new(address, port)) { }
private void ListenPath(String path)
{
String tmp = $"http://{this._serverEndPoint.Address}:{this._serverEndPoint.Port}{path}";
//String tmp = $"http://+:{this._serverEndPoint.Port}/{path}";
Console.Error.WriteLine($"Listen: {tmp}");
this._listener.Prefixes.Add(tmp);
}
private void _addServer(String path, CollabVMGuacamoleServer server)
{
this._servers[path] = server;
//this.ListenPath(path);
}
public void AddServer(String name, CollabVMGuacamoleServer server)
{
Regex nameRegex = new Regex(@"^[a-zA-Z0-9_-]+$");
if (this._servers.ContainsKey("/"))
{
throw new InvalidOperationException("Cannot add servers to a single-server instance");
}
if (name.Contains("/"))
{
throw new ArgumentException("Server name must only include latin letters, numbers, underscores and hyphens", nameof(name));
}
this._addServer($"/{name}", server);
}
public async void Start()
{
this.ListenPath("/");
this._listener.Start();
while (true)
{
HttpListenerContext context = await this._listener.GetContextAsync();
Console.Error.WriteLine($"<< {context.Request.HttpMethod} {context.Request.UserHostAddress} {context.Request.UserHostName} {context.Request.RawUrl}");
if (context.Request.RawUrl is not null)
{
if (context.Request.IsWebSocketRequest)
{
if (this._servers.TryGetValue(context.Request.RawUrl, out CollabVMGuacamoleServer? server))
{
WebSocketContext wsc;
try
{
wsc = await context.AcceptWebSocketAsync(subProtocol: "guacamole");
} catch (Exception)
{
context.Response.StatusCode = (Int32)HttpStatusCode.InternalServerError;
context.Response.Close();
continue;
}
this.HandleWebSocket(wsc, server, context.Request.RemoteEndPoint);
continue;
} else
{
context.Response.StatusCode = (Int32)HttpStatusCode.NotFound;
context.Response.Close();
continue;
}
} else if (this._allowList && context.Request.RawUrl == "/")
{
context.Response.StatusCode = (Int32)HttpStatusCode.OK;
context.Response.ContentType = "application/json";
context.Response.Close(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(this._servers.Keys.Select((path) => $"ws://{context.Request.UserHostAddress}{path}").ToList())), false);
continue;
}
}
context.Response.StatusCode = (Int32)HttpStatusCode.BadRequest;
context.Response.Close();
}
}
private async void HandleWebSocket(WebSocketContext wsc, CollabVMGuacamoleServer server, IPEndPoint remote)
{
server.HandleSocket(wsc.WebSocket, remote);
}
}
}