#nullable enable using System; using System.Collections.Generic; using Cysharp.Threading.Tasks; using ShrinkNetwork; namespace ShrinkCommand.Integration { public static class ShrinkNetworkCommandBridge { public const string ExecuteRoute = "command/execute"; private static readonly object SyncRoot = new(); private static readonly HashSet RegisteredServices = new(); public static void RegisterService( ShrinkNetworkService networkService, ShrinkCommandService commandService, ShrinkNetworkCommandBridgeOptions? options = null) { if (networkService == null) throw new ArgumentNullException(nameof(networkService)); if (commandService == null) throw new ArgumentNullException(nameof(commandService)); lock (SyncRoot) { if (RegisteredServices.Contains(networkService)) return; RegisteredServices.Add(networkService); } options ??= new ShrinkNetworkCommandBridgeOptions(); EnsureMessagesRegistered(networkService); var requirement = new ShrinkNetworkPermissionRequirement(options.Authority, options.Permission); networkService.RegisterRequestHandler( (context, request) => HandleExecuteAsync(commandService, options, context, request), requirement); } public static void EnsureMessagesRegistered(ShrinkNetworkService service) { if (!service.MessageRegistry.TryGetMeta(typeof(ShrinkNetworkCommandRequest), out _)) { var requestAttribute = (ShrinkNetworkMessageAttribute)Attribute.GetCustomAttribute( typeof(ShrinkNetworkCommandRequest), typeof(ShrinkNetworkMessageAttribute), false)!; service.RegisterMessage(typeof(ShrinkNetworkCommandRequest), requestAttribute.Opcode, requestAttribute.Route); } if (!service.MessageRegistry.TryGetMeta(typeof(ShrinkNetworkCommandResponse), out _)) { var responseAttribute = (ShrinkNetworkMessageAttribute)Attribute.GetCustomAttribute( typeof(ShrinkNetworkCommandResponse), typeof(ShrinkNetworkMessageAttribute), false)!; service.RegisterMessage(typeof(ShrinkNetworkCommandResponse), responseAttribute.Opcode, responseAttribute.Route); } } private static async UniTask HandleExecuteAsync( ShrinkCommandService commandService, ShrinkNetworkCommandBridgeOptions options, ShrinkNetworkContext context, ShrinkNetworkCommandRequest request) { var source = options.SourceFactory?.Invoke(context, request) ?? new ShrinkNetworkCommandSource(context, request); var result = await commandService.ExecuteAsync(source, request.CommandLine); var output = source is ShrinkNetworkCommandSource networkSource ? networkSource.BuildOutputMessage(result.Message) : result.Message; return new ShrinkNetworkCommandResponse { ServiceName = string.IsNullOrWhiteSpace(request.ServiceName) ? options.ServiceName : request.ServiceName.Trim(), CommandLine = request.CommandLine ?? string.Empty, OutputMessage = output, ErrorCode = result.IsSuccess ? 0 : ShrinkRpcErrorCode.HandlerException, ErrorMessage = result.IsSuccess ? string.Empty : output }; } } }