feat(cordis): 完成阶段5配置与调试工具

This commit is contained in:
2026-08-17 01:58:46 +08:00
parent 8738e633ee
commit 5765f411e9
29 changed files with 1322 additions and 18 deletions
@@ -27,9 +27,19 @@ namespace ShrinkContext.AppAdapter
public string ModuleId = string.Empty;
}
private sealed class CompositionOptions
{
public bool Enabled;
public IReadOnlyDictionary<string, string>? Isolate;
public IReadOnlyDictionary<string, IReadOnlyDictionary<string, object?>>? Intercept;
}
private readonly Dictionary<string, ModuleRecord> _modules = new(StringComparer.OrdinalIgnoreCase);
private readonly HashSet<string> _disabled = new(StringComparer.OrdinalIgnoreCase);
private readonly HashSet<string> _settingsDisabled = new(StringComparer.OrdinalIgnoreCase);
private readonly ShrinkComponentCatalog _catalog;
private Dictionary<string, CompositionOptions>? _compositionOptions;
private bool _includeUnlistedEntries = true;
private bool _started;
public ShrinkAppLoaderHost(ShrinkAppSettings? settings = null,
@@ -60,7 +70,10 @@ namespace ShrinkContext.AppAdapter
foreach (var rawId in Settings.disabledModuleIds ?? Array.Empty<string>())
{
if (!string.IsNullOrWhiteSpace(rawId))
{
_settingsDisabled.Add(rawId.Trim());
_disabled.Add(rawId.Trim());
}
}
}
@@ -69,6 +82,7 @@ namespace ShrinkContext.AppAdapter
public ShrinkContextRuntime Context { get; }
public ShrinkContextLoader Loader { get; }
public bool IsRunning { get; private set; }
public ShrinkAppCompositionDocument? AppliedComposition { get; private set; }
/// <summary>全部已注册模块 id(有序)。</summary>
public IReadOnlyList<string> ModuleIds =>
@@ -88,7 +102,10 @@ namespace ShrinkContext.AppAdapter
TryGetLoaderFiber(moduleId, out var fiber) && fiber.State == ShrinkFiberState.Inactive;
public bool IsModuleDisabled(string moduleId) =>
!string.IsNullOrWhiteSpace(moduleId) && _disabled.Contains(moduleId.Trim());
!string.IsNullOrWhiteSpace(moduleId) &&
(_disabled.Contains(moduleId.Trim()) ||
(!_includeUnlistedEntries && _compositionOptions != null &&
!_compositionOptions.ContainsKey(moduleId.Trim())));
/// <summary>查询模块当前纤程(被禁用模块返回 false)。</summary>
public bool TryGetModuleFiber(string moduleId, out ShrinkFiber fiber) =>
@@ -142,6 +159,46 @@ namespace ShrinkContext.AppAdapter
_catalog.Register(normalizedId, componentFactory);
}
/// <summary>
/// 在启动前应用声明式条目策略。组件工厂必须已经由组合根注册;配置不能实例化任意类型。
/// ShrinkAppSettings.disabledModuleIds 仍作为额外禁用集合保留。
/// </summary>
public void ApplyComposition(ShrinkAppCompositionDocument document)
{
if (_started)
throw new InvalidOperationException("Composition can only be applied before StartAsync.");
var copy = (document ?? throw new ArgumentNullException(nameof(document))).Clone();
var options = new Dictionary<string, CompositionOptions>(StringComparer.OrdinalIgnoreCase);
foreach (var entry in copy.entries)
{
var id = entry.NormalizedId;
if (!_modules.ContainsKey(id))
throw new ShrinkLoaderException(
$"Composition entry '{id}' has no registered module/component factory.");
options.Add(id, new CompositionOptions
{
Enabled = entry.enabled,
Isolate = entry.BuildIsolate(),
Intercept = entry.BuildIntercept()
});
}
_compositionOptions = options;
_includeUnlistedEntries = copy.includeUnlistedEntries;
AppliedComposition = copy;
_disabled.Clear();
foreach (var id in _settingsDisabled)
_disabled.Add(id);
foreach (var pair in options)
{
if (!pair.Value.Enabled)
_disabled.Add(pair.Key);
}
}
public async UniTask StartAsync()
{
if (_started)
@@ -172,10 +229,18 @@ namespace ShrinkContext.AppAdapter
if (!TryGetRecord(moduleId, out _))
throw new InvalidOperationException($"Unknown module id: '{moduleId}'.");
var normalizedId = moduleId.Trim();
if (!disabled && !_includeUnlistedEntries && _compositionOptions != null &&
!_compositionOptions.ContainsKey(normalizedId))
{
throw new InvalidOperationException(
$"Module '{normalizedId}' is excluded by the active composition profile.");
}
if (disabled)
_disabled.Add(moduleId.Trim());
_disabled.Add(normalizedId);
else
_disabled.Remove(moduleId.Trim());
_disabled.Remove(normalizedId);
await Loader.ApplyAsync(BuildEntries());
}
@@ -192,8 +257,15 @@ namespace ShrinkContext.AppAdapter
{
var entries = new List<ShrinkLoaderEntry>();
foreach (var record in _modules.Values.OrderBy(m => m.ModuleId, StringComparer.OrdinalIgnoreCase))
{
CompositionOptions? options = null;
_compositionOptions?.TryGetValue(record.ModuleId, out options);
if (!_includeUnlistedEntries && _compositionOptions != null && options == null)
continue;
entries.Add(new ShrinkLoaderEntry(record.ModuleId, record.ModuleId, Services,
_disabled.Contains(record.ModuleId)));
_disabled.Contains(record.ModuleId), options?.Isolate, options?.Intercept));
}
return entries;
}