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
+19 -5
View File
@@ -1,23 +1,35 @@
using System.Collections.Concurrent;
using System.Text.Json.Serialization;
using System.Threading.Channels;
using WxAgent.Core;
namespace WxAgent.Service;
public sealed record AgentEvent(string EventId, string AccountId, string? Session, string Kind, string Summary, DateTimeOffset At);
public sealed record AgentEvent(
string EventId,
string AccountId,
string? Session,
string Kind,
string Summary,
DateTimeOffset At,
[property: JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] string? ChatId = null,
[property: JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] ReportingChatType? ChatType = null,
[property: JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] string? Content = null);
public sealed class EventHub
{
private readonly ConcurrentDictionary<string, Subscription> subscriptions = new();
private readonly object gate = new();
private readonly Queue<AgentEvent> history = new();
private readonly Queue<HistoryEntry> history = new();
private const int MaxHistory = 200;
public (string SubscriptionId, IReadOnlyList<AgentEvent> Replay, bool Gap) Subscribe(string principal, string? after)
{
lock (gate)
{
var replay = after is null ? [] : history.SkipWhile(e => e.EventId != after).Skip(1).ToArray();
var gap = after is not null && !history.Any(e => e.EventId == after);
var scopedHistory = history.Where(entry => entry.Principal == principal).Select(entry => entry.Event).ToArray();
var replay = after is null ? [] : scopedHistory.SkipWhile(e => e.EventId != after).Skip(1).ToArray();
var gap = after is not null && !scopedHistory.Any(e => e.EventId == after);
var id = Convert.ToHexString(System.Security.Cryptography.RandomNumberGenerator.GetBytes(16));
subscriptions[id] = new Subscription(principal);
return (id, replay, gap);
@@ -28,7 +40,7 @@ public sealed class EventHub
{
lock (gate)
{
history.Enqueue(value);
history.Enqueue(new HistoryEntry(principal, value));
while (history.Count > MaxHistory) history.Dequeue();
foreach (var subscription in subscriptions.Values.Where(s => s.Principal == principal))
{
@@ -47,6 +59,8 @@ public sealed class EventHub
public void Remove(string id) => subscriptions.TryRemove(id, out _);
private sealed record HistoryEntry(string Principal, AgentEvent Event);
public sealed class Subscription(string principal)
{
public string Principal { get; } = principal;