feat(channel): 微信 iLink 账号状态三态(诚实口径)
state ∈ 有效 / 被拒(需重扫)/ 未知;🔴 -14 是**被拒不是过期**,且**未知原因绝不写成「过期」** (面板文案与错误码都如实)。三态判定为纯函数 + 三态各有用例。 ⚠️ 未做(如实登记):每账号逐条三态(accounts[] 数组上的三态)本片未做。
This commit is contained in:
1 parent
7505c46b70
commit
99a644d545
12 files changed
+2041
-57
No files matched your search
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/bus"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/events"
|
||||
)
|
||||
|
||||
// WebSocket 调参常量。ping/pong 节奏用于防止中间代理把空闲连接断开。
|
||||
@@ -66,12 +67,22 @@ type hub struct {
|
||||
// 解析器同源,使 WS 帧与 REST 的文档校验口径一致。为 nil 时带附件的回合
|
||||
// 被明确拒绝(见 resolveDocuments),绝不静默丢弃。
|
||||
documents documentResolver
|
||||
log *slog.Logger
|
||||
upgrader websocket.Upgrader
|
||||
origins map[string]bool
|
||||
allowAll bool
|
||||
cancel context.CancelFunc
|
||||
streamSeq atomic.Uint64
|
||||
// eventStore 是渠道事件的**写入面**(design/26 §2.6;切片 E7)。为 nil 表示
|
||||
// 这份构建没有留存面 ⇒ 渠道事件实时面整个不启动(见 startChannelEventWatch)。
|
||||
eventStore events.Store
|
||||
// accountStatus 采集各账号的在线状态快照(含未知)。它是纯函数式的取数口,
|
||||
// 由 server 提供(见 channelAccountStatusSamples),hub 只负责按节拍调用。
|
||||
accountStatus func() []events.StatusSample
|
||||
// channelWatch 是渠道事件采样循环的句柄(未接线时为 nil)。持有它有两个理由:
|
||||
// close() 之外还想让「循环到底起没起」有一个可断言的对象;测试可经
|
||||
// ObserveOnce 在**确定的一拍**上驱动迁移,而不必等 60s。
|
||||
channelWatch *events.Watcher
|
||||
log *slog.Logger
|
||||
upgrader websocket.Upgrader
|
||||
origins map[string]bool
|
||||
allowAll bool
|
||||
cancel context.CancelFunc
|
||||
streamSeq atomic.Uint64
|
||||
}
|
||||
|
||||
// newHub 构建一个绑定到 server 依赖的 hub。
|
||||
@@ -88,9 +99,13 @@ func newHub(s *Server) *hub {
|
||||
history: s.history,
|
||||
envResolver: s.envResolver,
|
||||
documents: s.resolveChatDocuments,
|
||||
log: s.log,
|
||||
origins: origins,
|
||||
allowAll: allowAll,
|
||||
// 渠道事件实时面的两个来源都在构造期取定:写入面按能力断言取(未接线时为
|
||||
// 真 nil ⇒ 循环不启动),状态快照直接引用 server 的方法。
|
||||
eventStore: s.channelEventWriter(),
|
||||
accountStatus: s.channelAccountStatusSamples,
|
||||
log: s.log,
|
||||
origins: origins,
|
||||
allowAll: allowAll,
|
||||
upgrader: websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
@@ -101,13 +116,16 @@ func newHub(s *Server) *hub {
|
||||
|
||||
// start 让 hub 订阅 bus 事件流。发往 ws.> 的事件到达此处后广播给客户端;
|
||||
// 生产者桥接模式(iot/task/automation/reminder/subagent-progress)也一并订阅,
|
||||
// 并归一为 ws.* 事件类型。未接入 bus 时什么都不做。
|
||||
// 并归一为 ws.* 事件类型。它同时启动**渠道事件实时面**(切片 E7):那一条腿
|
||||
// 只依赖写入面与状态源,没有 bus 也照常采(落行不推帧),因此不能挂在 bus 的
|
||||
// 判定之后。ctx 与订阅共用:close() 取消它,两条腿一起干净退出。
|
||||
func (h *hub) start() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
h.cancel = cancel
|
||||
h.startChannelEventWatch(ctx)
|
||||
if h.bus == nil {
|
||||
return
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
h.cancel = cancel
|
||||
patterns := append([]string{wsEventsPattern}, bridgePatterns...)
|
||||
for _, p := range patterns {
|
||||
if _, err := h.bus.Subscribe(ctx, p, h.relay); err != nil {
|
||||
@@ -116,8 +134,8 @@ func (h *hub) start() {
|
||||
}
|
||||
}
|
||||
|
||||
// close 取消 bus 订阅、中断所有 orchestrator 会话(使后台回合不会比 hub 活得
|
||||
// 更久),并关闭每条在线连接。
|
||||
// close 取消 bus 订阅与渠道事件采样循环、中断所有 orchestrator 会话(使后台回合
|
||||
// 不会比 hub 活得更久),并关闭每条在线连接。
|
||||
func (h *hub) close() {
|
||||
if h.cancel != nil {
|
||||
h.cancel()
|
||||
|
||||
Reference in new issue
Block a user