using System.IO; using System.Text.Json; using System.Text.Json.Nodes; using MaksIT.UScheduler.Shared; using MaksIT.UScheduler.Shared.Helpers; namespace MaksIT.UScheduler.ScheduleManager.Services; /// /// Service for loading and managing appsettings.json from UScheduler. /// public class AppSettingsService { private string? _appSettingsPath; private JsonNode? _rootDocument; /// /// Gets the path to the appsettings.json file. /// public string? AppSettingsPath => _appSettingsPath; /// /// Gets the directory containing appsettings.json (the service directory). /// public string? ServiceDirectory => string.IsNullOrEmpty(_appSettingsPath) ? null : System.IO.Path.GetDirectoryName(_appSettingsPath); /// /// Loads appsettings.json from the specified path. /// Returns null if path is null/empty or the file does not exist. /// public Configuration? LoadAppSettings(string? appSettingsPath = null) { _appSettingsPath = appSettingsPath; if (string.IsNullOrEmpty(_appSettingsPath) || !File.Exists(_appSettingsPath)) return null; try { var json = File.ReadAllText(_appSettingsPath); _rootDocument = JsonNode.Parse(json); if (_rootDocument == null) return null; var configNode = _rootDocument["Configuration"]; if (configNode == null) return new Configuration { LogDir = ".\\Logs" }; var config = new Configuration { ServiceName = configNode["ServiceName"]?.GetValue() ?? "MaksIT.UScheduler", LogDir = configNode["LogDir"]?.GetValue() ?? ".\\Logs" }; // Parse PowerShell scripts if (configNode["Powershell"] is JsonArray psArray) { foreach (var item in psArray) { if (item == null) continue; config.Powershell.Add(new PowershellScript { Path = item["Path"]?.GetValue() ?? string.Empty, Name = item["Name"]?.GetValue(), IsSigned = item["IsSigned"]?.GetValue() ?? true, Disabled = item["Disabled"]?.GetValue() ?? false }); } } // Parse Processes if (configNode["Processes"] is JsonArray procArray) { foreach (var item in procArray) { if (item == null) continue; var proc = new ProcessConfiguration { Path = item["Path"]?.GetValue() ?? string.Empty, RestartOnFailure = item["RestartOnFailure"]?.GetValue() ?? false, Disabled = item["Disabled"]?.GetValue() ?? false }; if (item["Args"] is JsonArray argsArray) { proc.Args = argsArray.Select(a => a?.GetValue() ?? "").ToArray(); } config.Processes.Add(proc); } } return config; } catch { return null; } } /// /// Gets the resolved log directory path from the service config. /// LogDir may be relative (e.g. ".\Logs"); it is resolved against the service directory, same as script paths. /// public string GetLogDirectory(Configuration? config) { if (config == null || string.IsNullOrEmpty(ServiceDirectory)) return string.Empty; if (!string.IsNullOrEmpty(config.LogDir)) return ResolvePathRelativeToService(config.LogDir); // Default: Logs folder in service directory return System.IO.Path.Combine(ServiceDirectory, "Logs"); } /// /// Gets the service executable path. /// public string GetExecutablePath() { if (string.IsNullOrEmpty(ServiceDirectory)) return string.Empty; var exePath = System.IO.Path.Combine(ServiceDirectory, "MaksIT.UScheduler.exe"); return File.Exists(exePath) ? exePath : string.Empty; } /// /// Reads the LogDir value from MaksIT.UScheduler's appsettings.json at the given path. /// The path should be the full path to appsettings.json (e.g. ServiceBinPath + "appsettings.json"). /// Returns null if the file doesn't exist or Configuration.LogDir is missing. /// public static string? GetLogDirFromAppSettingsFile(string appSettingsFilePath) { if (string.IsNullOrEmpty(appSettingsFilePath) || !File.Exists(appSettingsFilePath)) return null; try { var json = File.ReadAllText(appSettingsFilePath); var doc = JsonNode.Parse(json); var configNode = doc?["Configuration"]; return configNode?["LogDir"]?.GetValue(); } catch { return null; } } /// /// Updates Name, IsSigned and Disabled for a PowerShell script entry in appsettings and saves the file. /// The script is identified by its config path (e.g. ".\file-sync.ps1"). /// Pass null for name to leave the existing Name value unchanged. /// public bool UpdatePowershellScriptEntry(string configScriptPath, string? name, bool isSigned, bool disabled) { if (string.IsNullOrEmpty(_appSettingsPath) || _rootDocument == null) return false; var configNode = _rootDocument["Configuration"]; if (configNode?["Powershell"] is not JsonArray psArray) return false; for (var i = 0; i < psArray.Count; i++) { if (psArray[i] is not JsonObject item) continue; var path = item["Path"]?.GetValue(); if (path != configScriptPath) continue; if (name != null) item["Name"] = name; item["IsSigned"] = isSigned; item["Disabled"] = disabled; try { var options = new JsonWriterOptions { Indented = true }; using var stream = File.Create(_appSettingsPath); using var writer = new Utf8JsonWriter(stream, options); _rootDocument.WriteTo(writer); } catch { return false; } return true; } return false; } /// /// Resolves a path relative to the service directory (where appsettings.json is located). /// If the path is already absolute, returns it as-is. /// public string ResolvePathRelativeToService(string path) => PathHelper.ResolvePath(path, ServiceDirectory ?? string.Empty); }