using System.Text.Json; using Microsoft.Extensions.Hosting; using WxAgent.Core; namespace WxAgent.Service; public interface IAgentEventSource { IAsyncEnumerable ListenAsync(CancellationToken cancellationToken); } public sealed class EventPump(IAgentBackend backend, EventHub hub, ServiceOptions options, RemoteEventQueue? remoteQueue = null) : BackgroundService { protected override async Task ExecuteAsync(CancellationToken stoppingToken) { if (backend is not IAgentEventSource source || backend.Capabilities.All(c => c.Operation != "listener-events" || !c.Enabled)) return; while (!stoppingToken.IsCancellationRequested) { try { await foreach (var item in source.ListenAsync(stoppingToken)) { var runtime = await LoadRuntimeConfigurationAsync(options, stoppingToken); if (remoteQueue is not null && runtime.Remote.IsConfigured && item.Kind == "message" && item.ChatId is { Length: > 0 } chatId && item.ChatType is { } chatType) { _ = remoteQueue.Enqueue(runtime.Reporting, runtime.Remote.NodeId!, item.AccountId, chatId, chatType, item.Kind, item.At, item.Content); } var localItem = item with { Content = null }; foreach (var credential in options.ReadCredentials()) if (credential.AccountIds.Length == 0 || credential.AccountIds.Contains(item.AccountId, StringComparer.Ordinal)) hub.Publish(credential.PrincipalId, localItem); } } catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested) { return; } catch (Exception) { await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken); } } } private static async Task LoadRuntimeConfigurationAsync(ServiceOptions options, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(options.RemoteConfigurationFile)) return new RemoteNodeConfiguration { Remote = options.Remote ?? new RemoteAgentOptions(), Reporting = options.Reporting }; try { return await RemoteNodeConfigurationStore.LoadAsync(options.RemoteConfigurationFile, cancellationToken); } catch (Exception exception) when (exception is IOException or JsonException or WxAgentException) { return new RemoteNodeConfiguration(); } } }