diff --git a/CollabVM/CollabVM.csproj b/CollabVM/CollabVM.csproj index b760144..c7ca601 100644 --- a/CollabVM/CollabVM.csproj +++ b/CollabVM/CollabVM.csproj @@ -6,4 +6,10 @@ enable + + + + + + diff --git a/CollabVM/Server/CollabVMGuacamoleServer.cs b/CollabVM/Server/CollabVMGuacamoleServer.cs deleted file mode 100644 index 71c1be0..0000000 --- a/CollabVM/Server/CollabVMGuacamoleServer.cs +++ /dev/null @@ -1,40 +0,0 @@ -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(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(); - } - } - } -} diff --git a/CollabVM/Server/CollabVMHttpServer.cs b/CollabVM/Server/CollabVMHttpServer.cs index da7df25..1901544 100644 --- a/CollabVM/Server/CollabVMHttpServer.cs +++ b/CollabVM/Server/CollabVMHttpServer.cs @@ -10,7 +10,7 @@ namespace CollabVM.Server public class CollabVMHttpServer { private HttpListener _listener = new(); - private Dictionary _servers = new(); + private Dictionary _servers = new(); private readonly IPEndPoint _serverEndPoint; private readonly Boolean _allowList = false; @@ -21,12 +21,12 @@ namespace CollabVM.Server } public CollabVMHttpServer(IPAddress address, UInt16 port = 6004, Boolean allowList = false) : this(new(address, port), allowList) { } - public CollabVMHttpServer(CollabVMGuacamoleServer server, IPEndPoint endPoint) + public CollabVMHttpServer(CollabVMv1_2GuacamoleServer server, IPEndPoint endPoint) { this._serverEndPoint = endPoint; this._addServer("/", server); } - public CollabVMHttpServer(CollabVMGuacamoleServer server, IPAddress address, UInt16 port = 6004) : this(server, new(address, port)) { } + public CollabVMHttpServer(CollabVMv1_2GuacamoleServer server, IPAddress address, UInt16 port = 6004) : this(server, new(address, port)) { } private void ListenPath(String path) { @@ -36,13 +36,13 @@ namespace CollabVM.Server this._listener.Prefixes.Add(tmp); } - private void _addServer(String path, CollabVMGuacamoleServer server) + private void _addServer(String path, CollabVMv1_2GuacamoleServer server) { this._servers[path] = server; //this.ListenPath(path); } - public void AddServer(String name, CollabVMGuacamoleServer server) + public void AddServer(String name, CollabVMv1_2GuacamoleServer server) { Regex nameRegex = new Regex(@"^[a-zA-Z0-9_-]+$"); if (this._servers.ContainsKey("/")) @@ -68,7 +68,7 @@ namespace CollabVM.Server { if (context.Request.IsWebSocketRequest) { - if (this._servers.TryGetValue(context.Request.RawUrl, out CollabVMGuacamoleServer? server)) + if (this._servers.TryGetValue(context.Request.RawUrl, out CollabVMv1_2GuacamoleServer? server)) { WebSocketContext wsc; try @@ -101,7 +101,7 @@ namespace CollabVM.Server } } - private async void HandleWebSocket(WebSocketContext wsc, CollabVMGuacamoleServer server, IPEndPoint remote) + private async void HandleWebSocket(WebSocketContext wsc, CollabVMv1_2GuacamoleServer server, IPEndPoint remote) { server.HandleSocket(wsc.WebSocket, remote); } diff --git a/CollabVM/Server/CollabVMv1_2GuacamoleServer.cs b/CollabVM/Server/CollabVMv1_2GuacamoleServer.cs new file mode 100644 index 0000000..71e0e44 --- /dev/null +++ b/CollabVM/Server/CollabVMv1_2GuacamoleServer.cs @@ -0,0 +1,116 @@ +using ImageConverter; +using PVHelpers; +using RemoteFrameBuffer; +using System.Net; +using System.Net.WebSockets; +using System.Text; + +namespace CollabVM.Server +{ + public class CollabVMv1_2GuacamoleServer + { + private String tbfile = @"C:\Users\rolan\Downloads\bootsplash.jpg"; + + private static String[] ParseMessage(String s) + { + List args = []; + while (true) + { + String[] parts = s.Split('.', 2); + if (parts.Length != 2) + { + throw new ArgumentException("Invalid message format: missing `.`", nameof(s)); + } + if (Int32.TryParse(parts[0], out Int32 len)) + { + if (parts[1].Length < len + 1) + { + throw new ArgumentException("Invalid message format: data doesn't fit in message", nameof(s)); + } + args.Add(parts[1][..len]); + s = parts[1][(len+1)..]; + if (parts[1][len] == ',') + { + continue; + }else if (parts[1][len] == ';') + { + break; + } else + { + throw new ArgumentException("Invalid message format: parameters must be separated by `,`, list closed by `;`", nameof(s)); + } + } + else + { + throw new ArgumentException("Invalid message format: can't parse length field", nameof(s)); + } + } + return args.ToArray(); + } + + private static String ConstructMessage(params String[] args) => String.Join(',', args.Select((s) => $"{s.Length}.{s}")) + ";"; + + private RemoteFramebufferClient _client; + + public CollabVMv1_2GuacamoleServer(RemoteFramebufferClient client) + { + this._client = client; + client.Start(); + } + + 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(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); + await this.HandleCommand(ws, ParseMessage(msg)); + break; + default: + throw new NotSupportedException(); + } + } + } finally + { + ws.Dispose(); + } + } + + public async Task HandleCommand(WebSocket ws, params String[] args) + { + switch (args[0]) + { + case "cap": + break; + case "connect": + break; + case "list": + //await this.Reply(ws, "list", "vmx", "Fake test VM", File.ReadAllBytes(tbfile).EncodeBase64String()); + await this.Reply(ws, "list", "vmx", "Somewhat fake test VM", this._client.BitMap.BmpToJpg().EncodeBase64String()); + break; + case "rename": + break; + } + } + + public async Task Reply(WebSocket ws, params String[] args) + { + Byte[] buf = Encoding.UTF8.GetBytes(ConstructMessage(args)); + await ws.SendAsync(new ArraySegment(buf, 0, buf.Length), WebSocketMessageType.Text, true, CancellationToken.None); + } + } +} diff --git a/ImageConverter/ImageConverter.csproj b/ImageConverter/ImageConverter.csproj new file mode 100644 index 0000000..b760144 --- /dev/null +++ b/ImageConverter/ImageConverter.csproj @@ -0,0 +1,9 @@ + + + + net10.0 + enable + enable + + + diff --git a/ImageConverter/Magick.cs b/ImageConverter/Magick.cs new file mode 100644 index 0000000..2a5aecb --- /dev/null +++ b/ImageConverter/Magick.cs @@ -0,0 +1,34 @@ +using System.Diagnostics; + +namespace ImageConverter +{ + public static class Magick + { + public static void FileConvert(String infile, String outfile) + { + ProcessStartInfo psi = new ProcessStartInfo("magick"); + psi.ArgumentList.Add(infile); + psi.ArgumentList.Add(outfile); + Process? p = Process.Start(psi); + if (p==null) + { + throw new Exception("Could not launch magick"); + } + p.WaitForExit(); + } + + public static Byte[] BmpToJpg(this Byte[] bmpbuf) + { + String path = Path.GetTempFileName(); + String bmppath = Path.Combine(path, "magicktmp.bmp"); + String jpgpath = Path.Combine(path, "magicktmp.jpg"); + File.Delete(path); + Directory.CreateDirectory(path); + File.WriteAllBytes(bmppath, bmpbuf); + FileConvert(bmppath, jpgpath); + Byte[] buf = File.ReadAllBytes(jpgpath); + Directory.Delete(path, true); + return buf; + } + } +} diff --git a/PVHelpers/Base64Helpers.cs b/PVHelpers/Base64Helpers.cs new file mode 100644 index 0000000..3d496c9 --- /dev/null +++ b/PVHelpers/Base64Helpers.cs @@ -0,0 +1,20 @@ +using System.Buffers.Text; +using System.Text; + +namespace PVHelpers +{ + public static class Base64Helpers + { + public static String EncodeBase64String(this Byte[] data) + { + Byte[] buf = new Byte[data.Length * 2]; + if (Base64.EncodeToUtf8(data, buf, out _, out Int32 written) == System.Buffers.OperationStatus.Done) + { + return Encoding.UTF8.GetString(buf, 0, written); + } else + { + throw new Exception("Shit went south"); + } + } + } +} diff --git a/PVabel2026.slnx b/PVabel2026.slnx index edadf63..33e7528 100644 --- a/PVabel2026.slnx +++ b/PVabel2026.slnx @@ -4,6 +4,7 @@ + diff --git a/RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocol.cs b/RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocol.cs index 1f5c9e5..f329fa2 100644 --- a/RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocol.cs +++ b/RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocol.cs @@ -29,6 +29,9 @@ namespace RemoteFrameBuffer.Client private RgbFrameBuffer? _frameBuffer; + public delegate void BitmapUpdateCallback(Byte[] bitmap); + public event BitmapUpdateCallback? FrameUpdate; + public RemoteFrameBufferClientProtocol(Stream s) { this.vncStream = s; @@ -213,7 +216,8 @@ namespace RemoteFrameBuffer.Client throw new NotImplementedException(); } } - this._frameBuffer!.SaveBitmap($"{DateTime.Now:yyyyMMdd-HHmmss}.bmp"); + this.FrameUpdate?.Invoke(this._frameBuffer!.ToBitmap()); + //this._frameBuffer!.SaveBitmap($"{DateTime.Now:yyyyMMdd-HHmmss}.bmp"); } protected void ServerMsg_SetColourMapEntries() diff --git a/RemoteFrameBuffer/Client/RemoteFramebufferClient.cs b/RemoteFrameBuffer/Client/RemoteFramebufferClient.cs index 736a60d..448a9bf 100644 --- a/RemoteFrameBuffer/Client/RemoteFramebufferClient.cs +++ b/RemoteFrameBuffer/Client/RemoteFramebufferClient.cs @@ -20,6 +20,8 @@ namespace RemoteFrameBuffer }; } + public Byte[] BitMap { get; protected set; } = []; + public RemoteFramebufferClient(IRemoteFrameBufferClientStreamProvider socketProvider) { this._socketProvider = socketProvider; @@ -95,6 +97,10 @@ namespace RemoteFrameBuffer // TODO: register auth callback and the like proto.Handshake(this.cancellationTokenSource.Token); proto.Initialization(this.cancellationTokenSource.Token); + proto.FrameUpdate += (bitmap) => { + Console.Error.WriteLine("####################################### CB hit"); + this.BitMap = bitmap; + }; proto.StartListener(this.cancellationTokenSource.Token).Wait(); } #warning REMOVE THIS diff --git a/RemoteFrameBuffer/Common/RgbFrameBuffer.cs b/RemoteFrameBuffer/Common/RgbFrameBuffer.cs index 20f285f..0259ce2 100644 --- a/RemoteFrameBuffer/Common/RgbFrameBuffer.cs +++ b/RemoteFrameBuffer/Common/RgbFrameBuffer.cs @@ -44,7 +44,7 @@ public void CopyRegion(UInt16 source_x, UInt16 source_y, UInt16 width, UInt16 height, UInt16 target_x, UInt16 target_y) => this.SetRegion(this._frame, source_x, source_y, width, height, target_x, target_y); - public void SaveBitmap(String filename) + public Byte[] ToBitmap() { #warning Endianness is straight up ignored Int32 rowBytes = (this.Width * 3) + 3; @@ -72,7 +72,12 @@ buf[pos + 2] = this._frame[this.Height - j - 1][i].Red; } } - File.WriteAllBytes(filename, buf); + return buf; + } + + public void SaveBitmap(String filename) + { + File.WriteAllBytes(filename, this.ToBitmap()); } } } diff --git a/YetAnotherDummy/Program.cs b/YetAnotherDummy/Program.cs index 2e94cfe..77315db 100644 --- a/YetAnotherDummy/Program.cs +++ b/YetAnotherDummy/Program.cs @@ -4,16 +4,13 @@ using RemoteFrameBuffer; using RemoteFrameBuffer.Client; using System.Net; -/*IPAddress tessia = new([192,168,16,253]); +IPAddress tessia = new([192,168,16,253]); IRemoteFrameBufferClientStreamProvider tessia6001vnc = new RemoteFrameBufferTcpClientStreamProvider(tessia, 5901); RemoteFramebufferClient client = new(tessia6001vnc); -client.Start(); -Console.ReadLine(); -client.Stop();*/ - CollabVMHttpServer httpServer = new(new([100,65,0,14]), 6004, true); -httpServer.AddServer("vmx", new()); +httpServer.AddServer("vmx", new(client)); httpServer.Start(); Console.ReadLine(); +client.Stop();