feat(channels): QQ 账号 get_status 主动探活(复用既有 action 通道 / 状态变化才记日志 / AccountStatus 与 WS 连通分开)
This commit is contained in:
1 parent
f44114301e
commit
a79fe9684e
6 files changed
+577
-18
No files matched your search
@@ -121,6 +121,18 @@ type Adapter struct {
|
||||
// reconnect / policy 只服务 ws+client 的首连与重连退避(见 reconnect.go)。
|
||||
reconnect reconnectState
|
||||
policy reconnectPolicy
|
||||
|
||||
// account 是**账号级**在线状态(get_status 探活所得,见 probe.go)。它与
|
||||
// connected(Cyrene 与 OneBot 实现的 WS/会话是否通)是两件事——2026-10-05
|
||||
// 事故正是把两者混为一谈:WS 通 ≠ QQ 账号在线。由 mu 保护。
|
||||
account accountStatus
|
||||
|
||||
// probeMu / probeWait 是 WS 上「action 请求 → echo 回执」的等待表;probeEvery
|
||||
// 是两次 get_status 探活之间的正常间隔(失败按 policy 退避)。见 probe.go。
|
||||
probeMu sync.Mutex
|
||||
probeWait map[string]chan *obAPIResponse
|
||||
probeEvery time.Duration
|
||||
probeTimeout time.Duration
|
||||
}
|
||||
|
||||
// Compile-time conformance with the channel contract.
|
||||
@@ -143,12 +155,15 @@ func NewAdapter(cfg Config) *Adapter {
|
||||
base = logger.New(logger.Options{})
|
||||
}
|
||||
return &Adapter{
|
||||
cfg: cfg,
|
||||
log: logger.WithSource(base, "plugins/channels/qq_obv11"),
|
||||
groups: map[string]string{},
|
||||
newConn: make(chan struct{}, 1),
|
||||
limiter: newRateLimiter(cfg.MaxProactivePerWindow, cfg.ProactiveWindow),
|
||||
policy: defaultReconnectPolicy(),
|
||||
cfg: cfg,
|
||||
log: logger.WithSource(base, "plugins/channels/qq_obv11"),
|
||||
groups: map[string]string{},
|
||||
newConn: make(chan struct{}, 1),
|
||||
limiter: newRateLimiter(cfg.MaxProactivePerWindow, cfg.ProactiveWindow),
|
||||
policy: defaultReconnectPolicy(),
|
||||
probeWait: map[string]chan *obAPIResponse{},
|
||||
probeEvery: defaultProbeInterval,
|
||||
probeTimeout: defaultProbeTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +226,10 @@ func (a *Adapter) Connect(ctx context.Context) error {
|
||||
if !httpTransport {
|
||||
go a.readLoop(a.lifeCtx)
|
||||
}
|
||||
// 账号在线探活(get_status)与连接生命周期同生共死:lifeCtx 取消即干净退出。
|
||||
if a.probeEnabled() {
|
||||
go a.runProbeLoop(a.lifeCtx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -231,6 +250,9 @@ func (a *Adapter) Disconnect(ctx context.Context) error {
|
||||
a.ln = nil
|
||||
a.srv = nil
|
||||
a.httpAPI = nil
|
||||
// 断开即丢弃账号在线状态:新会话的 known=false 由下一次探活重新确立,绝不沿用
|
||||
// 上一轮的陈旧结论(AccountStatus 的诚实口径)。
|
||||
a.account = accountStatus{}
|
||||
a.mu.Unlock()
|
||||
|
||||
if !started && cancel == nil {
|
||||
@@ -261,6 +283,10 @@ func (a *Adapter) Disconnect(ctx context.Context) error {
|
||||
|
||||
// IsConnected reports whether a live OneBot session exists. HTTP 传输没有长连接,
|
||||
// 它反映的是「适配器已就绪」(监听已绑定 / 出站客户端已装配)。
|
||||
//
|
||||
// ⚠️ 它**只**回答「Cyrene 与 OneBot 实现(适配器服务器)通不通」——WS 两端是长连接
|
||||
// 是否建立。它**不**回答「QQ 账号是否在线」:NapCat 等实现即使掉了账号,正向 WS 仍
|
||||
// 可能保持连接(2026-10-05 事故现场)。账号在线状态见 AccountStatus(get_status 探活)。
|
||||
func (a *Adapter) IsConnected() bool {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
|
||||
Reference in new issue
Block a user