1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Process Monitor - initial POC implementation

This is probably overengineered. The same could be done cross platform only using Processes.GetProcesses. I did it this way because initially i wanted to use Wmi events for process start and stop. This requires admin though, so i decided to not use it.
This commit is contained in:
Diogo Trindade 2021-03-10 14:39:16 +00:00
parent fa26e6b7da
commit c9ee37ece8
7 changed files with 171 additions and 1 deletions

View File

@ -0,0 +1,14 @@
using System;
namespace Artemis.Core.Services
{
public class ProcessEventArgs : EventArgs
{
public string ProcessName { get; }
public ProcessEventArgs(string name)
{
ProcessName = name;
}
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Artemis.Core.Services
{
public interface IProcessMonitorService : IArtemisService
{
void AddProcessWatcher(ProcessWatcher provider);
void RemoveProcessWatcher(ProcessWatcher provider);
IEnumerable<string> GetRunningProcesses();
event EventHandler<ProcessEventArgs> ProcessStarted;
event EventHandler<ProcessEventArgs> ProcessStopped;
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Artemis.Core.Services
{
public class ProcessMonitorService : IProcessMonitorService
{
private readonly List<ProcessWatcher> _watchers = new List<ProcessWatcher>();
public event EventHandler<ProcessEventArgs> ProcessStarted;
public event EventHandler<ProcessEventArgs> ProcessStopped;
public void AddProcessWatcher(ProcessWatcher watcher)
{
watcher.ProcessStarted += ProviderOnProcessStarted;
watcher.ProcessStopped += ProviderOnProcessStopped;
_watchers.Add(watcher);
}
public void RemoveProcessWatcher(ProcessWatcher watcher)
{
if (!_watchers.Contains(watcher))
return;
_watchers.Remove(watcher);
watcher.ProcessStarted -= ProviderOnProcessStarted;
watcher.ProcessStopped -= ProviderOnProcessStopped;
}
public IEnumerable<string> GetRunningProcesses()
{
return _watchers.SelectMany(w => w.GetRunningProcesses());
}
private void ProviderOnProcessStopped(object? sender, ProcessEventArgs e)
{
ProcessStopped?.Invoke(this, e);
}
private void ProviderOnProcessStarted(object? sender, ProcessEventArgs e)
{
ProcessStarted?.Invoke(this, e);
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
namespace Artemis.Core.Services
{
/// <summary>
/// Class that provides info on running processes, including events on event start and stop
/// </summary>
public abstract class ProcessWatcher
{
public event EventHandler<ProcessEventArgs> ProcessStarted;
public event EventHandler<ProcessEventArgs> ProcessStopped;
public abstract IEnumerable<string> GetRunningProcesses();
public virtual void OnProcessStarted(string processName)
{
ProcessStarted?.Invoke(this, new ProcessEventArgs(processName));
}
public virtual void OnProcessStopped(string processName)
{
ProcessStopped?.Invoke(this, new ProcessEventArgs(processName));
}
}
}

View File

@ -89,6 +89,7 @@ namespace Artemis.UI
IRegistrationService registrationService = Kernel.Get<IRegistrationService>(); IRegistrationService registrationService = Kernel.Get<IRegistrationService>();
registrationService.RegisterInputProvider(); registrationService.RegisterInputProvider();
registrationService.RegisterProcessWatchers();
registrationService.RegisterControllers(); registrationService.RegisterControllers();
// Initialize background services // Initialize background services

View File

@ -0,0 +1,52 @@
using Artemis.Core.Services;
using Serilog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace Artemis.UI.ProcessWatchers
{
public class PollingProcessWatcher : ProcessWatcher
{
private readonly ILogger _logger;
private readonly Timer _processScanTimer;
private IEnumerable<string> _lastScannedProcesses;
public PollingProcessWatcher(ILogger logger)
{
_logger = logger;
_lastScannedProcesses = Process.GetProcesses().Select(p => p.ProcessName).Distinct().ToArray();
_processScanTimer = new Timer(100);
_processScanTimer.Elapsed += OnTimerElapsed;
_processScanTimer.Start();
}
private void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
var newProcesses = Process.GetProcesses().Select(p => p.ProcessName).Distinct();
foreach (var startedProcess in newProcesses.Except(_lastScannedProcesses))
{
OnProcessStarted(startedProcess);
_logger.Information($"Started Process!: {startedProcess}");
}
foreach (var stoppedProcess in _lastScannedProcesses.Except(newProcesses))
{
OnProcessStopped(stoppedProcess);
_logger.Information($"Stopped Process!: {stoppedProcess}");
}
_lastScannedProcesses = newProcesses.ToArray();
}
public override IEnumerable<string> GetRunningProcesses()
{
return _lastScannedProcesses;
}
}
}

View File

@ -7,6 +7,7 @@ using Artemis.UI.DefaultTypes.DataModel.Input;
using Artemis.UI.DefaultTypes.PropertyInput; using Artemis.UI.DefaultTypes.PropertyInput;
using Artemis.UI.InputProviders; using Artemis.UI.InputProviders;
using Artemis.UI.Ninject; using Artemis.UI.Ninject;
using Artemis.UI.ProcessWatchers;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Serilog; using Serilog;
@ -20,6 +21,7 @@ namespace Artemis.UI.Services
private readonly IPluginManagementService _pluginManagementService; private readonly IPluginManagementService _pluginManagementService;
private readonly IInputService _inputService; private readonly IInputService _inputService;
private readonly IWebServerService _webServerService; private readonly IWebServerService _webServerService;
private readonly IProcessMonitorService _processMonitorService;
private bool _registeredBuiltInDataModelDisplays; private bool _registeredBuiltInDataModelDisplays;
private bool _registeredBuiltInDataModelInputs; private bool _registeredBuiltInDataModelInputs;
private bool _registeredBuiltInPropertyEditors; private bool _registeredBuiltInPropertyEditors;
@ -29,7 +31,8 @@ namespace Artemis.UI.Services
IProfileEditorService profileEditorService, IProfileEditorService profileEditorService,
IPluginManagementService pluginManagementService, IPluginManagementService pluginManagementService,
IInputService inputService, IInputService inputService,
IWebServerService webServerService) IWebServerService webServerService,
IProcessMonitorService processMonitorService)
{ {
_logger = logger; _logger = logger;
_dataModelUIService = dataModelUIService; _dataModelUIService = dataModelUIService;
@ -37,6 +40,7 @@ namespace Artemis.UI.Services
_pluginManagementService = pluginManagementService; _pluginManagementService = pluginManagementService;
_inputService = inputService; _inputService = inputService;
_webServerService = webServerService; _webServerService = webServerService;
_processMonitorService = processMonitorService;
LoadPluginModules(); LoadPluginModules();
pluginManagementService.PluginEnabling += PluginServiceOnPluginEnabling; pluginManagementService.PluginEnabling += PluginServiceOnPluginEnabling;
@ -92,6 +96,11 @@ namespace Artemis.UI.Services
_inputService.AddInputProvider(new NativeWindowInputProvider(_logger, _inputService)); _inputService.AddInputProvider(new NativeWindowInputProvider(_logger, _inputService));
} }
public void RegisterProcessWatchers()
{
_processMonitorService.AddProcessWatcher(new PollingProcessWatcher(_logger));
}
public void RegisterControllers() public void RegisterControllers()
{ {
_webServerService.AddController<RemoteController>(); _webServerService.AddController<RemoteController>();
@ -115,6 +124,7 @@ namespace Artemis.UI.Services
void RegisterBuiltInDataModelInputs(); void RegisterBuiltInDataModelInputs();
void RegisterBuiltInPropertyEditors(); void RegisterBuiltInPropertyEditors();
void RegisterInputProvider(); void RegisterInputProvider();
void RegisterProcessWatchers();
void RegisterControllers(); void RegisterControllers();
} }
} }