Skip to content

Chirp 能力矩阵(Capability Matrix) ​

最后核对:2026-09-27

二进制命名约定:chirp_<plane>_<service>。游戏平面:chirp_game_sdk_gateway、chirp_game_server_gateway、chirp_npc_dialog;App 平面:chirp_app_sdk_gateway、chirp_app_auth、chirp_app_notification;共享 chat 二进制为 chirp_chat / chirp_chat_distributed,由 services/shared/chat/ 一份代码产出,部署角色由启动参数(hub/spoke)区分。

本文按运行目标(runtime target)描述仓库的当前实现状态,而不是按路线图愿景。

状态图例 ​

  • Supported:纳入默认文档化后端主干,必须保持可构建
  • Experimental:实现了一部分,或在替代目标 / 特定环境依赖之后
  • Demo:主要用于展示或本地探索,不是可靠的后端契约
  • Stub:占位、mock 驱动,或明显未完成

后端服务 ​

领域运行目标状态说明
游戏边缘登录/会话路由chirp_game_sdk_gateway(services/game/sdk_gateway/)SupportedTCP 5000 / WS 5001,游戏客户端边缘:登录、心跳、踢线流程的主入口;跨实例踢线按平台作用域(同用户+同 platform 顶替,跨 platform 共存,见「多端在线」行)。设置 --chat_host 后,会把聊天业务包(2xxx)经一条每客户端内部连接转发给 chat(SERVER_AUTH_REQ 信任门 + 登录重放,双向原样中继;管道断开则踢掉客户端使其重连)
App 平面认证基础 token 流程chirp_app_auth(services/app/auth/)Supported默认二进制可用;没有 MySQL/libsodium 时回退到更简单的 token 校验路径。增强模式把 LOGIN_REQ 的 token 按 HS256 JWT 校验(--jwt_secret,校验 exp);scaffold 回退藏在 --allow_scaffold_login(默认关)后面,部署上约定该密钥与边缘服务的 --token_secret 对齐。只服务 App 平面,游戏平面由游戏后端自签 JWT + chirp_chat --token_secret 本地验证,不依赖此服务
聊天基础消息chirp_chat(services/shared/chat/)Supported同一二进制按需部署为 game_chat 或 app_chat。私聊、历史、离线队列、群管理(建群/入群/退群/踢人/邀请/成员列表)、已读回执、正在输入提示、消息回应、消息编辑/删除(含管理员与批量删除)、消息撤回(发送者本人可撤回:默认私聊/公会 2 分钟窗口,--recall_window_sec / --recall_channels 可调,超窗/非撤回频道/重复撤回回 INVALID_PARAM,版主删除不受窗口约束;撤回经 MESSAGE_DELETED_NOTIFY 广播墓碑并回收接收方离线队列副本,历史存档双 tier 同步立碑——置位 is_recalled 并抹除正文,重拉历史只剩"被撤回过"的事实;basic 与 enhanced 两种部署形态都接了 DELETE_MESSAGE 入口(2026-09-27),enhanced 的成员解析只覆盖私聊(公会撤回的 notify/离线回收随群聊扇出订阅端落地生效)、无角色体系故 is_hard_delete 恒拒 AUTH_FAILED)、@提及解析与自动补全、敏感词过滤(--word_filter_file 词库 + `--word_filter_policy replace
多端在线(同型顶号 + 在线端清单)libs/network(session_registry + device_presence,接入双 sdk_gateway 与 chat/party/social)Supported2026-09-27 起会话槽位键为 (user_id, platform):同 platform 新登录顶掉旧会话(KICK_NOTIFY reason "logged in on another <platform>",legacy 空 platform 回退 "device" 文案),跨 platform 共存互不干扰;同 device_id 断线重连幂等重绑(同 device 必然同 platform);device_id 降为每会话元数据。空 platform 归一 "default",不上报 platform 的 legacy 客户端保持每用户一会话的旧行为。web 多标签同型互顶是该语义的直接后果,不另开特例(浏览器无稳定设备身份)。登录响应带 online_devices 初始清单(LoginResponse.online_devices,排除会话自身);登录/断开/被顶向该用户其余在线会话广播 DEVICES_PRESENCE_NOTIFY(1020,sequence 0,payload [{platform, device_id, online, ts}]);断开广播只在确认释放槽位时发——被顶旧会话迟到断开不产生假 offline。广播是 registry 本地的:多节点部署下其他实例听不到,与既有本地 notify 同边界。Redis 跨实例 claim 同步迁 platform 键(chirp:sess:<user>\x1F<platform>);voice 平面刻意不动(设计即每用户一会话);party/social 只切顶号键、不广播设备清单(设备清单属于客户端接入面)。SDK 三层可收:Go SetDevicePresenceHandler、TS @chirp/protocol(onDevicesPresence/onLoginDevices)、原生 Android/iOS ChatEventListener 同两 hook;web(侧栏 Dialog 带在线计数)带最小 UI,Flutter mobile 曾带「我的」页清单(2026-09-29 随原生迁移移除)。测试:session_registry_tests 24 例重写、chat_enhanced_session_tests 跨型共存/上下线 announce、party/social/app/game 网关套件同步、Go dispatch、web store+组件、mobile store+api+widget
聊天分布式路由chirp_chat_distributedExperimental独立目标,不是默认文档化的服务二进制
聊天 Redis + MySQL 混合存储chirp_chat / chirp_chat_enhancedExperimentalMySQL 可用时,默认 chirp_chat 目标直接构建增强实现;chirp_chat_enhanced 是 chirp_chat 的兼容别名(CMake ALIAS)
App 认证注册 / 刷新 / 防爆破 / 限流栈chirp_app_auth / chirp_app_auth_enhancedExperimentalMySQL 和 libsodium 可用时,默认 chirp_app_auth 目标直接构建增强实现;chirp_app_auth_enhanced 是 chirp_app_auth 的兼容别名(CMake ALIAS)。LOGIN_REQ 接受有效访问 token(HS256 JWT)或活跃会话;scaffold 登录需要 --allow_scaffold_login 1
游戏后端注入枢纽chirp_game_server_gateway(services/game/server_gateway/)Experimental服务认证(service_id + secret)、面向 chat 的消息注入(inject)路由、可靠事件投递(每服务队列、ack、重连重投);chat 把注入当内部 peer 消费;上游注入也可走 Redis Stream(--broker_redis_host,消费者组 + XAUTOCLAIM 重放,需要 Redis >= 6.2;下行事件仍只走长连接)。玩家身份绑定(WP-8 切片 1):游戏后端经 5013-5020 RPC 绑定平台 player_id <-> (game_id, game_user_id)(绑定带 binding_id 幂等键,按 id 或键对解绑,按玩家列举,按游戏用户反查);内存注册表 + 直写 Redis 镜像(--binding_redis_host,尽力而为,降级为纯内存)——见 docs/server_plane.md 的"玩家身份绑定"。玩家频道订阅(WP-8 切片 2):5021-5026 RPC 在 SubscriptionRegistry 里登记 玩家 -> (game_id, channel) 意图(三元组唯一,自服务路径由服务端铸造 subscription_id 幂等键,按 id 或完整三元组解绑,列举可按 game 过滤;同样是直写 Redis 形态,--subscription_redis_host)。扇入投递(WP-8 切片 3):带 game_id + 非 PRIVATE 频道的注入,对每个 (game_id, channel_id) 订阅者按玩家各发一份 SENDER_SERVICE 私聊副本,走 chat 正常投递尾段(chat 侧零改动);无订阅者静默回 OK,部分失败回 OK,全失败回 SERVER_UNAVAILABLE(可安全重放),超过 --max_fanout(默认 10000)回 RATE_LIMITED;流式 broker 共用同一套语义,见 docs/server_plane.md 的"玩家频道订阅"。统一未读(WP-8 切片 4):UnreadLedger 按(玩家, 游戏, 频道)给每份成功投递的扇入副本计红点(独立于 chat 已读游标;退订不清零),经 MARK_CHANNELS_READ(5027,分层选择器——单频道 / 单游戏 / 全部,幂等)与 GET_UNREAD_SUMMARY(5029,按(游戏, 频道)稳定排序 + 过滤后总数)读写;同样是直写 Redis 形态(--unread_redis_host,已清空条目直接删除,不会复活);见 docs/server_plane.md 的"统一未读"
NPC 对话(关键词规则引擎)chirp_npc_dialogExperimental纯 server plane 客户端(无玩家侧监听):chat 把 npc: 前缀的私聊转成 npc.player_message 事件,服务按关键词表回话,以 SENDER_NPC 注回(至少一次;hub 重投可能造成回复重复)。进程级冒烟:./test_services.sh --smoke-npc
离线消息推送触发chirp_chat(默认 + distributed 构建)Experimental离线私聊/群聊消息与 server plane 注入会经 PushBridge 入队推送 -> notification(发完即忘,失败记日志)。已接入默认构建与 chirp_chat_distributed(后者只在无实例投递成功时才存离线,依据 router 的 PUBLISH 接收方计数);main_enhanced(MySQL 构建)尚未接线,等一个能编译增强分支的构建环境
社交 / 在线状态services/socialExperimental服务代码在,但未作为核心路径验证。2026-09-27 起订阅 Redis pub/sub chirp:game_presence:events,好友 EffectivePresence 叠加游戏在线:游戏叠加非空 → IN_GAME(status_message=逗号连接 game_ids,metadata[game_id]="1"),叠加活过 social 登出、SET_PRESENCE AWAY 不覆盖;断线(游戏断言失效)向好友补发 offline。事件消费走 ConsumeGamePresenceEvent(channel 过滤+畸形忽略),social_tests 37 例
游戏在线状态 + 好友消息进游戏chirp::chat::PlayerDirectory + GamePresence(services/shared/chat/src/game_presence.*),自服务开关经 chirp_app_sdk_gatewayExperimental2026-09-27 起身份绑定即"在游戏内"断言,绑定即默认开启上报(可关,见 App 边缘行):GamePresence 只存显式关闭的覆盖行(Redis 键 chirp:game_presence:setting:<player_id>,缺行=开启);绑定增删触发 RefreshPresence 重算 desired=开启?排序绑定 game_ids:空,与 roster 键 chirp:game_presence:online:<player_id>(换行连接,空则 DEL)比对,翻转才发布 GamePresenceEvent{player_id, game_id, online} 到 pub/sub chirp:game_presence:events。Redis 是传输介质不是权威:进程重启从身份绑定全量重建(LoadAll 先恢复开关再服务);关闭态完全静默(无事件无 roster,回归用例锁定);game 断言随 spoke 断开/超时失效自然下线,无独立心跳。好友私聊镜像:RelayFriendMessage best-effort——接收方开启且有绑定时每绑定注入一份 PEER_INJECT_MESSAGE_NOTIFY(channel_id=接收方该游戏 game_user_id,sender_id=chirp 好友 user_id),常规端照常收,spoke 不在线/注入失败逐项跳过不回码,聊天主链路零影响。详见 server_plane.md「游戏在线状态与好友消息进游戏」
语音信令 / WebRTC 集成services/voice, sdks/core/modules/voiceExperimental信令面完整(61 个单测,TSan 干净):定向 SDP offer/answer/candidate 中继、LOGIN 认证门(--token_secret;默认 scaffold 自报)、join 响应携带 coturn REST 短期凭证、静音/闭麦及其派生参与者状态、空闲连接清扫。进程级验证:--smoke-voice(真实 chirp_voice 上跑建房→加入→名单→静音→心跳→离开全生命周期,chirp_voice_smoke_client,CI smoke job 内)。web 伴侣已接协议面(第五条 websocket 9001):msg_map.ts 7 对 voice spec、voice_api/voice_store/VoiceDialog 最小闭环(建房/按 ID 加入/名单与状态标签/自静音拒听/离开 + JOINED/LEFT/STATE_CHANGED 三 notify,广播排除操作者故自旗标本地回显),vitest 单测 + web_smoke.sh voice e2e(双客户端跨会话 notify 验证)。媒体面边界:SDP/ICE/SPEAKING 中继(4007-4009/4021)服务端存在,web 客户端不订阅不驱动音频;还没有真实浏览器/媒体 E2E,WebRTC 媒体面端到端仍未验证
组队信令(跨游戏组队)services/partyExperimental信令面完整(46 个单测,TSan 干净):邀请-接受入队(无加入码,重复邀请幂等)、就绪检查、离队/掉线自动继任队长、最后一人退出静默解散、踢人/转让队长带快照扇出(PARTY_STATE_CHANGED 到达包括操作者在内的每个成员)。组队快照直写 Redis(邀请仅存内存,10 分钟惰性过期);最后一台设备断线不解散队伍。玩家面身份与游戏侧语音房间解耦;单实例,无跨实例扇出;web 伴侣端已带组队 UI(快照驱动的第三条 websocket),引擎客户端随阶段 3 落地。进程级验证:--smoke-party(真实 chirp_party 上跑建队→快照→离线目标邀请→离队,chirp_party_smoke_client,CI smoke job 内)
App 通知投递chirp_app_notification(services/app/notification/)Experimental协议面已在 TCP 5006 / WS 5016 上线(6xxx 设备与推送消息,单测覆盖 100%);进程内设备注册表、按用户冷却与载荷构建都是真实现。--push_transport http 打开真实 HTTP/1.1 provider POST 客户端(HttpPushTransport,连接工厂留有可注入接缝,deadline/大小上限):https 端点走 SslHttpConnectionFactory(TLS 1.2+ 证书校验 + 主机名 SNI,--push_ca_file 指私有 CA,--push_verify_tls off 仅供调试),http 端点回落明文 TCP;端点可配(--fcm-endpoint/--apns-endpoint,--apns-sandbox 切沙箱主机);无 token 设备显式记失败。已回环测试(可信 CA/错误 CA/握手超时/跨 record 大响应)。APNs 要求 HTTP/2,生产部署在本通道前置协议转换;默认仍是日志传输,真实凭据接入留待部署环境
App 边缘(伴侣应用)chirp_app_sdk_gateway(services/app/sdk_gateway/)ExperimentalTCP 5200 / WS 5201,外加可选 TLS/wss 监听(--tls_port/--ws_tls_port,默认关;任一开启需 --tls_cert/--tls_key,TLS 1.2+):与游戏网关一致的登录/心跳/会话绑定(平台作用域跨实例踢线,见「多端在线」行),外加 6xxx 设备消息转发到 chirp_app_notification(要求已认证会话,user_id 由服务端钉死);TLS 会话与明文走同一套注册表/认证路径。聊天管道已上线:配置 --chat_host 后,聊天业务包(2xxx)经每客户端的 ChatBridge 原样中继到 chirp_chat(--chat_service_secret 必须与 chat 的 --gateway_service_secret 一致,否则每次登录都会被 5 秒握手超时踢掉;--chat_host 留空则边缘忽略 2xxx)。玩家聚合目标模型(玩家身份关联 N 个游戏,跨游戏订阅/语音/聊天扇入)记录在 architecture.md;WP-8 聚合面(身份绑定 5013-5020 / 订阅 5021-5026 / 未读 5027-5029)2026-09-22 已整体从 chirp_game_server_gateway 迁入 app_chat(chirp::chat::PlayerDirectory,扇入与未读自增随 FanoutChannelMessage 落地);游戏在线状态开关 5031-5034(SET_GAME_PRESENCE_ENABLED/GET_GAME_PRESENCE,2026-09-27)同链应答,player_id 同样钉死为登录身份(伪造不落地,测试扫描 hub 全量上行帧验证)。跨平面回复(2026-09-22):App 玩家 SEND_MESSAGE 的频道带 <game_id>:<bare> 前缀时,hub 侧 RelayGameReply 反查在线 spoke(service_id_for_game)与发送者游戏身份(ResolveGameUser)后经 PEER_INJECT_MESSAGE_NOTIFY 注入 game spoke(裸频道 ID、game_user_id 发送者,游戏侧铸消息 ID 走离线队列尾段);回码 OK/SERVER_UNAVAILABLE/INVALID_PARAM,拒绝不降级本地频道(详见 server_plane.md「跨平面回复」)。自服务链已切换(2026-09-22):--sg_host/--sg_port 现指 app_chat 的主端口、--sg_secret 用其 --gateway_service_secret,5021-5029 经长连 ServerGatewayPeer(SERVER_AUTH_REQ 过信任门)直发 hub 的 PlayerDirectory/SubscriptionRegistry/UnreadLedger RPC,响应体原样回传客户端;ForwardSubscriptionPacket 把 player_id 钉死为登录身份(客户端只能操作自己);登录对接 --auth_host 指 chirp_app_auth(scaffold 与增强形态均可);--smoke-edge 以新增的 chirp_wp8_client 端到端覆盖登录→订阅(幂等重订同 id)→未读摘要→标读→退订→列表
搜索服务services/searchExperimental代码在树里,尚未确立为已验证路径

SDK 与应用 ​

领域目标状态说明
C++ 核心 SDKsdks/coreExperimentalchirp::sdk::ChatClient:TCP 长连接协议核心(长度前缀 Packet 帧、sequence 关联请求(带响应 msg-id 校验与超时)、notify 订阅、25s 心跳(pong 回声校验 + 连续未答判死)、500ms→15s 带抖动退避重连、KICK 终态)。桌面游戏与 Unreal SDK 共用。73 例 loopback 套件进 CI,外加进程级冒烟(./test_services.sh --smoke-sdk)。从未编译过的 chirp::core 模块层已在 2026-09 评审中删除;五个钩子接口(拦截器/认证提供者/存储/监听器/命令)已接入 ChatClient
Unity SDKsdks/unityExperimental纯 C# 协议栈,2026-09 重写(旧桥从未编译过,已删):Runtime/Chirp/ 是无 Unity 依赖的协议库——长度前缀 Packet 帧(16MB 上限)、ChirpClient 状态机(25s 心跳带 pong 回声校验、抖动指数退避重连、KICK 终态、10s 请求超时、sequence 关联)和完整的 Req/Resp 规格表——外加一个把回调重放到主线程的 ChirpManager MonoBehaviour。gencode 提交在 proto/csharp(Google.Protobuf 3.27)。11 例 xunit 套件在 CI 中脱离 Unity 运行(unity-sdk.yml:钉版本 protoc 重生成 + 漂移检查 + dotnet test);Unity 集成 = 把 Runtime/ + proto/csharp/ 拷进 Assets(见 sdks/unity/README.md)
Unreal SDKsdks/unrealExperimental覆在 C++ 核心上的薄 UE 插件壳:UChirpClientSubsystem(GameInstance 子系统)用 AsyncTask 把所有原生回调编组到游戏线程,暴露 Blueprint 事件(登录结果、聊天消息、踢线、断线、原始 notify)和连接状态枚举。核心在 chirp CI 里编译;UE 层本身需要 UBT(构建契约记录在 sdks/unreal/README.md)
Go 服务端 SDKsdks/goExperimental游戏后端拨出连接 chirp_game_server_gateway 的客户端(仓库根 Go module 下的 chirp 包):service_id+secret 认证握手、服务端指定心跳节奏、sequence 关联 RPC(InjectMessage / PublishEvent / AckEvents / 玩家身份绑定 BindPlayerIdentity / UnbindPlayerIdentity / GetPlayerIdentities / ResolveGameUser / 玩家频道订阅 SubscribePlayerChannel / UnsubscribePlayerChannel / GetPlayerSubscriptions / 未读红点 MarkChannelsRead / GetUnreadSummary,context 超时,非 OK 码转类型化错误)、inject/event 通知处理器、失败挂起重连——语义与 C++ 参考 peer(libs/network/server_gateway_peer.cc)一致。多端在线:SetDevicePresenceHandler 收 DEVICES_PRESENCE_NOTIFY(1020)。游戏在线状态:SetGamePresenceEnabled / GetGamePresence(5031-5034,2026-09-27,dispatch 白名单含两 RESP,往返测试覆盖默认开启读数)。重生成的 proto/go 包(每个 proto 一个)在 CI 做漂移检查(go-sdk.yml:钉 protoc 33.4 + protoc-gen-go v1.36.12,go vet,13 例竞态开跑套件,对进程内 fake hub)
移动端(原生协议核)apps/android / apps/iosExperimental2026-09-29 Flutter 应用(apps/mobile_companion)随原生迁移移除,对应 CI 腿(mobile-build.yml)与 proto/dart gencode 同批删除。现役两包为纯协议核(Kotlin/Swift):Frame/MessageSpec/ChatConnection(长度前缀 Packet 帧、sequence 关联、心跳、指数退避重连、KICK 终态)/WordFilter/ChatPipeline(五钩子)/OfflineSendQueue/DeviceRegistrar(FCM/APNs token 缝,空 token 降级注册;Android 为构建开关 + 占位凭据,iOS 真凭据待接)。测试向量沿用 dart 原组三端对拍,Flutter 移除批次补齐 4 条缺口向量(custom msgType/状态翻转扇出/重连事件扇出/无 store 降级);门禁 make test 84 例 + gradlew testDebugUnitTest(Android)、swift test 81 例(iOS),均为本地门禁(CI 腿未接,见各 README)。壳层 UI/通知渲染/HarmonyOS 待后续批次(TODO 移动端迁移节)
Web 伴侣应用apps/web_companionExperimentalVite + React + TS strict + MUI;经四条可降级 websocket 连真实后端(chat 7001 / social 8001 / party 7501 / app_gateway 5201):登录带同型端顶号、私聊(历史/已读回执/正在输入/消息回应/编辑-删除)、完整群管理、服务端权威的好友 + 在线状态、快照驱动的组队 UI(建队/邀请/就绪/踢人/转让/离队/解散)、设备管理(经认证门控的 app_gateway 转发路径把浏览器自动注册为推送目标,带列表/注销 UI)、多端在线设备 Dialog(侧栏入口带在线计数,登录 online_devices 种子 + DEVICES_PRESENCE_NOTIFY 实时增减)、游戏在线状态开关(在线设备 Dialog 内分区,绑定默认开启,关闭即本地清空游戏清单,读写失败标 unavailable;game_presence_store/game_presence_api 与设备面共用 app_gateway socket)、桌面通知(基于实时聊天流的 Notification API;真正的 Web-Push 等后端传输层)。在 app_gateway 聚合边缘就绪前保持直连过渡拓扑;单测 + 组件套件(188 例)带真实后端冒烟脚本
管理后台apps/admin_dashboardStub用 mock 数据和演示页面,没有真实后端集成
CLI 客户端 / 基准工具apps/cli_client, tools/benchmarkDemo适合冒烟测试和手工验证

测试与交付置信度 ​

关注点当前状态状态
单元测试tests/unit 下 40 个套件;凡链接进测试二进制的后端包,行覆盖按 scripts/run_coverage.sh 都是 100%(仅限已登记的 KNOWN_UNCOVERABLE 行豁免与 KNOWN_UNCOVERABLE_ARMS 分支臂豁免——后者 2026-09-27 批次审计六文件 27 条未覆盖分支臂后落地:可达臂补真单测清零,残留的 unwind-only/不变量/竞态臂带理由与行号锚定逐条豁免并在每次报告列出;2026-09-27 批次#5 再收 hybrid_message_store 7 臂(3 行),累计豁免 22 行/75 臂,行覆盖门保持 100%)。chirp_app_sdk_gateway、chirp_voice、chirp_party 有套件(app_sdk_gateway_tests、voice_tests、party_tests),但它们的 main.cc 不在覆盖测量范围内Supported
标准本地构建经 ctest 跑测试ctest --preset dev(gcov 构建用 --preset coverage);全新树可构建并通过Supported
CI 把测试失败当硬失败ci.yml 跑 Debug + Release 构建 + ctest,外加一个 coverage job:任何包行覆盖跌破 98% 即失败Supported
进程级冒烟覆盖test_services.sh --smoke / --smoke-chat / --smoke-sdk / --smoke-npc / --smoke-edge / --smoke-jwt / --smoke-redis / --smoke-game 八条腿全部本地逐条验证且跑在 CI smoke job 里(--smoke-redis 用 docker redis 验跨实例踢线)Supported
核心服务的 Docker Compose 路径已具备Supported
路线图与默认构建产物一致是——TODO.md 是活的路线图(2026-09 重写);已完成项在 README.md 中划线Supported

推荐的对外口径 ​

对外介绍这个仓库时,当前合适的说法是:

  • 一条受支持的核心后端主干:gateway + auth + chat
  • 一个试验场:分布式聊天、更完整的认证、语音、社交、多引擎 SDK 都在这里试
  • 移动端/管理端按演示仓库对待,而不是成品套件