directors-assistant/Program.cs

191 lines
7.5 KiB
C#
Raw Permalink Normal View History

using franz;
using Newtonsoft.Json;
2021-06-09 07:51:25 -04:00
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;
2021-06-09 07:51:25 -04:00
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<Config>(File.ReadAllText("appsettings.json"));
2021-10-15 11:04:49 -04:00
Telefranz.Configure(name: conf.name, bootstrap_servers: conf.bootstrap_servers,
commands: conf.commands.Select(c => c.name).ToList());
telefranz = Telefranz.Instance;
2022-12-13 16:31:50 -05:00
telefranz.addHandler((gray_messages.directorial.execute_command 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)
2021-06-09 07:51:25 -04:00
{
foreach (var cmd in matchedCommands)
{
Console.WriteLine($"executing {cmd.name}{(ec.args != null ? ", given args " + string.Join(' ', ec.args) : "")} with timeout {ec.timeout}");
var cmdAndArgs = cmd.shell.Split(' ');
var justArgs = string.Join(' ', cmdAndArgs.Skip(1).ToList());
if(!string.IsNullOrWhiteSpace(ec.args))
{
justArgs += " " + ec.args;
}
var commandPath = cmdAndArgs[0];
var commandArguments = String.Join(' ', justArgs);
2021-10-26 07:33:39 -04:00
if (ec.timeout != null && ec.timeout > TimeSpan.Zero)
{
executeTimed(cmd.name, commandPath, commandArguments, ec.timeout);
}
else
{
Task.Run(() =>
{
executeUntimed(cmd.name, commandPath, commandArguments);
});
}
}
2021-06-09 07:51:25 -04:00
}
});
await Task.Delay(1000);
2022-12-13 16:31:50 -05:00
telefranz.ProduceMessage(new gray_messages.global.sound_off());
2021-06-09 07:51:25 -04:00
await Task.Delay(-1);
}
2021-10-15 11:04:49 -04:00
private static void executeTimed(string commandName, string commandPath, string commandArguments, TimeSpan? timeout)
{
var process = readableProcess(commandPath, commandArguments);
var outputs = new List<string>();
var errors = new List<string>();
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();
2021-10-26 07:33:39 -04:00
if (timeout != null && timeout > TimeSpan.Zero)
2021-10-15 11:04:49 -04:00
{
Task.WaitAny(
Task.Run(() =>
{
process.WaitForExit();
}),
Task.Delay(timeout.Value)
);
}
else
{
process.WaitForExit();
}
if (process.HasExited)
{
stopwatch.Stop();
Console.WriteLine($"{commandName} completed");
2022-12-13 16:31:50 -05:00
telefranz.ProduceMessage(new gray_messages.directorial.command_completed()
{
command = commandName,
runtimeMilliseconds = stopwatch.ElapsedMilliseconds,
exit_code = process.ExitCode,
stdout = string.Join('\n', outputs),
stderr = string.Join('\n', errors)
});
}
else
{
process.Kill();
Console.WriteLine($"{commandName} expired");
2022-12-13 16:31:50 -05:00
telefranz.ProduceMessage(new gray_messages.directorial.command_expired()
{
2021-10-15 11:04:49 -04:00
command = commandName,
stdout = string.Join('\n', outputs),
stderr = string.Join('\n', errors)
});
}
}
private static void executeUntimed(string commandName, string commandPath, string commandArguments)
{
var stopwatch = new Stopwatch();
var process = readableProcess(commandPath, commandArguments);
2021-10-15 11:04:49 -04:00
process.OutputDataReceived += new DataReceivedEventHandler((s, e) =>
{
Console.WriteLine($"{commandName} output: {e.Data}");
2021-10-15 11:04:49 -04:00
if (string.IsNullOrWhiteSpace(e.Data))
{
return;
}
2022-12-13 16:31:50 -05:00
telefranz.ProduceMessage(new gray_messages.directorial.command_output()
2021-10-15 11:04:49 -04:00
{
stdout = e.Data,
command = commandName,
runtime = (uint)stopwatch.ElapsedMilliseconds
});
});
2021-10-15 11:04:49 -04:00
process.ErrorDataReceived += new DataReceivedEventHandler((s, e) =>
{
if (string.IsNullOrWhiteSpace(e.Data))
{
return;
}
Console.Error.WriteLine($"{commandName} err (but not necessarily dead?): {e.Data}");
2022-12-13 16:31:50 -05:00
telefranz.ProduceMessage(new gray_messages.directorial.command_error()
2021-10-15 11:04:49 -04:00
{
stderr = e.Data,
command = commandName,
runtime = (uint)stopwatch.ElapsedMilliseconds
});
});
2021-10-26 07:33:39 -04:00
try
{
2021-10-26 07:33:39 -04:00
stopwatch.Start();
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
stopwatch.Stop();
Console.WriteLine($"{commandName} returned {process.ExitCode} after {stopwatch.ElapsedMilliseconds}ms");
2022-12-13 16:31:50 -05:00
telefranz.ProduceMessage(new gray_messages.directorial.command_completed()
2021-10-26 07:33:39 -04:00
{
command = commandName,
runtimeMilliseconds = stopwatch.ElapsedMilliseconds,
exit_code = process.ExitCode
});
}
catch(Exception e)
{
Console.Error.WriteLine($"{commandName} FATAL: {JsonConvert.SerializeObject(e)}");
2022-12-13 16:31:50 -05:00
telefranz.ProduceMessage(new gray_messages.directorial.command_error()
2021-10-26 07:33:39 -04:00
{
stderr = e.Message,
command = commandName,
runtime = (uint)stopwatch.ElapsedMilliseconds
});
}
}
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;
}
}
}