- 适配器只描述平台身份:qq_obv11 的 owner/admin 一律上报 RoleMember,不再上报 RoleOwner - session 层唯一判主点只认白名单(owner.yaml Accounts ∪ 每渠道 adminIds),nil 档案 fail-closed 拒绝 - 新增「每渠道管理员层」:channels.json ChannelAccount.adminIds[] → runtimeconfig.AdminIDs → OwnerProfile.SetPlatformAdmins(整体替换语义,热重载后移除的 id 立即失效) - 组合根接线:启动即播种、面板保存先灌白名单再重载适配器(cmd/cyrene/wire_channels.go + 4 条端到端单测) - 06.4.3 节流与参与度状态按会话独立计数(ConversationKey 三处统一,空会话 GC);06.4.4 未知平台主动发言保守默认 1 条/分钟
74 lines
2.8 KiB
Go
74 lines
2.8 KiB
Go
package adapter
|
||
|
||
// Role is the strongly typed identity role the channel layer assigns to a
|
||
// message sender. It is derived from channel-level actor metadata (login state,
|
||
// account binding, group membership) by the strategy engine, never from prompt
|
||
// text. This is a project red line: identity resolution must not rely on
|
||
// natural-language hints.
|
||
type Role string
|
||
|
||
const (
|
||
// RoleOwner is the bound owner/primary account. 只有渠道层的白名单判主可以赋这个角色
|
||
// (owner.yaml 账号白名单 + 每渠道 adminIds[],裁决 06.4.2):适配器**不得**从平台字段
|
||
// (如 OneBot 的 sender.role=owner)直接上报它——群主/群管理员都上报 RoleMember。
|
||
RoleOwner Role = "owner"
|
||
// RoleMember is a non-owner participant (for example a stranger in a group).
|
||
RoleMember Role = "member"
|
||
// RoleSystem is a system/synthetic sender (platform notice, bot).
|
||
RoleSystem Role = "system"
|
||
// RoleUnknown is a sender whose identity could not be determined.
|
||
RoleUnknown Role = "unknown"
|
||
)
|
||
|
||
// Valid reports whether r is one of the known roles.
|
||
func (r Role) Valid() bool {
|
||
switch r {
|
||
case RoleOwner, RoleMember, RoleSystem, RoleUnknown:
|
||
return true
|
||
default:
|
||
return false
|
||
}
|
||
}
|
||
|
||
// Actor is the strongly typed identity metadata attached to a message sender.
|
||
// The channel layer derives it from channel telemetry (login session, account
|
||
// binding, group membership) rather than from the message's free-text sender
|
||
// name. Owner detection and group isolation read this field, not prompt text.
|
||
type Actor struct {
|
||
// Role is the resolved identity role.
|
||
Role Role
|
||
// UserID is the stable platform user identifier.
|
||
UserID string
|
||
// DisplayName is the human-readable sender name, used for display only.
|
||
DisplayName string
|
||
// IsGroup is true when the actor represents a group/room conversation
|
||
// rather than a single user.
|
||
IsGroup bool
|
||
// GroupID is the group identifier, set when IsGroup is true.
|
||
GroupID string
|
||
// GroupName is the human-readable group name, used for display only.
|
||
GroupName string
|
||
}
|
||
|
||
// IsOwner reports whether the actor is the bound owner account.
|
||
func (a Actor) IsOwner() bool { return a.Role == RoleOwner }
|
||
|
||
// IsGroupChat reports whether the actor represents a group conversation.
|
||
func (a Actor) IsGroupChat() bool { return a.IsGroup }
|
||
|
||
// IsSystem reports whether the actor is a system/synthetic sender.
|
||
func (a Actor) IsSystem() bool { return a.Role == RoleSystem }
|
||
|
||
// IsUnknown reports whether the actor's role could not be determined.
|
||
func (a Actor) IsUnknown() bool { return a.Role == RoleUnknown }
|
||
|
||
// Resolve is a pure helper that infers IsGroup and the group identity from the
|
||
// GroupID when the channel layer has not set them explicitly, so adapters can
|
||
// populate a minimal Actor and still get correct group flags.
|
||
func (a Actor) Resolve() Actor {
|
||
if a.GroupID != "" {
|
||
a.IsGroup = true
|
||
}
|
||
return a
|
||
}
|