kmProcessServer/ServiceMain.cs

135 lines
3.5 KiB
C#
Raw Normal View History

2025-11-04 04:21:57 -05:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Topshelf;
using log4net;
using System.Net.Sockets;
using System.Net;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO.Pipes;
namespace kmProcessServer;
internal class ServiceMain : ServiceControl
{
ILog appLog = LogManager.GetLogger(Program.AppName);
ConcurrentBag<Task> tasks = new();
ConcurrentBag<MdlProcess> ChildProcesses = new();
public bool Start(HostControl hostControl)
{
appLog.Info(string.Format("Service successfully started."));
tasks.Add(Task.Run(() => { StartTasks(); }));
return true;
} //Start
public bool Stop(HostControl hostControl)
{
Program.isExiting = true;
Task.WaitAll(tasks.ToArray());
tasks.Clear();
appLog.Debug("++ Service shutdown successful.");
return true;
} //Stop
void StartTasks()
{
var rn = new Random();
try
{
foreach (var f0 in Directory.GetFiles(Program.AppPath + "Procs", "*.exe"))
{
var px = new MdlProcess()
{
ProgramToRun = f0,
ExecutableName = Path.GetFileName(f0)
};
var si = new ProcessStartInfo()
{
FileName = px.ProgramToRun,
Verb = "OPEN",
WorkingDirectory = Path.GetDirectoryName(f0),
RedirectStandardError = true,
UseShellExecute = false
};
px.theProcess = new Process() { StartInfo = si };
px.theProcess.Start();
px.StartTime = DateTimeOffset.Now;
px.IPCChannel = string.Format("kmProcess_IPCChannel.{0}", px.theProcess.Id);
ChildProcesses.Add(px);
appLog.DebugFormat("++ Launched Process '{0}' having PID of {1}", px.ExecutableName, px.theProcess.Id);
}
}
catch (Exception ex)
{
appLog.Error(ex);
}
while (!Program.isExiting)
{
Thread.Sleep(rn.Next(900, 3000));
}
// First, try to stop them all gracefully...
foreach (var px in ChildProcesses)
{
appLog.DebugFormat("Sending request to shut down process '{0}'...", px.ExecutableName);
try
{
using (var ch = new NamedPipeClientStream(".", px.IPCChannel, PipeDirection.Out))
{
if (ch.ConnectAsync().Wait(3000))
{
using (var w = new StreamWriter(ch))
{
w.WriteLine("EXIT_NOW");
w.Flush();
}
}
}
}
catch (Exception ex)
{
appLog.Error(ex);
}
Thread.Sleep(100);
}
// Anyone still running? Use the hammer.
foreach (var px in ChildProcesses)
{
if (px.theProcess != null)
{
if (!px.theProcess.HasExited)
Thread.Sleep(5000); //Give it a little time to gracefully exit
if (!px.theProcess.HasExited)
{
try { px.theProcess.Kill(); }
catch { }
}
try { px.theProcess.Dispose(); }
catch { }
}
}
ChildProcesses.Clear();
}
#region "Private Models and Such"
class MdlProcess
{
public string ProgramToRun { get; set; } = string.Empty;
public string ExecutableName { get; set; } = string.Empty;
public Process? theProcess { get; set; } = null;
public DateTimeOffset StartTime { get; set; } = DateTimeOffset.Now;
/// <summary>
/// Used for interprocess communications
/// </summary>
public string IPCChannel { get; set; } = string.Empty;
}
#endregion
}