feat(channel): 微信 iLink 账号状态三态(诚实口径)
state ∈ 有效 / **被拒(需重扫)** / 未知;🔴 -14 是**被拒不是过期**,且**未知原因绝不 写成「过期」**(面板文案与错误码都如实)。三态判定为纯函数 + 三态各有用例。 ⚠️ 未做(如实登记): 三态(每账号逐条三态)本片未做。
This commit is contained in:
1 parent
f75e7a9c9b
commit
7505c46b70
8 files changed
+808
-17
No files matched your search
@@ -135,3 +135,77 @@ func (s *Server) liveAccountOnline() map[string]map[string]bool {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// sessionStatusAware 是渠道适配器暴露「**会话凭据三态**」(有效 / 被拒 / 未知)的
|
||||
// 可选能力。*weixin_ilink.Adapter 实现了它(SessionStatus)。
|
||||
//
|
||||
// 为什么需要它:rescanAware(admin_channels_rescan.go)只回答「要不要重新扫码」,于是
|
||||
// 「凭据确实被 iLink 接受过」与「有凭据、但从没被接受过」在面板上长得一模一样 —— 而
|
||||
// 后者只是**还没被否定**。三态把这两者分开,并把如实的说明(detail)一起交给面板,
|
||||
// 使面板不必自己编造措辞(编造正是「未知」被写成「过期」的来源)。
|
||||
//
|
||||
// 与 accountStatusAware 同一契约风格:核心 SDK 契约被刻意不扩展,因此没有这条状态面
|
||||
// 的适配器不受任何改动,也不会凭空多出一个字段。
|
||||
type sessionStatusAware interface {
|
||||
// SessionStatus 报告会话凭据状态。state 是闭集取值(当前为
|
||||
// "active"/"rejected"/"unknown",定义在 plugins/channels/weixin_ilink 的
|
||||
// SessionState* 常量),detail 是如实的中文说明(绝不含凭据)。
|
||||
SessionStatus() (state string, detail string)
|
||||
}
|
||||
|
||||
// asSessionStatusAware 报告已注册的渠道值是否暴露会话三态能力。与 asAccountStatusAware
|
||||
// 同一套路:注册时会把适配器包进 cmd/cyrene 的 namedAdapter —— 一个内嵌
|
||||
// adapter.PlatformAdapter 的未导出结构体 —— 它只提升接口的方法,因此具体适配器多出的
|
||||
// 能力只能通过拆开被内嵌字段才能抵达。
|
||||
func asSessionStatusAware(v any) (sessionStatusAware, bool) {
|
||||
if ss, ok := v.(sessionStatusAware); ok {
|
||||
return ss, true
|
||||
}
|
||||
inner, ok := unwrapNamedAdapter(v)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
ss, ok := inner.(sessionStatusAware)
|
||||
return ss, ok
|
||||
}
|
||||
|
||||
// sessionStatus 是一个账号的会话凭据三态快照:State ∈ {"active","rejected","unknown"}
|
||||
// (定义在 plugins/channels/weixin_ilink 的 SessionState* 常量),Detail 是如实的说明。
|
||||
type sessionStatus struct {
|
||||
State string
|
||||
Detail string
|
||||
}
|
||||
|
||||
// liveAccountAuthStates 收集每个平台各账号的**会话凭据三态**,键与
|
||||
// liveAccountConnections 相同(裸平台名 ⇒ 空账号 id)。
|
||||
//
|
||||
// 与 liveAccountOnline 的关键差别:三态里的「未知」是一个**值**("unknown"),不是
|
||||
// 缺席 —— 它必须带着「为什么还未知」一起上屏,否则面板只能写一句它自己编的话(而
|
||||
// 「未知」被编成「过期」正是本切片要根除的那句话)。缺席只留给「该账号没有这条状态面」
|
||||
// (适配器没实现 sessionStatusAware),两者不可互相冒充。
|
||||
func (s *Server) liveAccountAuthStates() map[string]map[string]sessionStatus {
|
||||
out := make(map[string]map[string]sessionStatus)
|
||||
if s.caps == nil {
|
||||
return out
|
||||
}
|
||||
for _, cap := range s.caps.List(capreg.KindChannel) {
|
||||
ch, ok := cap.Value.(sdk.Channel)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
ss, ok := asSessionStatusAware(cap.Value)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
state, detail := ss.SessionStatus()
|
||||
if state == "" {
|
||||
continue
|
||||
}
|
||||
platform, acct := splitAdapterName(ch.Name())
|
||||
if out[platform] == nil {
|
||||
out[platform] = make(map[string]sessionStatus)
|
||||
}
|
||||
out[platform][acct] = sessionStatus{State: state, Detail: detail}
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in new issue
Block a user