diff --git a/MatrixLogFwd/Program.cs b/MatrixLogFwd/Program.cs
new file mode 100644
index 0000000..4f2c8e1
--- /dev/null
+++ b/MatrixLogFwd/Program.cs
@@ -0,0 +1,144 @@
+// See https://aka.ms/new-console-template for more information
+
+using System.Text;
+using System.Text.Json;
+using ArcaneLibs;
+using LibMatrix.Helpers;
+using LibMatrix.Homeservers;
+using LibMatrix.RoomTypes;
+using MatrixLogFwd;
+using Microsoft.VisualBasic.CompilerServices;
+
+Console.WriteLine("Hello, World!");
+var cfgPath = Util.ExpandPath($"~/.config/MatrixLogFwd/config.json");
+var cfg = JsonSerializer.Deserialize<Config>(System.IO.File.ReadAllText(cfgPath));
+
+var hs = await new AuthenticatedHomeserverGeneric(cfg.HomeserverBaseUrl, new(){Client = cfg.HomeserverBaseUrl}, null, cfg.AccessToken).Initialise();
+Console.WriteLine(hs);
+
+string mode = "lines";
+int chunkSize = 1000;
+string? command = null;
+GenericRoom? room = null;
+
+var argsEnum = args.AsEnumerable().GetEnumerator();
+while (argsEnum.MoveNext())
+{
+ var arg = argsEnum.Current;
+ switch (arg)
+ {
+ case "--help":
+ Console.WriteLine("Usage: MatrixLogFwd [--help] [--mode <file|lines>] [--chunk-size <int>] [-- <command>]");
+ break;
+ case "--mode":
+ argsEnum.MoveNext();
+ mode = argsEnum.Current;
+ if (mode != "file" && mode != "lines")
+ {
+ Console.WriteLine("Invalid mode");
+ return;
+ }
+ break;
+ case "--chunk-size":
+ argsEnum.MoveNext();
+ chunkSize = Conversions.ToInteger(argsEnum.Current);
+ break;
+ case "--roomid":
+ argsEnum.MoveNext();
+ var roomId = argsEnum.Current;
+ room = hs.GetRoom(roomId);
+ break;
+
+ case "--":
+ command = "";
+ while (argsEnum.MoveNext())
+ {
+ command += argsEnum.Current + " ";
+ }
+ break;
+ }
+}
+
+if (room == null)
+{
+ Console.WriteLine("No room specified, creating new room");
+ room = await hs.CreateRoom(new()
+ {
+ Name = $"MatrixLogFwd logs from {Environment.MachineName} at {DateTime.Now}",
+ });
+}
+
+var stream = Console.OpenStandardInput();
+if (!string.IsNullOrWhiteSpace(command))
+{
+ var proc = new System.Diagnostics.Process
+ {
+ StartInfo = new()
+ {
+ FileName = "/bin/sh",
+ Arguments = $"-c \"{command}\"",
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ CreateNoWindow = true
+ }
+ };
+ proc.Start();
+ stream = proc.StandardOutput.BaseStream;
+}
+
+if (mode == "lines")
+{
+ var buffer = new byte[1024];
+ var line = new StringBuilder();
+ int linesInBuffer = 0;
+ while (true)
+ {
+ var read = await stream.ReadAsync(buffer);
+ Console.WriteLine($"Read {read} bytes");
+ if (read == 0)
+ {
+ await room.SendMessageEventAsync(new MessageBuilder().WithCodeBlock(line.ToString()).Build());
+ break;
+ }
+ for (int i = 0; i < read; i++)
+ {
+ if (buffer[i] == '\n')
+ {
+ linesInBuffer++;
+ if (linesInBuffer > chunkSize)
+ {
+ await room.SendMessageEventAsync(new MessageBuilder().WithCodeBlock(line.ToString()).Build());
+ line.Clear();
+ linesInBuffer = 0;
+ }
+ else
+ {
+ line.Append((char)buffer[i]);
+ }
+ }
+ else
+ {
+ line.Append((char)buffer[i]);
+ }
+ }
+ }
+}
+else
+{
+ var buffer = new byte[chunkSize];
+ while (true)
+ {
+ var read = await stream.ReadAtLeastAsync(buffer, chunkSize, false);
+ if (read == 0)
+ {
+ break;
+ }
+ Console.WriteLine($"Read {read} bytes");
+ var ms = new System.IO.MemoryStream(buffer, 0, read);
+ var filename = $"log-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt";
+ await room.SendFileAsync(filename, ms);
+ }
+}
+
+// await room.LeaveAsync();
\ No newline at end of file
|