using franz; using Newtonsoft.Json; using silver_messages.directorial; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; namespace directors_assistant { class Program { public static Config conf; public static Telefranz telefranz; static async Task Main(string[] args) { conf = JsonConvert.DeserializeObject(File.ReadAllText("appsettings.json")); telefranz = new Telefranz(conf.name, conf.bootstrap_servers, new List() { "proof_of_concept" }); telefranz.addHandler((silver_messages.directorial.execute_command ec) => { Console.WriteLine(JsonConvert.SerializeObject(ec)); var matchedCommands = conf.commands.Where(c => c.name == ec.command)?.ToList(); //I swear I have a vague memory of foreach in linq'd query throwing an exception when results empty. if (matchedCommands != null && matchedCommands.Count > 0) { foreach (var cmd in matchedCommands) { Console.WriteLine($"executing {cmd.name}, given args {ec.args}" + cmd.name); var cmdAndArgs = cmd.shell.Split(' '); var justArgs = cmdAndArgs.Skip(1).ToList(); justArgs.AddRange(ec.args); var commandPath = cmdAndArgs[0]; var commandArguments = String.Join(' ', justArgs); if (ec.timeout > 0) { executeTimed(cmd.name, commandPath, commandArguments, ec.timeout); } else { Task.Run(() => { executeUntimed(cmd.name, commandPath, commandArguments); }); } } } }); Console.WriteLine("off we go"); await Task.Delay(1000); Console.WriteLine("im a strong independent director's assistant who don't need no director"); telefranz.ProduceMessage(new silver_messages.global.sound_off()); await Task.Delay(120000); Console.WriteLine("alright fuck it"); } private static void executeTimed(string commandName, string commandPath, string commandArguments, int timeout) { var process = readableProcess(commandPath, commandArguments); var outputs = new List(); var errors = new List(); process.OutputDataReceived += new DataReceivedEventHandler((s, e) => { outputs.Add(e.Data); }); process.ErrorDataReceived += new DataReceivedEventHandler((s, e) => { errors.Add(e.Data); }); var stopwatch = new Stopwatch(); stopwatch.Start(); process.Start(); process.BeginErrorReadLine(); process.BeginOutputReadLine(); Task.WaitAny( Task.Run(() => { process.WaitForExit(); }), Task.Delay(new TimeSpan(0, 0, timeout)) ); if (process.HasExited) { stopwatch.Stop(); telefranz.ProduceMessage(new silver_messages.directorial.command_completed() { command = commandName, runtime = (uint)stopwatch.ElapsedMilliseconds, exit_code = process.ExitCode, stdout = string.Join('\n', outputs), stderr = string.Join('\n', errors) }); } else { process.Kill(); telefranz.ProduceMessage(new silver_messages.directorial.command_expired() { command = commandName, runtime = (uint)timeout }); } } private static void executeUntimed(string commandName, string commandPath, string commandArguments) { var process = readableProcess(commandPath, commandArguments); process.OutputDataReceived += new DataReceivedEventHandler((s, e) => { telefranz.ProduceMessage(new silver_messages.directorial.command_output() { stdout = e.Data }); }); process.ErrorDataReceived += new DataReceivedEventHandler((s, e) => { telefranz.ProduceMessage(new silver_messages.directorial.command_error() { stderr = e.Data }); }); var stopwatch = new Stopwatch(); stopwatch.Start(); process.Start(); process.BeginErrorReadLine(); process.BeginOutputReadLine(); process.WaitForExit(); telefranz.ProduceMessage(new silver_messages.directorial.command_completed() { command = commandName, runtime = (uint)stopwatch.ElapsedMilliseconds, exit_code = process.ExitCode }); } private static Process readableProcess(string commandPath, string commandArguments) { var pi = new ProcessStartInfo(commandPath, commandArguments); pi.UseShellExecute = false; pi.CreateNoWindow = true; pi.RedirectStandardError = true; pi.RedirectStandardOutput = true; var process = new Process(); process.StartInfo = pi; return process; } } }