diff --git a/Library/App/App.csproj b/Library/App/App.csproj
index cdc89b3..9c51dbc 100644
--- a/Library/App/App.csproj
+++ b/Library/App/App.csproj
@@ -37,9 +37,9 @@
+
-
diff --git a/Library/App/Forms/MainForm/MainForm.cs b/Library/App/Forms/MainForm/MainForm.cs
index 0f11e43..b764037 100644
--- a/Library/App/Forms/MainForm/MainForm.cs
+++ b/Library/App/Forms/MainForm/MainForm.cs
@@ -3,6 +3,7 @@
using App.Utils;
using Contracts.Scripts.Base;
using Data;
+using Data.Service.Interfaces;
using JobManager.Service;
using MaterialSkin.Controls;
@@ -13,17 +14,19 @@ public partial class MainForm : BaseForm
private readonly TrayContextMenu _trayContextMenu;
private readonly IWindowsRegistryService _windowsRegistryService;
- public MainForm(IRunScriptService runScriptService, IWindowsRegistryService windowsRegistryService)
+ public MainForm(IRunScriptService runScriptService, IWindowsRegistryService windowsRegistryService, IScriptsService scriptsService)
{
InitializeComponent();
_windowsRegistryService = windowsRegistryService;
- _trayContextMenu = new TrayContextMenu();
- ConfigureTrayContextMenu();
+ var scripts = runTabControl.SetScriptsService(scriptsService);
runTabControl.SetRunScriptService(runScriptService);
runTabControl.ScriptEdited += RunTabControl_ScriptEdited;
runTabControl.ScriptAdded += RunTabControl_ScriptAdded;
runTabControl.ScriptRemoved += RunTabControl_ScriptRemoved;
+
+ _trayContextMenu = new TrayContextMenu();
+ ConfigureTrayContextMenu(scripts);
}
protected override void WndProc(ref Message m)
@@ -98,12 +101,12 @@ private void ShowForm()
TopMost = true;
TopMost = currentTop;
}
- private void ConfigureTrayContextMenu()
+ private void ConfigureTrayContextMenu(List scripts)
{
_trayContextMenu.CloseClicked += ContextMenu_Close_Click;
_trayContextMenu.OpenClicked += ContextMenu_Open_Click;
_trayContextMenu.ScriptStatusClicked += ContextMenu_StatusClick;
- _trayContextMenu.LoadScriptList(SettingsManager.Scripts);
+ _trayContextMenu.LoadScriptList(scripts);
this.appNotifyIcon.ContextMenuStrip = _trayContextMenu;
}
private void ChangeScriptStatus(ScriptAbs script)
diff --git a/Library/App/Forms/MainForm/Tabs/Run/RunTabControl.cs b/Library/App/Forms/MainForm/Tabs/Run/RunTabControl.cs
index 34ab8f8..a9a471a 100644
--- a/Library/App/Forms/MainForm/Tabs/Run/RunTabControl.cs
+++ b/Library/App/Forms/MainForm/Tabs/Run/RunTabControl.cs
@@ -3,7 +3,7 @@
using Contracts.Key;
using Contracts.Scripts;
using Contracts.Scripts.Base;
-using Data;
+using Data.Service.Interfaces;
using JobManager.Service;
using MaterialSkin.Controls;
using Serilog;
@@ -20,10 +20,14 @@ public partial class RunTabControl : UserControl
private readonly ScriptListAdapter _scriptListAdapter;
private readonly ListenKeysService _listenKeysService;
private IRunScriptService? _runScriptService;
+ private IScriptsService? _scriptsService;
+ private List _scripts;
public RunTabControl()
{
InitializeComponent();
+ _scripts = new();
+
_scriptListAdapter = new ScriptListAdapter(pnlScripts);
_scriptListAdapter.ShowMenu += ShowContextMenuScript;
_scriptListAdapter.StatusClicked += ChangeScriptStatusClicked;
@@ -31,21 +35,35 @@ public RunTabControl()
_listenKeysService = ListenKeysService.GetInstance();
_listenKeysService.KeyUpClicked += ListenKeysService_KeyUpClicked;
}
+
+ #region Public methods
public void SetRunScriptService(IRunScriptService runScriptService)
{
_runScriptService = runScriptService;
_runScriptService.OneOffScriptExecuted += OneOffJobWasExecuted;
}
+ public List SetScriptsService(IScriptsService scriptsService)
+ {
+ _scriptsService = scriptsService;
+ _scripts = _scriptsService.GetScripts();
+ return _scripts;
+ }
+ public async void RefreshScriptStatusAsync(string scriptId)
+ {
+ var script = _scripts.FirstOrDefault(s => s.Id == scriptId)?.Clone();
+ await ChangeScriptStatusAsync(script);
+ }
+ #endregion
#region Events
private async void OnLoad(object sender, EventArgs e)
{
if (this.DesignMode) return;
- _scriptListAdapter.CreateWithList(SettingsManager.Scripts);
- await CheckIfScriptsNeedToRunOnLoad();
+ _scriptListAdapter.CreateWithList(_scripts);
+ await CheckIfScriptsNeedToRunOnLoadAsync();
}
private void OneOffJobWasExecuted(string scriptId)
{
- var script = SettingsManager.FindScriptById(scriptId);
+ var script = _scripts.FirstOrDefault(s => s.Id == scriptId)?.Clone();
if (script != null)
ChangeScriptStatusThreadSafe(script);
}
@@ -74,7 +92,7 @@ private async void ContextMenuItemClicked(object sender, ToolStripItemClickedEve
}
else if (e.ClickedItem.Text == "Remove")
{
- await ShowRemoveScriptDialogAsync(script);
+ ShowRemoveScriptDialog(script);
}
}
private void ListenKeysService_KeyUpClicked(KeyPressed keyPressed)
@@ -93,7 +111,7 @@ private void ListenKeysService_KeyUpClicked(KeyPressed keyPressed)
#endregion
#region Private Methods
- private async Task CheckIfScriptsNeedToRunOnLoad()
+ private async Task CheckIfScriptsNeedToRunOnLoadAsync()
{
foreach (var script in GetRunningScriptsByType())
await _runScriptService!.RunScriptAsync(script);
@@ -101,10 +119,10 @@ private async Task CheckIfScriptsNeedToRunOnLoad()
if (IsListenKeyServiceNecessary())
_listenKeysService.Run();
}
- private static bool IsListenKeyServiceNecessary(string? executingScriptId = null)
+ private bool IsListenKeyServiceNecessary(string? executingScriptId = null)
=> GetRunningScriptsByType()?.Any(s => s.Id != executingScriptId) ?? false;
- private static IEnumerable GetRunningScriptsByType()
- where T : ScriptAbs => SettingsManager.Scripts.OfType().Where(s => s.ScriptStatus == ScriptStatus.Running);
+ private IEnumerable GetRunningScriptsByType()
+ where T : ScriptAbs => _scripts.OfType().Where(s => s.ScriptStatus == ScriptStatus.Running);
private void ChangeScriptStatusThreadSafe(ScriptAbs script)
=> this.Invoke((MethodInvoker) async delegate () { await ChangeScriptStatusAsync(script); });
private async Task ShowEditScriptFormAsync(ScriptAbs script)
@@ -114,7 +132,7 @@ await ShowScriptForm(script, async (ScriptAbs? editedScript) => {
return;
Log.Debug("Editing Script {@ScriptName} ({@ScriptType})", editedScript.ScriptName, editedScript.ScriptType);
bool rescheduleJob = ScriptAbs.HasScriptTypeChanged(script.ScriptType, editedScript.ScriptType) || ScriptAbs.HasScheduledTimeChanged(script, editedScript);
- await SettingsManager.EditScriptAsync(editedScript);
+ UpdateScript(editedScript);
if (editedScript.ScriptStatus == ScriptStatus.Running && rescheduleJob)
{
await _runScriptService!.StopScriptAsync(editedScript);
@@ -129,23 +147,24 @@ await ShowScriptForm(script, async (ScriptAbs? editedScript) => {
}
private async Task ShowAddScriptForm()
{
- await ShowScriptForm(null, async (ScriptAbs? addedScript) => {
+ await ShowScriptForm(null, (ScriptAbs? addedScript) => {
if (addedScript == null)
- return;
+ return Task.CompletedTask;
Log.Debug("Adding Script {@ScriptName} ({@ScriptType})", addedScript.ScriptName, addedScript.ScriptType);
addedScript.Id = Guid.NewGuid().ToString();
- await SettingsManager.AddScriptAsync(addedScript);
+ AddScript(addedScript);
_scriptListAdapter.AddItem(addedScript);
ScriptAdded?.Invoke(addedScript);
+ return Task.CompletedTask;
});
}
- private async Task ShowRemoveScriptDialogAsync(ScriptAbs script)
+ private void ShowRemoveScriptDialog(ScriptAbs script)
{
var dialog = new MaterialDialog(this.ParentForm, "Remove", "Do you want to remove the script?", "Yes", true, "No");
if (dialog.ShowDialog(this) == DialogResult.OK)
{
Log.Debug("Removing ScriptId {@ScriptId}", script.Id);
- await SettingsManager.RemoveScriptAsync(script.Id);
+ DeleteScript(script.Id);
_scriptListAdapter.RemoveItem(script.Id);
ScriptRemoved?.Invoke(script);
}
@@ -182,7 +201,7 @@ private async Task ChangeScriptStatusAsync(ScriptAbs? script)
await _runScriptService!.StopScriptAsync(script);
}
- await SettingsManager.EditScriptAsync(script);
+ UpdateScript(script);
_scriptListAdapter.RefreshScriptStatus(script.Id, script.ScriptStatus);
ScriptEdited?.Invoke(script);
@@ -204,13 +223,26 @@ private static ScriptStatus GetNewScriptStatus(ScriptStatus oldStatus)
}
return newStatus;
}
- #endregion
-
- #region Public methods
- public async void RefreshScriptStatusAsync(string scriptId)
+ private void AddScript(ScriptAbs addedScript)
{
- var script = SettingsManager.FindScriptById(scriptId);
- await ChangeScriptStatusAsync(script);
+ _scriptsService!.AddScript(addedScript);
+ _scripts.Add(addedScript);
+ }
+ private void UpdateScript(ScriptAbs editedScript)
+ {
+ _scriptsService!.UpdateScript(editedScript);
+ int index = _scripts.FindIndex(s => s.Id == editedScript.Id);
+ if (index == -1)
+ return;
+ _scripts[index] = editedScript;
+ }
+ private void DeleteScript(string scriptId)
+ {
+ _scriptsService!.DeleteScript(scriptId);
+ var scriptToDelete = _scripts.FirstOrDefault(s => s.Id == scriptId);
+ if (scriptToDelete == null)
+ return;
+ _scripts.Remove(scriptToDelete);
}
#endregion
diff --git a/Library/App/Program.cs b/Library/App/Program.cs
index e900362..8246b6b 100644
--- a/Library/App/Program.cs
+++ b/Library/App/Program.cs
@@ -6,6 +6,7 @@
using App.Utils;
using Data;
using Data.Extensions;
+using Data.Service.Interfaces;
using JobManager.Service;
using Logging;
using MaterialSkin;
@@ -66,7 +67,7 @@ private static void InitForm(string[] args)
private static void InitServices()
{
ServiceProvider = ServiceCollection!.BuildServiceProvider();
- Data.Service.ISettingsService settingsService = ServiceProvider.GetRequiredService();
+ ISettingsService settingsService = ServiceProvider.GetRequiredService();
Task.Run(async () => await SettingsManager.InitInstanceAsync(settingsService))
.Wait();
LogManager.InstanceLogger(SettingsManager.Settings);
diff --git a/Library/CommonScripts.sln b/Library/CommonScripts.sln
index ca7ad7e..d59e2c2 100644
--- a/Library/CommonScripts.sln
+++ b/Library/CommonScripts.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.3.32901.215
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Settings\Data.csproj", "{D36F28B5-E435-4D65-AC85-B360466D44FE}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Data\Data.csproj", "{D36F28B5-E435-4D65-AC85-B360466D44FE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Contracts", "Contracts\Contracts.csproj", "{C2BC20B0-A72C-43DA-8C46-351ADBA4D1A2}"
EndProject
diff --git a/Library/Settings/Data.csproj b/Library/Data/Data.csproj
similarity index 89%
rename from Library/Settings/Data.csproj
rename to Library/Data/Data.csproj
index 9f181d7..7f3fa7e 100644
--- a/Library/Settings/Data.csproj
+++ b/Library/Data/Data.csproj
@@ -7,6 +7,7 @@
+
diff --git a/Library/Data/DbAccessor.cs b/Library/Data/DbAccessor.cs
new file mode 100644
index 0000000..44bff69
--- /dev/null
+++ b/Library/Data/DbAccessor.cs
@@ -0,0 +1,87 @@
+using Common;
+using LiteDB;
+
+namespace Data
+{
+ public class DbAccessor : IDisposable
+ {
+ private const string DB_NAME = "CommonScripts.db";
+
+ private LiteDatabase? db;
+ private int _activeConnections = 0;
+
+ private static DbAccessor? _instance;
+ private readonly static object _instanceLockObj = new();
+ private readonly static object _accessorLockObj = new();
+
+ public static DbAccessor GetInstance()
+ {
+ if (_instance != null)
+ return _instance;
+ lock (_instanceLockObj)
+ {
+ if (_instance != null)
+ return _instance;
+ _instance = new DbAccessor();
+ }
+ return _instance;
+ }
+
+ public void RunAction(Action action)
+ {
+ try
+ {
+ InitDatabase();
+ action(db!);
+ }
+ catch (Exception)
+ {
+
+ throw;
+ }
+ finally
+ {
+ DecrementConnections();
+ }
+ }
+
+ private void InitDatabase()
+ {
+ Interlocked.Increment(ref _activeConnections);
+ if (db != null)
+ return;
+ lock (_accessorLockObj)
+ {
+ if (db != null)
+ return;
+ db = new LiteDatabase(GetDatabasePath());
+ }
+ }
+
+ private void DecrementConnections()
+ {
+ Interlocked.Decrement(ref _activeConnections);
+ if (_activeConnections == 0)
+ {
+ db?.Dispose();
+ db = null;
+ }
+ }
+
+ public void Dispose()
+ {
+ db?.Dispose();
+ GC.SuppressFinalize(this);
+ }
+
+ private static string GetDatabasePath()
+ {
+#if DEBUG
+ string path = FileUtils.GetConfigDirectory();
+#else
+ string path = SettingsManager.Settings.Core.InstallationPath;
+#endif
+ return Path.Combine(path, DB_NAME);
+ }
+ }
+}
diff --git a/Library/Settings/Extensions/SettingsManagerExtensions.cs b/Library/Data/Extensions/SettingsManagerExtensions.cs
similarity index 60%
rename from Library/Settings/Extensions/SettingsManagerExtensions.cs
rename to Library/Data/Extensions/SettingsManagerExtensions.cs
index e7d4074..52fb246 100644
--- a/Library/Settings/Extensions/SettingsManagerExtensions.cs
+++ b/Library/Data/Extensions/SettingsManagerExtensions.cs
@@ -1,5 +1,7 @@
using Data.Repository;
+using Data.Repository.Interfaces;
using Data.Service;
+using Data.Service.Interfaces;
using Microsoft.Extensions.DependencyInjection;
namespace Data.Extensions
@@ -10,7 +12,9 @@ public static IServiceCollection AddSettingServices(this IServiceCollection serv
{
return serviceCollection
.AddScoped()
- .AddScoped();
+ .AddScoped()
+ .AddScoped()
+ .AddScoped();
}
}
}
diff --git a/Library/Data/Repository/Interfaces/IScriptsRepository.cs b/Library/Data/Repository/Interfaces/IScriptsRepository.cs
new file mode 100644
index 0000000..93fb7fe
--- /dev/null
+++ b/Library/Data/Repository/Interfaces/IScriptsRepository.cs
@@ -0,0 +1,12 @@
+using Contracts.Scripts.Base;
+
+namespace Data.Repository.Interfaces
+{
+ public interface IScriptsRepository
+ {
+ List GetScripts();
+ void DeleteScript(string scriptId);
+ void UpdateScript(ScriptAbs script);
+ void AddScript(ScriptAbs script);
+ }
+}
diff --git a/Library/Data/Repository/Interfaces/ISettingsRepository.cs b/Library/Data/Repository/Interfaces/ISettingsRepository.cs
new file mode 100644
index 0000000..9e4d90d
--- /dev/null
+++ b/Library/Data/Repository/Interfaces/ISettingsRepository.cs
@@ -0,0 +1,10 @@
+using Contracts.Config;
+
+namespace Data.Repository.Interfaces
+{
+ public interface ISettingsRepository
+ {
+ Task ReadSettingsAsync();
+ Task UpdateSettingsAsync(object file);
+ }
+}
diff --git a/Library/Data/Repository/ScriptsRepository.cs b/Library/Data/Repository/ScriptsRepository.cs
new file mode 100644
index 0000000..756558e
--- /dev/null
+++ b/Library/Data/Repository/ScriptsRepository.cs
@@ -0,0 +1,48 @@
+using Contracts.Scripts.Base;
+using Data.Repository.Interfaces;
+using LiteDB;
+
+namespace Data.Repository
+{
+ public class ScriptsRepository : IScriptsRepository
+ {
+ public void DeleteScript(string scriptId)
+ {
+ RunAction(scriptsCollection =>
+ {
+ scriptsCollection.Delete(new BsonValue(scriptId));
+ });
+ }
+
+ public List GetScripts()
+ {
+ List scripts = new();
+
+ RunAction(scriptsCollection =>
+ {
+ scripts = scriptsCollection.FindAll().ToList();
+ });
+
+ return scripts;
+ }
+
+ public void UpdateScript(ScriptAbs script)
+ {
+ RunAction(scriptsCollection =>
+ {
+ scriptsCollection.Update(script);
+ });
+ }
+
+ public void AddScript(ScriptAbs script)
+ {
+ RunAction(scriptsCollection =>
+ {
+ scriptsCollection.Insert(script);
+ });
+ }
+
+ private static void RunAction(Action> action)
+ => DbAccessor.GetInstance().RunAction(db => action(db.GetCollection("scripts")));
+ }
+}
diff --git a/Library/Data/Repository/SettingsRepository.cs b/Library/Data/Repository/SettingsRepository.cs
new file mode 100644
index 0000000..f5f9abb
--- /dev/null
+++ b/Library/Data/Repository/SettingsRepository.cs
@@ -0,0 +1,55 @@
+using Common;
+using Contracts.Config;
+using Data.Repository.Interfaces;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Data.Repository
+{
+ public class SettingsRepository : ISettingsRepository
+ {
+ private const string SettingsFileName = "settings.json";
+ private readonly JsonSerializerOptions _options;
+
+ public SettingsRepository()
+ {
+ _options = new JsonSerializerOptions
+ {
+ Converters = { new JsonStringEnumConverter() },
+ WriteIndented = true
+ };
+ }
+
+ public async Task ReadSettingsAsync()
+ {
+ Settings fileContent;
+ string settingsPath = GetSettingsPath();
+
+ if (!File.Exists(settingsPath))
+ {
+ fileContent = new();
+ CreateDirectoryIfNotExists(settingsPath);
+ await UpdateSettingsAsync(fileContent);
+ }
+ else
+ fileContent = JsonSerializer.Deserialize(await File.ReadAllTextAsync(settingsPath), _options)!;
+
+ return fileContent;
+ }
+
+ public async Task UpdateSettingsAsync(object file)
+ => await File.WriteAllTextAsync(GetSettingsPath(), JsonSerializer.Serialize(file, _options));
+
+ private static string GetSettingsPath()
+ => Path.Combine(FileUtils.GetConfigDirectory(), SettingsFileName);
+
+ private static void CreateDirectoryIfNotExists(string filePath)
+ {
+ string? directoryPath = Path.GetDirectoryName(filePath);
+ if (directoryPath == null)
+ throw new ArgumentNullException(directoryPath);
+ if (!Directory.Exists(directoryPath))
+ Directory.CreateDirectory(directoryPath);
+ }
+ }
+}
diff --git a/Library/Data/Service/Interfaces/IScriptsService.cs b/Library/Data/Service/Interfaces/IScriptsService.cs
new file mode 100644
index 0000000..8f8ba5a
--- /dev/null
+++ b/Library/Data/Service/Interfaces/IScriptsService.cs
@@ -0,0 +1,12 @@
+using Contracts.Scripts.Base;
+
+namespace Data.Service.Interfaces
+{
+ public interface IScriptsService
+ {
+ List GetScripts();
+ void DeleteScript(string scriptId);
+ void UpdateScript(ScriptAbs script);
+ void AddScript(ScriptAbs script);
+ }
+}
diff --git a/Library/Settings/Service/ISettingsService.cs b/Library/Data/Service/Interfaces/ISettingsService.cs
similarity index 52%
rename from Library/Settings/Service/ISettingsService.cs
rename to Library/Data/Service/Interfaces/ISettingsService.cs
index d7dcebc..59f1a50 100644
--- a/Library/Settings/Service/ISettingsService.cs
+++ b/Library/Data/Service/Interfaces/ISettingsService.cs
@@ -1,13 +1,10 @@
using Contracts.Config;
-using Contracts.Scripts.Base;
-namespace Data.Service
+namespace Data.Service.Interfaces
{
public interface ISettingsService
{
Task ReadSettingsAsync();
Task UpdateSettingsAsync(Settings settings);
- Task> ReadScriptsAsync();
- Task UpdateScriptsAsync(List scripts);
}
}
diff --git a/Library/Data/Service/ScriptsService.cs b/Library/Data/Service/ScriptsService.cs
new file mode 100644
index 0000000..607572a
--- /dev/null
+++ b/Library/Data/Service/ScriptsService.cs
@@ -0,0 +1,28 @@
+using Contracts.Scripts.Base;
+using Data.Repository.Interfaces;
+using Data.Service.Interfaces;
+
+namespace Data.Service
+{
+ public class ScriptsService : IScriptsService
+ {
+ private readonly IScriptsRepository _scriptsRepository;
+
+ public ScriptsService(IScriptsRepository scriptsRepository)
+ {
+ _scriptsRepository = scriptsRepository;
+ }
+
+ public void AddScript(ScriptAbs script)
+ => _scriptsRepository.AddScript(script);
+
+ public void DeleteScript(string scriptId)
+ => _scriptsRepository.DeleteScript(scriptId);
+
+ public List GetScripts()
+ => _scriptsRepository.GetScripts();
+
+ public void UpdateScript(ScriptAbs script)
+ => _scriptsRepository.UpdateScript(script);
+ }
+}
diff --git a/Library/Data/Service/SettingsService.cs b/Library/Data/Service/SettingsService.cs
new file mode 100644
index 0000000..6689a8e
--- /dev/null
+++ b/Library/Data/Service/SettingsService.cs
@@ -0,0 +1,22 @@
+using Contracts.Config;
+using Data.Repository.Interfaces;
+using Data.Service.Interfaces;
+
+namespace Data.Service
+{
+ public class SettingsService : ISettingsService
+ {
+ private readonly ISettingsRepository _fileRepository;
+
+ public SettingsService(ISettingsRepository fileRepository)
+ {
+ _fileRepository = fileRepository;
+ }
+
+ public async Task ReadSettingsAsync()
+ => await _fileRepository.ReadSettingsAsync();
+
+ public async Task UpdateSettingsAsync(Settings settings)
+ => await _fileRepository.UpdateSettingsAsync(settings);
+ }
+}
diff --git a/Library/Data/SettingsManager.cs b/Library/Data/SettingsManager.cs
new file mode 100644
index 0000000..abea609
--- /dev/null
+++ b/Library/Data/SettingsManager.cs
@@ -0,0 +1,59 @@
+using Contracts.Config;
+using Data.Service.Interfaces;
+
+namespace Data
+{
+ public class SettingsManager
+ {
+ private static SettingsManager? _instance;
+
+ private readonly ISettingsService _settingsService;
+ private Settings? _settings;
+
+ private SettingsManager(ISettingsService settingsService)
+ {
+ _settingsService = settingsService;
+ }
+
+ public static Settings Settings
+ => GetInstance().GetSettings();
+
+ public static Settings CloneSettings
+ => (Settings)GetInstance().GetSettings().Clone();
+
+ public static async Task InitInstanceAsync(ISettingsService settingsService)
+ {
+ _instance = new(settingsService);
+ await _instance.InitConfigFilesAsync();
+ }
+
+ public static async Task UpdateSettingsAsync(Settings newSettings)
+ => await GetInstance().UpdateSettingsFileAsync(newSettings);
+
+ public static async Task UpdateSettingsAsync(Action action)
+ {
+ Settings settings = CloneSettings;
+ action(settings);
+ await UpdateSettingsAsync(settings);
+ }
+
+ private static SettingsManager GetInstance()
+ => _instance ?? throw new ArgumentNullException("Instance is not initiated. Call InitInstance() method first");
+
+ private async Task InitConfigFilesAsync()
+ {
+ _settings = await _settingsService.ReadSettingsAsync();
+ }
+
+ private Settings GetSettings()
+ => _settings!;
+
+ private async Task UpdateSettingsFileAsync(Settings newSettings)
+ {
+ if (newSettings.Equals(_settings))
+ return;
+ await _settingsService.UpdateSettingsAsync(newSettings);
+ _settings = newSettings;
+ }
+ }
+}
diff --git a/Library/JobManager/Job/RunScriptJob.cs b/Library/JobManager/Job/RunScriptJob.cs
index e98611a..7fa87ca 100644
--- a/Library/JobManager/Job/RunScriptJob.cs
+++ b/Library/JobManager/Job/RunScriptJob.cs
@@ -28,13 +28,19 @@ private Task RunScript()
if (File.Exists(realPath))
{
Log.Information("Executing {@ScriptName}", _script.ScriptName);
- string psScript = $"Set-Location \"{realPath}\"{Environment.NewLine}";
+ string psScript = $"Set-Location \"{Path.GetDirectoryName(realPath)}\"{Environment.NewLine}";
psScript += File.ReadAllText(realPath);
Log.Verbose("Script content: {ScriptContent}", psScript);
using var powerShell = PowerShell.Create();
- powerShell
+ string output = "";
+ var scriptOutput = powerShell
.AddScript(psScript)
.Invoke();
+ foreach (var line in scriptOutput)
+ output += line + Environment.NewLine;
+ if (string.IsNullOrWhiteSpace(output))
+ output = "(no output)";
+ Log.Debug("Script output: {Output}", output.TrimEnd());
}
else
{
diff --git a/Library/Settings/Converter/ScriptJsonConverter.cs b/Library/Settings/Converter/ScriptJsonConverter.cs
deleted file mode 100644
index 7905692..0000000
--- a/Library/Settings/Converter/ScriptJsonConverter.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-using Contracts.Scripts;
-using Contracts.Scripts.Base;
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-namespace Data.Converter
-{
- public class ScriptJsonConverter : JsonConverter
- {
- private enum TypeDiscriminator
- {
- BaseClass = 0,
- Scheduled = 1,
- OneOff = 2,
- ListenKey = 3
- }
-
- private readonly JsonSerializerOptions _converterOptions = new() { Converters = { new JsonStringEnumConverter() } };
-
- public override bool CanConvert(Type type)
- {
- return typeof(ScriptAbs).IsAssignableFrom(type);
- }
-
- public override ScriptAbs? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- if (reader.TokenType != JsonTokenType.StartObject)
- {
- throw new JsonException();
- }
-
- TypeDiscriminator typeDiscriminator = GetTypeDiscriminator(ref reader);
- ScriptAbs baseClass = typeDiscriminator switch
- {
- TypeDiscriminator.Scheduled => GetScript(ref reader),
- TypeDiscriminator.ListenKey => GetScript(ref reader),
- TypeDiscriminator.OneOff => GetScript(ref reader),
- _ => throw new NotSupportedException(),
- };
- if (!reader.Read() || reader.TokenType != JsonTokenType.EndObject)
- {
- throw new JsonException();
- }
-
- return baseClass;
- }
-
- public override void Write(Utf8JsonWriter writer, ScriptAbs value, JsonSerializerOptions options)
- {
- writer.WriteStartObject();
-
- if (value is ScriptOneOff derivedA)
- {
- writer.WriteNumber("TypeDiscriminator", (int)TypeDiscriminator.OneOff);
- writer.WritePropertyName("TypeValue");
- JsonSerializer.Serialize(writer, derivedA, _converterOptions);
- }
- else if (value is ScriptListenKey derivedB)
- {
- writer.WriteNumber("TypeDiscriminator", (int)TypeDiscriminator.ListenKey);
- writer.WritePropertyName("TypeValue");
- JsonSerializer.Serialize(writer, derivedB, _converterOptions);
- }
- else if (value is ScriptScheduled derivedC)
- {
- writer.WriteNumber("TypeDiscriminator", (int)TypeDiscriminator.Scheduled);
- writer.WritePropertyName("TypeValue");
- JsonSerializer.Serialize(writer, derivedC, _converterOptions);
- }
- else
- {
- throw new NotSupportedException();
- }
-
- writer.WriteEndObject();
- }
-
- private static TypeDiscriminator GetTypeDiscriminator(ref Utf8JsonReader reader)
- {
- if (!reader.Read()
- || reader.TokenType != JsonTokenType.PropertyName
- || reader.GetString() != "TypeDiscriminator")
- {
- throw new JsonException();
- }
-
- if (!reader.Read() || reader.TokenType != JsonTokenType.Number)
- {
- throw new JsonException();
- }
-
- return (TypeDiscriminator)reader.GetInt32();
- }
-
- private T GetScript(ref Utf8JsonReader reader)
- {
- if (!reader.Read() || reader.GetString() != "TypeValue")
- {
- throw new JsonException();
- }
- if (!reader.Read() || reader.TokenType != JsonTokenType.StartObject)
- {
- throw new JsonException();
- }
-
- return (T)JsonSerializer.Deserialize(ref reader, typeof(T), _converterOptions)!;
- }
- }
-}
diff --git a/Library/Settings/Repository/FileRepository.cs b/Library/Settings/Repository/FileRepository.cs
deleted file mode 100644
index c26c88a..0000000
--- a/Library/Settings/Repository/FileRepository.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using Data.Converter;
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-namespace Data.Repository
-{
- public class FileRepository : IFileRepository
- {
- private JsonSerializerOptions _options;
- public FileRepository()
- {
- _options = new JsonSerializerOptions
- {
- Converters = { new ScriptJsonConverter(), new JsonStringEnumConverter() },
- WriteIndented = true
- };
- }
- public bool FileExists(string path)
- => File.Exists(path);
-
- public async Task GetFileAsync(string path)
- => JsonSerializer.Deserialize(await File.ReadAllTextAsync(path), _options)!;
-
- public async Task UpdateFileAsync(object file, string path)
- => await File.WriteAllTextAsync(path, JsonSerializer.Serialize(file, _options));
- }
-}
diff --git a/Library/Settings/Repository/IFileRepository.cs b/Library/Settings/Repository/IFileRepository.cs
deleted file mode 100644
index e514a9b..0000000
--- a/Library/Settings/Repository/IFileRepository.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Data.Repository
-{
- public interface IFileRepository
- {
- bool FileExists(string path);
- Task GetFileAsync(string path);
- Task UpdateFileAsync(object file, string path);
- }
-}
diff --git a/Library/Settings/Service/SettingsService.cs b/Library/Settings/Service/SettingsService.cs
deleted file mode 100644
index 123a6f0..0000000
--- a/Library/Settings/Service/SettingsService.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-using Common;
-using Contracts.Config;
-using Contracts.Scripts.Base;
-using Data.Repository;
-
-namespace Data.Service
-{
- public class SettingsService : ISettingsService
- {
- private readonly IFileRepository _fileRepository;
- private const string SettingsFileName = "settings.json";
- private const string ScriptsFileName = "scripts.json";
-
- public SettingsService(IFileRepository fileRepository)
- {
- _fileRepository = fileRepository;
- }
-
- public async Task> ReadScriptsAsync()
- => await ReadFileAsync< List>(GetScriptsPath());
-
- public async Task ReadSettingsAsync()
- => await ReadFileAsync(GetConfigPath());
-
- public async Task UpdateScriptsAsync(List scripts)
- => await _fileRepository.UpdateFileAsync(scripts, GetScriptsPath());
-
- public async Task UpdateSettingsAsync(Settings settings)
- => await _fileRepository.UpdateFileAsync(settings, GetConfigPath());
-
- private async Task ReadFileAsync(string filePath)
- where T : new()
- {
- T fileContent;
-
- if (!_fileRepository.FileExists(filePath))
- {
- fileContent = new();
- CreateDirectoryIfNotExists(filePath);
- await _fileRepository.UpdateFileAsync(fileContent, filePath);
- }
- else
- fileContent = await _fileRepository.GetFileAsync(filePath);
-
- return fileContent;
- }
-
- private static void CreateDirectoryIfNotExists(string filePath)
- {
- string? directoryPath = Path.GetDirectoryName(filePath);
- if (directoryPath == null)
- throw new ArgumentNullException(directoryPath);
- if (!Directory.Exists(directoryPath))
- Directory.CreateDirectory(directoryPath);
- }
-
- private static string GetFilePath(string configFilename)
- => Path.Combine(FileUtils.GetConfigDirectory(), configFilename);
-
- private static string GetConfigPath()
- => GetFilePath(SettingsFileName);
-
- private static string GetScriptsPath()
- => GetFilePath(ScriptsFileName);
- }
-}
diff --git a/Library/Settings/SettingsManager.cs b/Library/Settings/SettingsManager.cs
deleted file mode 100644
index f65a8d9..0000000
--- a/Library/Settings/SettingsManager.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-using Contracts.Config;
-using Contracts.Scripts.Base;
-using Data.Service;
-
-namespace Data
-{
- public class SettingsManager
- {
- private static SettingsManager? _instance;
-
- private readonly ISettingsService _settingsService;
- private Settings? _settings;
- private List? _scripts;
-
- private SettingsManager(ISettingsService settingsService)
- {
- _settingsService = settingsService;
- }
-
- public static Settings Settings
- => GetInstance().GetSettings();
-
- public static Settings CloneSettings
- => (Settings)GetInstance().GetSettings().Clone();
-
- public static List Scripts
- => GetInstance().GetScripts();
-
- public static ScriptAbs? FindScriptById(string scriptId)
- => GetInstance().GetScripts().FirstOrDefault(s => s.Id == scriptId)?.Clone();
-
- public static async Task InitInstanceAsync(ISettingsService settingsService)
- {
- _instance = new(settingsService);
- await _instance.InitConfigFilesAsync();
- }
-
- public static async Task UpdateSettingsAsync(Settings newSettings)
- => await GetInstance().UpdateSettingsFileAsync(newSettings);
-
- public static async Task UpdateSettingsAsync(Action action)
- {
- Settings settings = CloneSettings;
- action(settings);
- await UpdateSettingsAsync(settings);
- }
-
- public static async Task UpdateScriptsAsync(List newScripts)
- => await GetInstance().UpdateScriptsFileAsync(newScripts);
-
- public static async Task AddScriptAsync(ScriptAbs newScript)
- => await UpdateScriptsAsync(scripts => scripts.Add(newScript));
-
- public static async Task EditScriptAsync(ScriptAbs scriptToEdit)
- {
- int index = Scripts.FindIndex(s => s.Id == scriptToEdit.Id);
- if (index == -1)
- return;
- await UpdateScriptsAsync(scripts => scripts[index] = scriptToEdit);
- }
-
- public static async Task RemoveScriptAsync(string scriptId)
- {
- var scriptToDelete = Scripts.FirstOrDefault(s => s.Id == scriptId);
- if (scriptToDelete == null)
- return;
- await UpdateScriptsAsync(scripts => scripts.Remove(scriptToDelete));
- }
-
- public static async Task UpdateScriptsAsync(Action> action)
- {
- List scripts = GetInstance().GetScripts();
- action(scripts);
- await UpdateScriptsAsync(scripts);
- }
-
- private static SettingsManager GetInstance()
- => _instance ?? throw new ArgumentNullException("Instance is not initiated. Call InitInstance() method first");
-
- private async Task InitConfigFilesAsync()
- {
- _settings = await _settingsService.ReadSettingsAsync();
- _scripts = await _settingsService.ReadScriptsAsync();
- }
-
- private Settings GetSettings()
- => _settings!;
-
- private List GetScripts()
- => _scripts!;
-
- private async Task UpdateSettingsFileAsync(Settings newSettings)
- {
- if (newSettings.Equals(_settings))
- return;
- await _settingsService.UpdateSettingsAsync(newSettings);
- _settings = newSettings;
- }
- private async Task UpdateScriptsFileAsync(List newScripts)
- {
- await _settingsService.UpdateScriptsAsync(newScripts);
- _scripts = newScripts;
- }
- }
-}