From c9ee37ece8f5adf122bbd08a94db3ab561ad8072 Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Wed, 10 Mar 2021 14:39:16 +0000 Subject: [PATCH 1/5] 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. --- .../ProcessMonitor/Events/ProcessEventArgs.cs | 14 +++++ .../Interfaces/IProcessMonitorService.cs | 21 ++++++++ .../ProcessMonitor/ProcessMonitorService.cs | 46 ++++++++++++++++ .../Services/ProcessMonitor/ProcessWatcher.cs | 26 ++++++++++ src/Artemis.UI/Bootstrapper.cs | 1 + .../ProcessWatchers/PollingProcessWatcher.cs | 52 +++++++++++++++++++ .../Services/RegistrationService.cs | 12 ++++- 7 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 src/Artemis.Core/Services/ProcessMonitor/Events/ProcessEventArgs.cs create mode 100644 src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs create mode 100644 src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs create mode 100644 src/Artemis.Core/Services/ProcessMonitor/ProcessWatcher.cs create mode 100644 src/Artemis.UI/ProcessWatchers/PollingProcessWatcher.cs diff --git a/src/Artemis.Core/Services/ProcessMonitor/Events/ProcessEventArgs.cs b/src/Artemis.Core/Services/ProcessMonitor/Events/ProcessEventArgs.cs new file mode 100644 index 000000000..beb5e42e9 --- /dev/null +++ b/src/Artemis.Core/Services/ProcessMonitor/Events/ProcessEventArgs.cs @@ -0,0 +1,14 @@ +using System; + +namespace Artemis.Core.Services +{ + public class ProcessEventArgs : EventArgs + { + public string ProcessName { get; } + + public ProcessEventArgs(string name) + { + ProcessName = name; + } + } +} diff --git a/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs b/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs new file mode 100644 index 000000000..c1873de68 --- /dev/null +++ b/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs @@ -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 GetRunningProcesses(); + + event EventHandler ProcessStarted; + + event EventHandler ProcessStopped; + } +} diff --git a/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs new file mode 100644 index 000000000..65df1ae65 --- /dev/null +++ b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs @@ -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 _watchers = new List(); + public event EventHandler ProcessStarted; + public event EventHandler 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 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); + } + } +} diff --git a/src/Artemis.Core/Services/ProcessMonitor/ProcessWatcher.cs b/src/Artemis.Core/Services/ProcessMonitor/ProcessWatcher.cs new file mode 100644 index 000000000..7bede154a --- /dev/null +++ b/src/Artemis.Core/Services/ProcessMonitor/ProcessWatcher.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; + +namespace Artemis.Core.Services +{ + /// + /// Class that provides info on running processes, including events on event start and stop + /// + public abstract class ProcessWatcher + { + public event EventHandler ProcessStarted; + public event EventHandler ProcessStopped; + + public abstract IEnumerable 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)); + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Bootstrapper.cs b/src/Artemis.UI/Bootstrapper.cs index 585b1b1a4..b540db62c 100644 --- a/src/Artemis.UI/Bootstrapper.cs +++ b/src/Artemis.UI/Bootstrapper.cs @@ -89,6 +89,7 @@ namespace Artemis.UI IRegistrationService registrationService = Kernel.Get(); registrationService.RegisterInputProvider(); + registrationService.RegisterProcessWatchers(); registrationService.RegisterControllers(); // Initialize background services diff --git a/src/Artemis.UI/ProcessWatchers/PollingProcessWatcher.cs b/src/Artemis.UI/ProcessWatchers/PollingProcessWatcher.cs new file mode 100644 index 000000000..20a4e807a --- /dev/null +++ b/src/Artemis.UI/ProcessWatchers/PollingProcessWatcher.cs @@ -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 _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 GetRunningProcesses() + { + return _lastScannedProcesses; + } + } +} diff --git a/src/Artemis.UI/Services/RegistrationService.cs b/src/Artemis.UI/Services/RegistrationService.cs index 0d51ce376..b8a1e8b86 100644 --- a/src/Artemis.UI/Services/RegistrationService.cs +++ b/src/Artemis.UI/Services/RegistrationService.cs @@ -7,6 +7,7 @@ using Artemis.UI.DefaultTypes.DataModel.Input; using Artemis.UI.DefaultTypes.PropertyInput; using Artemis.UI.InputProviders; using Artemis.UI.Ninject; +using Artemis.UI.ProcessWatchers; using Artemis.UI.Shared.Services; using Serilog; @@ -20,6 +21,7 @@ namespace Artemis.UI.Services private readonly IPluginManagementService _pluginManagementService; private readonly IInputService _inputService; private readonly IWebServerService _webServerService; + private readonly IProcessMonitorService _processMonitorService; private bool _registeredBuiltInDataModelDisplays; private bool _registeredBuiltInDataModelInputs; private bool _registeredBuiltInPropertyEditors; @@ -29,7 +31,8 @@ namespace Artemis.UI.Services IProfileEditorService profileEditorService, IPluginManagementService pluginManagementService, IInputService inputService, - IWebServerService webServerService) + IWebServerService webServerService, + IProcessMonitorService processMonitorService) { _logger = logger; _dataModelUIService = dataModelUIService; @@ -37,6 +40,7 @@ namespace Artemis.UI.Services _pluginManagementService = pluginManagementService; _inputService = inputService; _webServerService = webServerService; + _processMonitorService = processMonitorService; LoadPluginModules(); pluginManagementService.PluginEnabling += PluginServiceOnPluginEnabling; @@ -92,6 +96,11 @@ namespace Artemis.UI.Services _inputService.AddInputProvider(new NativeWindowInputProvider(_logger, _inputService)); } + public void RegisterProcessWatchers() + { + _processMonitorService.AddProcessWatcher(new PollingProcessWatcher(_logger)); + } + public void RegisterControllers() { _webServerService.AddController(); @@ -115,6 +124,7 @@ namespace Artemis.UI.Services void RegisterBuiltInDataModelInputs(); void RegisterBuiltInPropertyEditors(); void RegisterInputProvider(); + void RegisterProcessWatchers(); void RegisterControllers(); } } \ No newline at end of file From fb51e75b94b79e7cbbd54c27f98e8d8f8fe082c3 Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Wed, 10 Mar 2021 15:35:27 +0000 Subject: [PATCH 2/5] Process Monitor - simplified structure, moved everything to Core --- .../Interfaces/IProcessMonitorService.cs | 7 +-- .../ProcessMonitor/ProcessMonitorService.cs | 58 ++++++++++--------- .../Services/ProcessMonitor/ProcessWatcher.cs | 26 --------- src/Artemis.UI/Bootstrapper.cs | 1 - .../ProcessWatchers/PollingProcessWatcher.cs | 52 ----------------- .../Services/RegistrationService.cs | 12 +--- 6 files changed, 35 insertions(+), 121 deletions(-) delete mode 100644 src/Artemis.Core/Services/ProcessMonitor/ProcessWatcher.cs delete mode 100644 src/Artemis.UI/ProcessWatchers/PollingProcessWatcher.cs diff --git a/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs b/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs index c1873de68..907af1607 100644 --- a/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs +++ b/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs @@ -9,13 +9,10 @@ namespace Artemis.Core.Services { public interface IProcessMonitorService : IArtemisService { - void AddProcessWatcher(ProcessWatcher provider); - void RemoveProcessWatcher(ProcessWatcher provider); - - IEnumerable GetRunningProcesses(); - event EventHandler ProcessStarted; event EventHandler ProcessStopped; + + IEnumerable GetRunningProcesses(); } } diff --git a/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs index 65df1ae65..3b3eefc55 100644 --- a/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs +++ b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs @@ -1,46 +1,52 @@ -using System; +using Serilog; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Timers; namespace Artemis.Core.Services { public class ProcessMonitorService : IProcessMonitorService { - private readonly List _watchers = new List(); + private readonly ILogger _logger; + private readonly Timer _processScanTimer; + private IEnumerable _lastScannedProcesses; + + public ProcessMonitorService(ILogger logger) + { + _logger = logger; + _lastScannedProcesses = Process.GetProcesses().Select(p => p.ProcessName).Distinct().ToArray(); + _processScanTimer = new Timer(1000); + _processScanTimer.Elapsed += OnTimerElapsed; + _processScanTimer.Start(); + } + public event EventHandler ProcessStarted; + public event EventHandler 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 GetRunningProcesses() { - return _watchers.SelectMany(w => w.GetRunningProcesses()); + return _lastScannedProcesses; } - private void ProviderOnProcessStopped(object? sender, ProcessEventArgs e) + private void OnTimerElapsed(object sender, ElapsedEventArgs e) { - ProcessStopped?.Invoke(this, e); - } + var newProcesses = Process.GetProcesses().Select(p => p.ProcessName).Distinct(); + foreach (var startedProcess in newProcesses.Except(_lastScannedProcesses)) + { + ProcessStarted?.Invoke(this, new ProcessEventArgs(startedProcess)); + _logger.Verbose("Started Process: {startedProcess}", startedProcess); + } - private void ProviderOnProcessStarted(object? sender, ProcessEventArgs e) - { - ProcessStarted?.Invoke(this, e); + foreach (var stoppedProcess in _lastScannedProcesses.Except(newProcesses)) + { + ProcessStopped?.Invoke(this, new ProcessEventArgs(stoppedProcess)); + _logger.Verbose("Stopped Process: {stoppedProcess}", stoppedProcess); + } + + _lastScannedProcesses = newProcesses.ToArray(); } } } diff --git a/src/Artemis.Core/Services/ProcessMonitor/ProcessWatcher.cs b/src/Artemis.Core/Services/ProcessMonitor/ProcessWatcher.cs deleted file mode 100644 index 7bede154a..000000000 --- a/src/Artemis.Core/Services/ProcessMonitor/ProcessWatcher.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Artemis.Core.Services -{ - /// - /// Class that provides info on running processes, including events on event start and stop - /// - public abstract class ProcessWatcher - { - public event EventHandler ProcessStarted; - public event EventHandler ProcessStopped; - - public abstract IEnumerable 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)); - } - } -} \ No newline at end of file diff --git a/src/Artemis.UI/Bootstrapper.cs b/src/Artemis.UI/Bootstrapper.cs index b540db62c..585b1b1a4 100644 --- a/src/Artemis.UI/Bootstrapper.cs +++ b/src/Artemis.UI/Bootstrapper.cs @@ -89,7 +89,6 @@ namespace Artemis.UI IRegistrationService registrationService = Kernel.Get(); registrationService.RegisterInputProvider(); - registrationService.RegisterProcessWatchers(); registrationService.RegisterControllers(); // Initialize background services diff --git a/src/Artemis.UI/ProcessWatchers/PollingProcessWatcher.cs b/src/Artemis.UI/ProcessWatchers/PollingProcessWatcher.cs deleted file mode 100644 index 20a4e807a..000000000 --- a/src/Artemis.UI/ProcessWatchers/PollingProcessWatcher.cs +++ /dev/null @@ -1,52 +0,0 @@ -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 _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 GetRunningProcesses() - { - return _lastScannedProcesses; - } - } -} diff --git a/src/Artemis.UI/Services/RegistrationService.cs b/src/Artemis.UI/Services/RegistrationService.cs index b8a1e8b86..0d51ce376 100644 --- a/src/Artemis.UI/Services/RegistrationService.cs +++ b/src/Artemis.UI/Services/RegistrationService.cs @@ -7,7 +7,6 @@ using Artemis.UI.DefaultTypes.DataModel.Input; using Artemis.UI.DefaultTypes.PropertyInput; using Artemis.UI.InputProviders; using Artemis.UI.Ninject; -using Artemis.UI.ProcessWatchers; using Artemis.UI.Shared.Services; using Serilog; @@ -21,7 +20,6 @@ namespace Artemis.UI.Services private readonly IPluginManagementService _pluginManagementService; private readonly IInputService _inputService; private readonly IWebServerService _webServerService; - private readonly IProcessMonitorService _processMonitorService; private bool _registeredBuiltInDataModelDisplays; private bool _registeredBuiltInDataModelInputs; private bool _registeredBuiltInPropertyEditors; @@ -31,8 +29,7 @@ namespace Artemis.UI.Services IProfileEditorService profileEditorService, IPluginManagementService pluginManagementService, IInputService inputService, - IWebServerService webServerService, - IProcessMonitorService processMonitorService) + IWebServerService webServerService) { _logger = logger; _dataModelUIService = dataModelUIService; @@ -40,7 +37,6 @@ namespace Artemis.UI.Services _pluginManagementService = pluginManagementService; _inputService = inputService; _webServerService = webServerService; - _processMonitorService = processMonitorService; LoadPluginModules(); pluginManagementService.PluginEnabling += PluginServiceOnPluginEnabling; @@ -96,11 +92,6 @@ namespace Artemis.UI.Services _inputService.AddInputProvider(new NativeWindowInputProvider(_logger, _inputService)); } - public void RegisterProcessWatchers() - { - _processMonitorService.AddProcessWatcher(new PollingProcessWatcher(_logger)); - } - public void RegisterControllers() { _webServerService.AddController(); @@ -124,7 +115,6 @@ namespace Artemis.UI.Services void RegisterBuiltInDataModelInputs(); void RegisterBuiltInPropertyEditors(); void RegisterInputProvider(); - void RegisterProcessWatchers(); void RegisterControllers(); } } \ No newline at end of file From d4a0b0710cbc844fe512996b816a820beddf4ab7 Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Wed, 10 Mar 2021 16:04:25 +0000 Subject: [PATCH 3/5] Process Monitor - Switched to Processes instead of strings --- src/Artemis.Core/Services/CoreService.cs | 3 +- .../ProcessMonitor/Events/ProcessEventArgs.cs | 7 ++-- .../Interfaces/IProcessMonitorService.cs | 2 +- .../ProcessMonitor/ProcessMonitorService.cs | 34 ++++++++++++++----- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index 19b9b6210..6c2c69c21 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -46,7 +46,8 @@ namespace Artemis.Core.Services IPluginManagementService pluginManagementService, IRgbService rgbService, IProfileService profileService, - IModuleService moduleService // injected to ensure module priorities get applied + IModuleService moduleService, // injected to ensure module priorities get applied + IProcessMonitorService processMonitorService //injected to keep track of processes ) { Kernel = kernel; diff --git a/src/Artemis.Core/Services/ProcessMonitor/Events/ProcessEventArgs.cs b/src/Artemis.Core/Services/ProcessMonitor/Events/ProcessEventArgs.cs index beb5e42e9..65482023b 100644 --- a/src/Artemis.Core/Services/ProcessMonitor/Events/ProcessEventArgs.cs +++ b/src/Artemis.Core/Services/ProcessMonitor/Events/ProcessEventArgs.cs @@ -1,14 +1,15 @@ using System; +using System.Diagnostics; namespace Artemis.Core.Services { public class ProcessEventArgs : EventArgs { - public string ProcessName { get; } + public Process Process { get; } - public ProcessEventArgs(string name) + public ProcessEventArgs(Process process) { - ProcessName = name; + Process = process; } } } diff --git a/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs b/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs index 907af1607..37ae223ae 100644 --- a/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs +++ b/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs @@ -13,6 +13,6 @@ namespace Artemis.Core.Services event EventHandler ProcessStopped; - IEnumerable GetRunningProcesses(); + IEnumerable GetRunningProcesses(); } } diff --git a/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs index 3b3eefc55..a487fc626 100644 --- a/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs +++ b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs @@ -11,12 +11,12 @@ namespace Artemis.Core.Services { private readonly ILogger _logger; private readonly Timer _processScanTimer; - private IEnumerable _lastScannedProcesses; + private Process[] _lastScannedProcesses; public ProcessMonitorService(ILogger logger) { _logger = logger; - _lastScannedProcesses = Process.GetProcesses().Select(p => p.ProcessName).Distinct().ToArray(); + _lastScannedProcesses = Process.GetProcesses().DistinctBy(p => p.ProcessName).ToArray(); _processScanTimer = new Timer(1000); _processScanTimer.Elapsed += OnTimerElapsed; _processScanTimer.Start(); @@ -26,27 +26,43 @@ namespace Artemis.Core.Services public event EventHandler ProcessStopped; - public IEnumerable GetRunningProcesses() + public IEnumerable GetRunningProcesses() { return _lastScannedProcesses; } private void OnTimerElapsed(object sender, ElapsedEventArgs e) { - var newProcesses = Process.GetProcesses().Select(p => p.ProcessName).Distinct(); - foreach (var startedProcess in newProcesses.Except(_lastScannedProcesses)) + var newProcesses = Process.GetProcesses().DistinctBy(p => p.ProcessName).ToArray(); + foreach (var startedProcess in newProcesses.Except(_lastScannedProcesses, new ProcessComparer())) { ProcessStarted?.Invoke(this, new ProcessEventArgs(startedProcess)); - _logger.Verbose("Started Process: {startedProcess}", startedProcess); + _logger.Debug("Started Process: {startedProcess}", startedProcess.ProcessName); } - foreach (var stoppedProcess in _lastScannedProcesses.Except(newProcesses)) + foreach (var stoppedProcess in _lastScannedProcesses.Except(newProcesses, new ProcessComparer())) { ProcessStopped?.Invoke(this, new ProcessEventArgs(stoppedProcess)); - _logger.Verbose("Stopped Process: {stoppedProcess}", stoppedProcess); + _logger.Debug("Stopped Process: {stoppedProcess}", stoppedProcess.ProcessName); } - _lastScannedProcesses = newProcesses.ToArray(); + _lastScannedProcesses = newProcesses; + } + } + + internal class ProcessComparer : IEqualityComparer + { + public bool Equals(Process? x, Process? y) + { + if (x == null && y == null) return true; + if (x == null || y == null) return false; + return x.Id == y.Id && x.ProcessName == y.ProcessName && x.SessionId == y.SessionId; + } + + public int GetHashCode(Process obj) + { + if (obj == null) return 0; + return obj.Id; } } } From a21db5eaa40791bcc4766453191181ee3133dcc0 Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Fri, 19 Mar 2021 14:36:22 +0000 Subject: [PATCH 4/5] Process Monitor - removed unneeded injection --- src/Artemis.Core/Services/CoreService.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index 6c2c69c21..19b9b6210 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -46,8 +46,7 @@ namespace Artemis.Core.Services IPluginManagementService pluginManagementService, IRgbService rgbService, IProfileService profileService, - IModuleService moduleService, // injected to ensure module priorities get applied - IProcessMonitorService processMonitorService //injected to keep track of processes + IModuleService moduleService // injected to ensure module priorities get applied ) { Kernel = kernel; From be11439b2192404201621b500a06c380008dbedc Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Fri, 19 Mar 2021 16:16:09 +0000 Subject: [PATCH 5/5] Process Monitor - documentation and code style --- .../ProcessMonitor/Events/ProcessEventArgs.cs | 8 +++++++- .../Interfaces/IProcessMonitorService.cs | 12 ++++++++++++ .../ProcessMonitor/ProcessMonitorService.cs | 16 +++++++++------- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/Artemis.Core/Services/ProcessMonitor/Events/ProcessEventArgs.cs b/src/Artemis.Core/Services/ProcessMonitor/Events/ProcessEventArgs.cs index 65482023b..dca403a13 100644 --- a/src/Artemis.Core/Services/ProcessMonitor/Events/ProcessEventArgs.cs +++ b/src/Artemis.Core/Services/ProcessMonitor/Events/ProcessEventArgs.cs @@ -3,11 +3,17 @@ using System.Diagnostics; namespace Artemis.Core.Services { + /// + /// Contains data for the ProcessMonitor process events + /// public class ProcessEventArgs : EventArgs { + /// + /// Gets the process related to the event + /// public Process Process { get; } - public ProcessEventArgs(Process process) + internal ProcessEventArgs(Process process) { Process = process; } diff --git a/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs b/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs index 37ae223ae..b26376b37 100644 --- a/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs +++ b/src/Artemis.Core/Services/ProcessMonitor/Interfaces/IProcessMonitorService.cs @@ -7,12 +7,24 @@ using System.Threading.Tasks; namespace Artemis.Core.Services { + /// + /// A service that provides events for started and stopped processes and a list of all running processes. + /// public interface IProcessMonitorService : IArtemisService { + /// + /// Occurs when a process starts. + /// event EventHandler ProcessStarted; + /// + /// Occurs when a process stops. + /// event EventHandler ProcessStopped; + /// + /// Returns an enumerable with the processes running on the system. + /// IEnumerable GetRunningProcesses(); } } diff --git a/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs index a487fc626..86f38e0a1 100644 --- a/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs +++ b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs @@ -7,24 +7,26 @@ using System.Timers; namespace Artemis.Core.Services { - public class ProcessMonitorService : IProcessMonitorService + internal class ProcessMonitorService : IProcessMonitorService { private readonly ILogger _logger; private readonly Timer _processScanTimer; + private readonly ProcessComparer _comparer; private Process[] _lastScannedProcesses; public ProcessMonitorService(ILogger logger) { _logger = logger; - _lastScannedProcesses = Process.GetProcesses().DistinctBy(p => p.ProcessName).ToArray(); + _lastScannedProcesses = Process.GetProcesses(); _processScanTimer = new Timer(1000); _processScanTimer.Elapsed += OnTimerElapsed; _processScanTimer.Start(); + _comparer = new ProcessComparer(); } - public event EventHandler ProcessStarted; + public event EventHandler? ProcessStarted; - public event EventHandler ProcessStopped; + public event EventHandler? ProcessStopped; public IEnumerable GetRunningProcesses() { @@ -33,14 +35,14 @@ namespace Artemis.Core.Services private void OnTimerElapsed(object sender, ElapsedEventArgs e) { - var newProcesses = Process.GetProcesses().DistinctBy(p => p.ProcessName).ToArray(); - foreach (var startedProcess in newProcesses.Except(_lastScannedProcesses, new ProcessComparer())) + Process[] newProcesses = Process.GetProcesses(); + foreach (Process startedProcess in newProcesses.Except(_lastScannedProcesses, _comparer)) { ProcessStarted?.Invoke(this, new ProcessEventArgs(startedProcess)); _logger.Debug("Started Process: {startedProcess}", startedProcess.ProcessName); } - foreach (var stoppedProcess in _lastScannedProcesses.Except(newProcesses, new ProcessComparer())) + foreach (Process stoppedProcess in _lastScannedProcesses.Except(newProcesses, _comparer)) { ProcessStopped?.Invoke(this, new ProcessEventArgs(stoppedProcess)); _logger.Debug("Stopped Process: {stoppedProcess}", stoppedProcess.ProcessName);