feat: add remote control plane and whitelist reads
Build web service image / build (push) Successful in 1m53s

This commit is contained in:
2026-09-12 09:46:05 +08:00
parent c86ba9c4d7
commit 13c31fc902
53 changed files with 9878 additions and 43 deletions
+15 -2
View File
@@ -6,7 +6,7 @@ namespace WxAgent.Host;
public sealed class WindowsAgentBackend(AccountBindingStore bindings) : IAgentBackend, IAgentEventSource
{
private const bool ListenerEventsEnabled = false;
private const bool ListenerEventsEnabled = true;
private readonly SemaphoreSlim bindingGate = new(1, 1);
public IReadOnlyList<AgentCapability> Capabilities { get; } =
@@ -48,6 +48,13 @@ public sealed class WindowsAgentBackend(AccountBindingStore bindings) : IAgentBa
var current = await WechatChatClient.GetMyInfoAsync(cancellationToken);
if (!BindingMatches(binding, current))
throw new ServiceException("AccountBindingStale", 409, "The listener binding is stale; bind the account again.");
var sessions = (await WechatChatClient.ListVisibleSessionsAsync(cancellationToken))
.Where(session => string.Equals(session.Name, WechatLocators.FileTransferAssistant, StringComparison.Ordinal)
&& !string.IsNullOrWhiteSpace(session.AutomationId))
.ToArray();
if (sessions.Length != 1)
throw new ServiceException("ChatIdentityUnconfirmed", 409, "The listener chat identity could not be uniquely confirmed.");
var chatId = sessions[0].AutomationId;
var accountTag = Convert.ToHexString(System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(binding.AccountId)))[..16].ToLowerInvariant();
var checkpoint = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "WxAgent", $"listener-{accountTag}.json");
while (!cancellationToken.IsCancellationRequested)
@@ -55,8 +62,13 @@ public sealed class WindowsAgentBackend(AccountBindingStore bindings) : IAgentBa
await foreach (var item in WechatChatClient.ListenEventsAsync(TimeSpan.FromMinutes(5), checkpoint, cancellationToken,
session: WechatLocators.FileTransferAssistant))
{
var observedIdentity = await WechatChatClient.GetMyInfoAsync(cancellationToken);
if (!BindingMatches(binding, observedIdentity))
throw new ServiceException("AccountBindingStale", 409, "The listener binding changed; reporting is paused until the account is rebound.");
var eventType = item.Kind == MessageEventKind.MessageReceived ? "message" : "listener.reconnected";
yield return new AgentEvent(item.EventId, binding.AccountId, item.Session,
item.Kind.ToString(), item.Message is null ? "listener state" : item.Message.Type.ToString(), item.ObservedAt);
eventType, item.Message is null ? "listener state" : item.Message.Type.ToString(), item.ObservedAt,
chatId, ReportingChatType.Private, item.Message?.Text);
}
}
}
@@ -446,6 +458,7 @@ public sealed class WindowsAgentBackend(AccountBindingStore bindings) : IAgentBa
serviceOnline = true,
wechatAvailable = report.Errors.Count == 0,
sessionAvailable = report.UserInteractive && report.InputDesktopAvailable,
sessionLocked = report.Errors.Contains(WxAgentErrorCode.SessionLocked),
report.WindowFound,
errors = report.Errors.Select(e => e.ToString()),
wechatVersions = report.Processes.Select(p => p.Version).Where(v => v is not null).Distinct(),