210 lines
8.3 KiB
C#
210 lines
8.3 KiB
C#
#nullable enable
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using Cysharp.Threading.Tasks;
|
|
using ShrinkEventBus;
|
|
|
|
namespace ShrinkCommand.Integration
|
|
{
|
|
public static class ShrinkCommandEventBusBridge
|
|
{
|
|
private sealed class ServiceRegistration
|
|
{
|
|
public string ServiceName = ShrinkCommandConstants.DefaultServiceName;
|
|
public ShrinkCommandService Service = null!;
|
|
public IShrinkCommandSource? DefaultSource;
|
|
public Action<ShrinkCommandExecutingInfo>? ExecutingHandler;
|
|
public Action<ShrinkCommandExecutedInfo>? ExecutedHandler;
|
|
}
|
|
|
|
private static readonly object SyncRoot = new();
|
|
private static readonly Dictionary<string, ServiceRegistration> RegisteredByName = new(StringComparer.OrdinalIgnoreCase);
|
|
private static readonly Dictionary<ShrinkCommandService, ServiceRegistration> RegisteredByService = new();
|
|
private static bool _initialized;
|
|
|
|
[UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)]
|
|
private static void ResetStaticState()
|
|
{
|
|
lock (SyncRoot)
|
|
{
|
|
foreach (var registration in RegisteredByService.Values)
|
|
{
|
|
if (registration.ExecutingHandler != null)
|
|
registration.Service.OnCommandExecuting -= registration.ExecutingHandler;
|
|
if (registration.ExecutedHandler != null)
|
|
registration.Service.OnCommandExecuted -= registration.ExecutedHandler;
|
|
}
|
|
|
|
RegisteredByService.Clear();
|
|
RegisteredByName.Clear();
|
|
_initialized = false;
|
|
}
|
|
}
|
|
|
|
public static void RegisterService(
|
|
ShrinkCommandService service,
|
|
ShrinkCommandEventBusBridgeOptions? options = null)
|
|
{
|
|
if (service == null)
|
|
throw new ArgumentNullException(nameof(service));
|
|
|
|
EnsureInitialized();
|
|
options ??= new ShrinkCommandEventBusBridgeOptions();
|
|
|
|
lock (SyncRoot)
|
|
{
|
|
if (RegisteredByService.TryGetValue(service, out var existing))
|
|
{
|
|
existing.DefaultSource = options.DefaultSource;
|
|
if (!string.Equals(existing.ServiceName, options.ServiceName, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
RegisteredByName.Remove(existing.ServiceName);
|
|
existing.ServiceName = NormalizeServiceName(options.ServiceName);
|
|
RegisteredByName[existing.ServiceName] = existing;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
var registration = new ServiceRegistration
|
|
{
|
|
ServiceName = NormalizeServiceName(options.ServiceName),
|
|
Service = service,
|
|
DefaultSource = options.DefaultSource
|
|
};
|
|
registration.ExecutingHandler = info => PublishExecuting(registration, info);
|
|
registration.ExecutedHandler = info => PublishExecuted(registration, info);
|
|
service.OnCommandExecuting += registration.ExecutingHandler;
|
|
service.OnCommandExecuted += registration.ExecutedHandler;
|
|
RegisteredByService[service] = registration;
|
|
RegisteredByName[registration.ServiceName] = registration;
|
|
}
|
|
}
|
|
|
|
public static void UnregisterService(ShrinkCommandService service)
|
|
{
|
|
if (service == null)
|
|
return;
|
|
|
|
lock (SyncRoot)
|
|
{
|
|
if (!RegisteredByService.TryGetValue(service, out var registration))
|
|
return;
|
|
|
|
if (registration.ExecutingHandler != null)
|
|
service.OnCommandExecuting -= registration.ExecutingHandler;
|
|
if (registration.ExecutedHandler != null)
|
|
service.OnCommandExecuted -= registration.ExecutedHandler;
|
|
|
|
RegisteredByService.Remove(service);
|
|
RegisteredByName.Remove(registration.ServiceName);
|
|
}
|
|
}
|
|
|
|
public static async UniTask<ShrinkCommandExecutionResult> RequestCommandAsync(
|
|
string rawInput,
|
|
IShrinkCommandSource? source = null,
|
|
string? serviceName = null)
|
|
{
|
|
var requestEvent = new ShrinkCommandExecuteRequestEvent
|
|
{
|
|
ServiceName = NormalizeServiceName(serviceName),
|
|
RawInput = rawInput ?? string.Empty,
|
|
Source = source
|
|
};
|
|
|
|
await EventBus.TriggerEventAsync(requestEvent);
|
|
return requestEvent.ExecutionResult ?? ShrinkCommandExecutionResult.Failure("没有命令桥处理该请求。");
|
|
}
|
|
|
|
private static void EnsureInitialized()
|
|
{
|
|
if (_initialized)
|
|
return;
|
|
|
|
_initialized = true;
|
|
EventBus.RegisterEvent<ShrinkCommandExecuteRequestEvent>(HandleExecuteRequestAsync, EventPriority.LOWEST);
|
|
}
|
|
|
|
private static async UniTask HandleExecuteRequestAsync(ShrinkCommandExecuteRequestEvent eventArgs)
|
|
{
|
|
if (eventArgs == null || eventArgs.IsHandled || eventArgs.IsCanceled)
|
|
return;
|
|
|
|
ServiceRegistration? registration;
|
|
lock (SyncRoot)
|
|
{
|
|
RegisteredByName.TryGetValue(NormalizeServiceName(eventArgs.ServiceName), out registration);
|
|
}
|
|
|
|
if (registration == null)
|
|
{
|
|
eventArgs.IsHandled = true;
|
|
eventArgs.ExecutionResult = ShrinkCommandExecutionResult.Failure(
|
|
$"未找到命令服务: {NormalizeServiceName(eventArgs.ServiceName)}");
|
|
return;
|
|
}
|
|
|
|
var source = eventArgs.Source ?? registration.DefaultSource;
|
|
if (source == null)
|
|
{
|
|
eventArgs.IsHandled = true;
|
|
eventArgs.ExecutionResult = ShrinkCommandExecutionResult.Failure("命令请求缺少来源对象。");
|
|
return;
|
|
}
|
|
|
|
eventArgs.ExecutionResult = await registration.Service.ExecuteAsync(source, eventArgs.RawInput);
|
|
eventArgs.IsHandled = true;
|
|
}
|
|
|
|
private static void PublishExecuting(ServiceRegistration registration, ShrinkCommandExecutingInfo info)
|
|
{
|
|
EventBus.TriggerEvent(new ShrinkCommandExecutingEvent
|
|
{
|
|
ServiceName = registration.ServiceName,
|
|
RawInput = info.RawInput,
|
|
CommandPath = info.Command.Path,
|
|
SourceId = info.Source.SourceId,
|
|
SourceDisplayName = info.Source.DisplayName,
|
|
Arguments = new Dictionary<string, string>(info.Arguments, StringComparer.OrdinalIgnoreCase)
|
|
});
|
|
}
|
|
|
|
private static void PublishExecuted(ServiceRegistration registration, ShrinkCommandExecutedInfo info)
|
|
{
|
|
var commandPath = info.Command?.Path ?? string.Empty;
|
|
var arguments = new Dictionary<string, string>(info.Arguments, StringComparer.OrdinalIgnoreCase);
|
|
EventBus.TriggerEvent(new ShrinkCommandExecutedEvent
|
|
{
|
|
ServiceName = registration.ServiceName,
|
|
RawInput = info.RawInput,
|
|
CommandPath = commandPath,
|
|
SourceId = info.Source.SourceId,
|
|
SourceDisplayName = info.Source.DisplayName,
|
|
Arguments = arguments,
|
|
IsSuccess = info.Result.IsSuccess,
|
|
Message = info.Result.Message
|
|
});
|
|
|
|
if (info.Result.IsSuccess)
|
|
return;
|
|
|
|
EventBus.TriggerEvent(new ShrinkCommandFailedEvent
|
|
{
|
|
ServiceName = registration.ServiceName,
|
|
RawInput = info.RawInput,
|
|
CommandPath = commandPath,
|
|
SourceId = info.Source.SourceId,
|
|
SourceDisplayName = info.Source.DisplayName,
|
|
Arguments = arguments,
|
|
ErrorMessage = info.Result.Message
|
|
});
|
|
}
|
|
|
|
private static string NormalizeServiceName(string? serviceName)
|
|
{
|
|
return string.IsNullOrWhiteSpace(serviceName) ? ShrinkCommandConstants.DefaultServiceName : serviceName.Trim();
|
|
}
|
|
}
|
|
}
|