#nullable enable using System; using System.Collections.Generic; using Cysharp.Threading.Tasks; using ShrinkContext; using ShrinkNetwork; namespace ShrinkNetwork.Integration.App { /// ShrinkNetwork 组件的配置。 public sealed class ShrinkNetworkAppModuleConfig { /// 是否在激活时自动绑定 loopback 传输并打开默认会话(演示/调试台用)。 public bool BindLoopbackTransport; public int LoopbackSessionId = 1; /// 可选:把网络服务同时注册进 ShrinkApp 服务容器(兼容旧调试台读取路径)。 public ShrinkApp.ShrinkAppServices? Services; } /// /// ShrinkNetwork 的原生 Cordis 组件(阶段 3): /// - 提供 shrink.service.network 余效应键(服务实例),依赖者按键注入; /// - 可选的 loopback 传输绑定是**可逆效应**:停用时解绑传输、清理会话并使挂起 RPC 失败—— /// 全部由效应回滚完成,而非手写卸载路径; /// - 与经典 ShrinkNetworkAppInstaller(ModuleId "shrink.network")二选一使用: /// 两者都发布 "app.module.shrink.network",同时激活会触发供给冲突。 /// public sealed class ShrinkNetworkAppComponent : IShrinkComponent { public const string ServiceKey = "shrink.service.network"; public const string ModuleKey = "app.module.shrink.network"; private static readonly string[] ProvideKeys = { ModuleKey, ServiceKey }; public string Name => "shrink.network"; public IReadOnlyList Inject => Array.Empty(); public IReadOnlyList Provide => ProvideKeys; public async UniTask ApplyAsync(ShrinkCtx ctx, object? config) { var moduleConfig = config as ShrinkNetworkAppModuleConfig ?? new ShrinkNetworkAppModuleConfig(); var service = ShrinkNetworkRuntime.Default; // set 是可逆效应:停用自动撤回服务键,依赖者随之停用 ctx.Set(ServiceKey, service); var facade = new ShrinkNetworkAppService(service); moduleConfig.Services?.Register(facade); if (config is ShrinkApp.ShrinkAppServices appServices) { appServices.Register(facade); ctx.EffectInverse(() => { appServices.TryUnregister(facade); return UniTask.CompletedTask; }); } ctx.Set(ModuleKey, Name); if (moduleConfig.BindLoopbackTransport) { await ctx.EffectAsync(() => BindLoopbackAsync(service, moduleConfig.LoopbackSessionId)); } } private static async UniTask> BindLoopbackAsync(ShrinkNetworkService service, int sessionId) { var client = new ShrinkLoopbackTransport(); var server = new ShrinkLoopbackTransport(); client.LinkPeer(server); service.BindTransport(client); client.OpenSession(sessionId); await UniTask.CompletedTask; return () => { // 逆操作:关闭会话并解绑传输;BindTransport(null) 触发会话清理与挂起 RPC 失败 client.CloseSession(sessionId); service.BindTransport(null); return UniTask.CompletedTask; }; } } }