#nullable enable using System; using System.Collections.Generic; using System.Linq; using Cysharp.Threading.Tasks; using ShrinkApp; namespace ShrinkContext.AppAdapter { /// /// 把现有 包装为 ShrinkContext 组件: /// - inject 由 DependsOn 派生(模块依赖 → 模块键),依赖未就绪时安装器保持非活动等待, /// 而不是像拓扑排序那样直接抛错; /// - provide 发布模块键 app.module.<ModuleId>(安装器 Active 后对依赖者可见); /// - apply 依次执行 RegisterServices + InitializeAsync,config 必须传入 。 /// /// 已知边界(后续阶段补齐):ShrinkAppServices 尚无注销能力, /// 安装器卸载时不会移除已注册的服务;重新激活会重复执行 RegisterServices(同键覆盖)。 /// public sealed class ShrinkAppInstallerComponent : IShrinkComponent { /// 模块键前缀:依赖声明 DependsOn = ["a"] 映射为 app.module.a public const string ModuleKeyPrefix = "app.module."; private readonly IShrinkAppModuleInstaller _installer; private readonly ShrinkAppSettings? _settings; private readonly string[] _inject; public ShrinkAppInstallerComponent(IShrinkAppModuleInstaller installer, ShrinkAppSettings? settings = null) { _installer = installer ?? throw new ArgumentNullException(nameof(installer)); _settings = settings; _inject = (installer.DependsOn ?? Array.Empty()) .Where(id => !string.IsNullOrWhiteSpace(id)) .Select(id => ModuleKeyPrefix + id.Trim()) .ToArray(); } public string Name => "app-installer:" + _installer.ModuleId; public IReadOnlyList Inject => _inject; public IReadOnlyList Provide => new[] { ModuleKeyPrefix + _installer.ModuleId }; public IShrinkAppModuleInstaller Installer => _installer; public async UniTask ApplyAsync(ShrinkCtx ctx, object? config) { if (config is not ShrinkAppServices services) throw new InvalidOperationException( $"ShrinkAppInstallerComponent '{_installer.ModuleId}' requires ShrinkAppServices as fiber config."); // 先发布模块键再执行安装:装载期绑定对依赖者不可见(提供者须 Active), // 供给冲突(重复 ModuleId)在安装器初始化之前即失败 ctx.Set(Provide[0], _installer.ModuleId); var appContext = ShrinkAppContext.CreateStandalone(services, _settings); _installer.RegisterServices(appContext); await _installer.InitializeAsync(appContext); } } }