Agents can read recent S3 log lines without scraping UMM files. TrySetActive changes session state only, so benchmarks and MCP can toggle modules without writing the UMM enabled flags.
112 lines
3.1 KiB
C#
112 lines
3.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace S3.Core;
|
|
|
|
/// <summary>
|
|
/// Holds every registered module and enables the ones flagged on at load.
|
|
/// One failing module must never take down the rest, so each enable is guarded.
|
|
/// </summary>
|
|
public sealed class ModuleRegistry
|
|
{
|
|
private readonly List<IModule> _modules = new();
|
|
private readonly HashSet<IModule> _active = new();
|
|
|
|
public IReadOnlyList<IModule> Modules => _modules;
|
|
|
|
public void Register(IModule module) => _modules.Add(module);
|
|
|
|
/// <summary>Call <see cref="IModule.OnEnable"/> on every module currently enabled.</summary>
|
|
public void EnableConfigured()
|
|
{
|
|
foreach (IModule m in _modules)
|
|
{
|
|
if (!m.Enabled)
|
|
{
|
|
Log.Info($"[{m.Id}] disabled — skipping.");
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
m.OnEnable();
|
|
_active.Add(m);
|
|
Log.Info($"[{m.Id}] enabled.");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Log.Error($"[{m.Id}] failed to enable: {e}");
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsActive(IModule module) => _active.Contains(module);
|
|
|
|
public bool IsActive(string id)
|
|
{
|
|
IModule? module = Find(id);
|
|
return module != null && _active.Contains(module);
|
|
}
|
|
|
|
public IModule? Find(string id)
|
|
{
|
|
foreach (IModule module in _modules)
|
|
if (string.Equals(module.Id, id, StringComparison.OrdinalIgnoreCase))
|
|
return module;
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Changes a module's live state without changing its persisted Enabled setting.
|
|
/// Callers that want the change persisted must update Enabled and SaveSettings.
|
|
/// </summary>
|
|
public bool TrySetActive(string id, bool active, out string message)
|
|
{
|
|
IModule? module = Find(id);
|
|
if (module == null)
|
|
{
|
|
message = "unknown module: " + id;
|
|
return false;
|
|
}
|
|
|
|
bool current = _active.Contains(module);
|
|
if (current == active)
|
|
{
|
|
message = $"{module.Id} active={active} (unchanged)";
|
|
return true;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (active)
|
|
{
|
|
module.OnEnable();
|
|
_active.Add(module);
|
|
}
|
|
else
|
|
{
|
|
module.OnDisable();
|
|
_active.Remove(module);
|
|
}
|
|
message = $"{module.Id} active={active}";
|
|
Log.Info($"[{module.Id}] live active={active}.");
|
|
return true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
message = $"{module.Id} active={current}; transition failed: {e.Message}";
|
|
Log.Error($"[{module.Id}] live transition to active={active} failed: {e}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>Persist every module's settings (called from UMM's OnSaveGUI).</summary>
|
|
public void SaveAll()
|
|
{
|
|
foreach (IModule m in _modules)
|
|
{
|
|
try { m.SaveSettings(); }
|
|
catch (Exception e) { Log.Error($"[{m.Id}] failed to save settings: {e}"); }
|
|
}
|
|
}
|
|
}
|