diff --git a/netsd/Handlers/Init.cs b/netsd/Handlers/Init.cs index 2da40ad..533ad15 100644 --- a/netsd/Handlers/Init.cs +++ b/netsd/Handlers/Init.cs @@ -1,4 +1,3 @@ -using System.Diagnostics; using Grpc.Core; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -40,42 +39,26 @@ public class Init var app = _socketBuilder.Build(); - app.MapGrpcService(); + app.MapGrpcService(); app.Run(); } } -public class StartGrpc : StartRpc.StartRpcBase +public class StartRPC : StartRpc.StartRpcBase { - public override async Task StartService(StartRequest request, IServerStreamWriter responseStream, - ServerCallContext context) + public override async Task StartService(StartRequest request, ServerCallContext context) { Init.Logger.Information($"Received request to start service {Path.GetFileName(request.Path)}."); - var parseServiceFile = await ServiceParser.Parse(request.Path); + var startService = await Utils.StartService.InitAsync(request.Path); + var thread = new Thread(startService.StartServiceAsync); + thread.Start(); - using var startService = new Process(); - startService.StartInfo.FileName = parseServiceFile.ExecStart?.Split(' ').First(); - startService.StartInfo.Arguments = string.Join(" ", parseServiceFile.ExecStart?.Split(' ').Skip(1)!); - startService.StartInfo.UseShellExecute = false; - startService.StartInfo.RedirectStandardOutput = true; - startService.StartInfo.RedirectStandardError = true; - startService.EnableRaisingEvents = true; + Init.Logger.Information($"Started service {Path.GetFileName(Path.GetFileName(request.Path))}."); - startService.OutputDataReceived += (sender, args) => Init.Logger.Information(args.Data!); - startService.ErrorDataReceived += (sender, args) => Init.Logger.Error(args.Data!); + Globals.Services.Add(startService); - if (!startService.Start()) - throw new Exception("Process failed to start"); - - startService.BeginOutputReadLine(); - startService.BeginErrorReadLine(); - - Init.Logger.Information($"Started service {Path.GetFileName(request.Path)}."); - - await responseStream.WriteAsync(new StartReply { Success = true }); - - await startService.WaitForExitAsync(); + return new StartReply { Success = true }; } } diff --git a/netsd/Handlers/Start.cs b/netsd/Handlers/Start.cs index 9365d4e..3280d9b 100644 --- a/netsd/Handlers/Start.cs +++ b/netsd/Handlers/Start.cs @@ -1,4 +1,3 @@ -using Grpc.Core; using netsd.Utils; using StartGrpc; @@ -23,17 +22,8 @@ public class Start using var channel = UDSConnector.CreateChannel(); var client = new StartRpc.StartRpcClient(channel); - var reply = client.StartService(new StartRequest{ Path = ServiceFilePath }); + var reply = await client.StartServiceAsync(new StartRequest { Path = ServiceFilePath }); - while (await reply.ResponseStream.MoveNext()) - { - var current = reply.ResponseStream.Current; - Console.WriteLine($"{current.Success}"); - - if (!current.Success) continue; - - Environment.Exit(0); - break; - } + Console.WriteLine($"{reply.Success}"); } } diff --git a/netsd/Program.cs b/netsd/Program.cs index 4c5f9f3..ecd896b 100644 --- a/netsd/Program.cs +++ b/netsd/Program.cs @@ -22,13 +22,9 @@ initCommand.SetHandler(() => new Init()); startCommand.SetHandler(async (file, name) => { if (name.Length != 0) - { await new Start().StartAsync(ServiceName: name); - } else - { - await new Start().StartAsync(ServiceFilePath: file.FullName); - } + await new Start().StartAsync(file.FullName); }, startServicePath, startServiceName); return await rootCommand.InvokeAsync(args); diff --git a/netsd/Protos/Start.proto b/netsd/Protos/Start.proto index 6c59817..558de5b 100644 --- a/netsd/Protos/Start.proto +++ b/netsd/Protos/Start.proto @@ -5,7 +5,7 @@ option csharp_namespace = "StartGrpc"; package netsd; service StartRpc { - rpc StartService (StartRequest) returns (stream StartReply); + rpc StartService (StartRequest) returns (StartReply); } message StartRequest { diff --git a/netsd/Utils/Globals.cs b/netsd/Utils/Globals.cs new file mode 100644 index 0000000..4ce353f --- /dev/null +++ b/netsd/Utils/Globals.cs @@ -0,0 +1,6 @@ +namespace netsd.Utils; + +public static class Globals +{ + public static List Services = new(); +} diff --git a/netsd/Utils/ServiceParser.cs b/netsd/Utils/ServiceParser.cs index dd9a251..f360104 100644 --- a/netsd/Utils/ServiceParser.cs +++ b/netsd/Utils/ServiceParser.cs @@ -16,5 +16,5 @@ public class ServiceParser sv.ExecStart = serviceData["Service"]["ExecStart"]; return sv; - } + } } diff --git a/netsd/Utils/StartService.cs b/netsd/Utils/StartService.cs new file mode 100644 index 0000000..270877e --- /dev/null +++ b/netsd/Utils/StartService.cs @@ -0,0 +1,51 @@ +using System.Diagnostics; +using netsd.Handlers; + +namespace netsd.Utils; + +public class StartService +{ + private readonly ServiceParser _parseServiceFile; + private readonly Process _process; + private readonly string _servicePath; + + private StartService(string servicePath, ServiceParser parseServiceFile) + { + _parseServiceFile = parseServiceFile; + _servicePath = servicePath; + _process = new Process(); + + _process.StartInfo.FileName = _parseServiceFile.ExecStart?.Split(' ').First(); + _process.StartInfo.Arguments = string.Join(" ", _parseServiceFile.ExecStart?.Split(' ').Skip(1)!); + _process.StartInfo.UseShellExecute = false; + _process.StartInfo.RedirectStandardOutput = true; + _process.StartInfo.RedirectStandardError = true; + _process.EnableRaisingEvents = true; + + _process.OutputDataReceived += (sender, args) => + Init.Logger.Information($"({Path.GetFileName(_servicePath)}) {args.Data}"); + _process.ErrorDataReceived += (sender, args) => + Init.Logger.Error($"({Path.GetFileName(_servicePath)}) {args.Data}"); + _process.Exited += (sender, args) => + { + if (_process.ExitCode != 0) + Init.Logger.Error( + $"Service {Path.GetFileName(_servicePath)} exited with a non-zero code! ({_process.ExitCode})"); + }; + } + + public static async Task InitAsync(string servicePath) + { + var parseServiceFile = await ServiceParser.Parse(servicePath); + + return new StartService(servicePath, parseServiceFile); + } + + public async void StartServiceAsync() + { + _process.Start(); + _process.BeginOutputReadLine(); + _process.BeginErrorReadLine(); + await _process.WaitForExitAsync(); + } +} diff --git a/netsd/Utils/UDSConnector.cs b/netsd/Utils/UDSConnector.cs index e3a3558..95209dc 100644 --- a/netsd/Utils/UDSConnector.cs +++ b/netsd/Utils/UDSConnector.cs @@ -6,15 +6,16 @@ namespace netsd.Utils; public class UDSConnector { - private readonly EndPoint _endPoint; private static readonly string _socketPath = Path.Combine(Path.GetTempPath(), "netsd.sock"); + private readonly EndPoint _endPoint; private UDSConnector(EndPoint endPoint) { _endPoint = endPoint; } - private async ValueTask _connectAsync(SocketsHttpConnectionContext _, CancellationToken cancellationToken = default) + private async ValueTask _connectAsync(SocketsHttpConnectionContext _, + CancellationToken cancellationToken = default) { var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); @@ -29,19 +30,19 @@ public class UDSConnector throw; } } - + public static GrpcChannel CreateChannel() { var udsEndPoint = new UnixDomainSocketEndPoint(_socketPath); var connectionFactory = new UDSConnector(udsEndPoint); var socketsHttpHandler = new SocketsHttpHandler { - ConnectCallback = connectionFactory._connectAsync + ConnectCallback = connectionFactory._connectAsync, }; return GrpcChannel.ForAddress("http://localhost", new GrpcChannelOptions { - HttpHandler = socketsHttpHandler + HttpHandler = socketsHttpHandler, }); } } diff --git a/netsd/netsd.csproj b/netsd/netsd.csproj index 6ca578a..38299be 100644 --- a/netsd/netsd.csproj +++ b/netsd/netsd.csproj @@ -10,10 +10,7 @@ 0.0.0.1 Release;Debug x64 - - true - Size - false + true false false @@ -25,8 +22,10 @@ false true true + true + true - +