using XFEExtension.NetCore.WinUIHelper.Utilities; using XFEWorkflow.Controls; using XFEWorkflow.Core.Runtime; using XFEWorkflow.Infrastructure.Execution; using XFEWorkflow.Infrastructure.Plugins; using XFEWorkflow.Infrastructure.Space; using XFEWorkflow.Infrastructure.Storage; using XFEWorkflow.Plugins.Desktop; using XFEWorkflow.Plugins.WeCom; namespace XFEWorkflow.Services; public interface IWorkflowApplicationService { WorkflowRepository Workflows { get; } PluginManager Plugins { get; } RunCoordinator Runs { get; } } public sealed class AppServices : IWorkflowApplicationService, IAsyncDisposable { public static AppServices Current { get; } = new(); public WorkspacePaths Paths { get; } public ClientState State { get; } public CredentialVault Credentials { get; } public SecretRedactor Redactor { get; } = new(); public WorkflowRepository Workflows { get; } public PluginManager Plugins { get; } public RunCoordinator Runs { get; } public WorkflowScheduler Scheduler { get; } public SpaceClient Space { get; } public WorkflowLogService Logs { get; } public PluginPageService PluginPages { get; } public DesktopInputService Desktop { get; } = new(); public ScreenToolsService ScreenTools { get; } = new(); public CommandProcessHost Commands { get; } public WeComHostService WeCom { get; } public BrowserHost? Browser { get; private set; } public Task Ready { get; private set; } = Task.CompletedTask; private bool initialized; private AppServices() { Paths = new(Utilities.AppPath.WorkspaceDirectory); State = new(Paths); Credentials = new(State); Workflows = new(Paths); Plugins = new(Paths, State); Runs = new(Paths, Plugins, Credentials, Redactor, Path.Combine(AppContext.BaseDirectory, "Runner", "XFEWorkflow.Runner.exe")); Commands = new(Path.Combine(AppContext.BaseDirectory, "Runner", "XFEWorkflow.Runner.exe")); WeCom = new(Path.Combine(Paths.Root, "PluginData", "WeCom"), Path.Combine(AppContext.BaseDirectory, "NativeBridge", "WeCom")); WeCom.Log += message => XFEExtension.NetCore.XFEConsole.XFEConsole.Log.AddLog(Redactor.Redact(message)); Scheduler = new(Workflows, Runs); Space = new(State, Credentials); Logs = new(Paths, Runs, Redactor); PluginPages = new(this); Runs.RunChanged += Logs.Observe; Scheduler.Error += message => XFEExtension.NetCore.XFEConsole.XFEConsole.Log.AddLog(Redactor.Redact(message), XFEExtension.NetCore.XFEConsole.LogLevel.Error); Plugins.Changed += () => { if (initialized) _ = RefreshPluginTriggersAsync(); }; Desktop.Backend = State.DesktopBackend; Runs.Host = async (id, method, input, ct) => { if (method.StartsWith("browser.", StringComparison.Ordinal)) return await (Browser ?? throw new InvalidOperationException("浏览器服务尚未启动")).InvokeAsync(id, method, input, ct); if (method == "desktop.input") return await Desktop.ExecuteAsync(id, input, ct); if (method.StartsWith("screen.", StringComparison.Ordinal)) return await ScreenTools.InvokeAsync(method, input, ct); if (method == "command.run") return await Commands.ExecuteAsync(id, input, ct); if (method.StartsWith("wecom.", StringComparison.Ordinal)) return await WeCom.InvokeAsync(id, method, input, ct); throw new NotSupportedException(method); }; Runs.ReleaseHost = async id => { await Desktop.ReleaseAsync(id); await Commands.ReleaseAsync(id); await WeCom.ReleaseAsync(id); if (Browser is not null) await Browser.ReleaseAsync(id); }; ServiceManager.RegisterService(() => this); } public void Start(BrowserHost browser) { Browser = browser; browser.Paths = Paths; Ready = InitializeAsync(); } private async Task InitializeAsync() { await Plugins.ImportBundledAsync(Path.Combine(AppContext.BaseDirectory, "BundledPlugins")); await Runs.InitializeAsync(); foreach (var reference in Credentials.References) { try { Redactor.Add(Credentials.Get(reference)); } catch (System.Security.Cryptography.CryptographicException) { } } if ((await Workflows.ListAsync()).Count == 0) await Workflows.SaveAsync(WorkflowTemplates.Welcome()); await Scheduler.StartAsync(); initialized = true; } private async Task RefreshPluginTriggersAsync() { try { await Scheduler.RefreshAsync(); } catch (OperationCanceledException) { } catch (Exception ex) { XFEExtension.NetCore.XFEConsole.XFEConsole.Log.AddLog(Redactor.Redact(ex.Message), XFEExtension.NetCore.XFEConsole.LogLevel.Error); } } public async ValueTask DisposeAsync() { initialized = false; if (WorkflowEditorPage.Current is { } editor) await editor.SaveAllAsync(); if (MainPage.Current?.ViewModel.SelectedWorkflow is { } workflow) await Workflows.SaveAsync(workflow); await Scheduler.DisposeAsync(); ScreenTools.CancelSelection(); Desktop.EmergencyStop(); await Runs.DisposeAsync(); await PluginPages.DisposeAsync(); await Commands.DisposeAsync(); await WeCom.DisposeAsync(); if (Browser is not null) await Browser.DisposeAsync(); Desktop.Dispose(); await State.DisposeAsync(); } }