后端音视频即时通讯AI Agent【免费下载链接】livekitEnd-to-end realtime stack for connecting humans and AI项目地址https://gitcode.com/GitHub_Trending/li/livekit点击查看免费下载本文以 LiveKit 仓库中的cmd/test-server为对象剖析这套专为服务端 SDKGo、Rust、Python、Node、Kotlin、Ruby打造的无状态、按请求可编程的 LiveKit HTTP API Mock。读完本文你将掌握如何启动多区域 Mock 服务器、如何用X-Lk-Mock控制头精确注入区域故障、延迟与自定义响应如何通过 token 中的lk.mock属性模拟 WebSocket 信号连接的各类异常模式以及该 Mock 如何充当权限一致性校验器。文中所有结论均有仓库源码佐证可直接对照 cmd/test-server/README.md 与实现代码深入阅读。一、设计动机为什么需要一套共享的 Mock 服务器LiveKit 官方维护着 Go、Rust、Python、Node、Kotlin、Ruby 等多套服务端 SDK。每套 SDK 都需要验证客户端侧行为——例如区域容灾region failover、请求超时、错误分类等。与其让每套 SDK 各自造一套桩stub不如在 LiveKit 主仓库中维护一份共享实现它被打包为 Docker 镜像由各 SDK 的 CI 启动所有 SDK 对着同一套 Mock 行为做一致性验证。从实现上看它就是一个标准的 Go HTTP 服务入口见 main.go路由分发逻辑在 main.go 的ServeHTTP中完成/settings/regions→ 区域发现接口/rtc、/rtc/v1及其/validate变体 → WebSocket 信号连接模拟{twirp-prefix}/...→ 全部 Twirp API 方法RoomService、Egress、Ingress、SIP、Connector/与/_test/health→ 返回ok的健康检查。无状态设计一切由请求头驱动Mock 服务器的核心原则是无状态服务端不保存任何可变状态所有行为都通过单个X-Lk-Mock请求头一个 JSON 对象按请求选择。因此各测试可以完全并行运行互不干扰。这个头由 SDK 在初始请求、/settings/regions获取以及每一次容灾重试上原样转发SDK 必须把客户端配置的自定义头转发到所有这些请求上。省略该头或省略其中某个字段即表示正常行为。多端口 多区域进程为每个模拟区域绑定一个监听端口--ports。端口在列表中的位置就是它的区域索引region index索引0是主区域SDK 初始指向的区域其余是后备区域。GET /settings/regions会按顺序通告全部区域。见 main.go每个区域被构造成region-{i}、URL 为{advertiseHost}:{port}、距离Distance为i的RegionInfo。一个控制头驱动所有尝试SDK 在初始请求和每次容灾重试上发送同一个控制头而每个监听器根据自己的索引决定行为。因此单个X-Lk-Mock: {failRegions:[0]}就能让主区域失败、第一个后备区域成功——完全无需协调。贴近真实的延迟真实服务器中会阻塞的方法在 Mock 里同样阻塞见 handlers.go 的methodLatencyCreateSIPParticipant设置了wait_until_answered→ 阻塞约11 秒sipAnswerLatencyTransferSIPParticipant→ 始终阻塞约11 秒等待 REFER 完成。这样 SDK 就能用自己的超时机制去处理这些长时间调用。测试时可用delayMs覆盖这种自然延迟。全 API 可返回填充好的响应每个 RoomService、Egress、Ingress、SIP、Connector 方法都会返回类型正确、字段填充完整的响应。填充规则见 handlers.go 的populateMessage回显与请求同名的标量字段如name、metadata、identity、room、各类 timeout从请求回显到响应占位符id/sid类字段得到确定性占位值如MOCK_SID列表list 端点返回一个元素嵌套深度受控。同时支持 protobuf 与 JSON 两种 Twirp 客户端响应 Content-Type 跟随请求。客户端可用response字段完全覆盖返回内容见下文。未注册/未来的方法回退到空全默认值消息依然能被任何 Twirp 客户端正常解码见writeAPIResponse中的!known分支。二、启动与运行命令行、Docker 与全部配置项README 给出了两种启动方式均从仓库根目录执行go run ./cmd/test-server # 主区域 :9999后备区域 :10000-10002 go run ./cmd/test-server --ports 9999,10000 # 主区域 一个后备区域 # Docker docker build -f cmd/test-server/Dockerfile -t livekit/test-server . docker run -p 9999-10002:9999-10002 livekit/test-serverDocker 镜像由 cmd/test-server/Dockerfile 构建多阶段构建golang:1.26.7-alpine3.24编译、alpine:3.24.1运行固定镜像摘要保证可复现EXPOSE 9999 10000 10001 10002暴露 1 个主区域加 3 个后备区域。仓库的 magefile.go 也提供了一个mage任务等价于前台运行go run ./cmd/test-server。启动参数与默认值Flag环境变量默认值含义--portsLK_TEST_SERVER_PORTS9999,10000,10001,10002监听端口列表索引 区域编号--advertise-hostLK_TEST_SERVER_ADVERTISE_HOSThttp://127.0.0.1/settings/regions中通告的基础 URL--bindLK_TEST_SERVER_BIND0.0.0.0绑定地址--twirp-prefixLK_TEST_SERVER_TWIRP_PREFIX/twirpTwirp 路径前缀--api-secretLK_TEST_SERVER_API_SECRETsecret校验请求 token 的 API 密钥与livekit-server --dev的密钥一致参数解析实现在 main.go 与flagValue函数main.go优先级为命令行 flag 环境变量 默认值。parsePorts要求至少一个端口main.go。启动后每个监听器打印test-server: region-{i} listening on {bind}:{port} (advertised as {advertiseHost}:{port})。进程收到SIGINT/SIGTERM时优雅退出。三、控制协议X-Lk-Mock头的完整字段所有行为都由单个X-Lk-Mock请求头驱动其值是一个 JSON 对象。SDK 需要在 API 调用、/settings/regions获取和每次容灾重试上都发送该头。省略头或任一字段即正常行为。每个字段都可选字段默认值效果failRegions—本次请求失败的区域索引数组如[0]或[0,1]。每个监听器仅当自己的索引被列出时才失败failModestatus失败区域的失败方式status写一个 Twirp 错误或drop直接关闭连接 → 传输层错误failStatus503status模式失败时的 HTTP 状态码failTwirpCode由状态推导失败响应体中的 Twirp 错误码字符串delayMs—响应前延迟毫秒成功与失败都生效。覆盖方法的自然延迟——用于超时测试也可设为 0 跳过 SIP 方法内置的 ~11 秒等待regionsStatus200覆盖GET /settings/regions的状态码response—被调用方法的响应消息JSON 对象protojson 形状完全替换填充好的默认响应可完全控制返回载荷skipAuthfalsetrue时对该请求关闭权限校验用于与权限无关的测试例如带占位 token 的容灾测试sipStatus—让 SIP 拨号方法CreateSIPParticipant/TransferSIPParticipant以 SIP 状态失败如{code:486,status:Busy Here}status可选。Twirp 错误码与sip_status_code/sip_status/error_details元数据按真实服务器完全一致地推导。可与delayMs组合模拟先振铃、后失败pinnedRegions—项目被固定到的区域名称数组即其允许区域如[region-1]对应云端的 per-projectPinnedRegions区域名不是索引。非空即表示固定生效任何名称未被列出的区域会以HTTP 451拒绝请求区域固定违规且GET /settings/regions只返回被列出的区域。SDK 应看到 451 后重新获取/settings/regions并对允许区域重试——451 不带任何区域提示其响应体是中间件的纯文本不是 Twirp 错误。客户端中该重定向逻辑始终生效、无法关闭。可用一个没有任何监听器通告的名称如[region-99]来模拟不可达的固定区域。名称是 Mock 的区域名region-0、region-1……注意与按索引寻址监听器的failRegions区分示例X-Lk-Mock: {skipAuth:true,failRegions:[0],failStatus:400}字段的源码级实现failRegions/failMode/failStatusshouldFail用slices.Contains(cfg.FailRegions, h.regionIndex)判断本监听器是否失败main.gofail在drop模式下 Hijack 连接并直接关闭status模式写出 Twirp JSON 错误main.go。failStatus→failTwirpCode的映射见twirpCodeForStatusmain.go400→invalid_argument、401→unauthenticated、403→permission_denied、404→not_found、429→resource_exhausted、≥500→unavailable、其余→internal。delayMsserveAPI中若显式给出则覆盖methodLatency的自然延迟handlers.go。pinnedRegionsserveAPI在权限校验之后、延迟之前检查——若本区域名称不在固定列表中直接failRegionPin返回 451 纯文本project not allowed in this region.handlers.go/settings/regions处理器则用pinnedRegionSettings过滤只返回被允许的区域main.go。sipStatusfailSIP构造livekit.SIPStatus并通过xtwirp.ToError生成与真实服务器一致的 Twirp 错误handlers.go。响应头Header含义X-Lk-Mock-Region响应该请求的区域索引失败区域上为空。断言此头可确认容灾最终落在哪个区域已废弃的旧版逐项头以下旧的逐项控制头仍为既有客户端保留将来会被移除X-Lk-Mock-Fail-Regions、X-Lk-Mock-Fail-Mode含delay模式、X-Lk-Mock-Fail-Status、X-Lk-Mock-Fail-Twirp-Code、X-Lk-Mock-Delay-Ms、X-Lk-Mock-Regions-Status、X-Lk-Mock-Response、X-Lk-Mock-Skip-Auth。当X-Lk-Mock同时存在时其字段逐字段优先见 config.go 的parseMockConfig先解析旧头作为基底再叠加 JSON 头。新客户端应只用X-Lk-Mock。四、信号连接WebSocket模拟Mock 还实现了足够多的 LiveKit 信号协议让 SDK 能跑端到端的信号连接测试连接、keepalive、重连、离开以及客户端必须分类的失败/超时模式。关键点信号行为通过访问令牌中的参与者属性lk.mock选择——因为 WebSocket 客户端无法设置请求头也就无法携带控制头。改由 token 选择意味着并行测试无需共享状态。端点路径用途/rtc、/rtc/v1WebSocket 信号连接两种协议版本均支持且行为一致/rtc/validate、/rtc/v1/validateHTTP validateWS 打开失败时客户端会请求它认证与协议细节token 从access_token查询参数或BearerAuthorization 头读取并用 API secret 校验。缺失/格式错误/过期/签名错误的 token 会使validate返回401WS 也拒绝升级见 signal.go。线上格式为二进制 protobufSignalRequest进、SignalResponse出。v1 内嵌的 publisher offerjoin_request连接参数被忽略——不要求有效 offer。keepalive 使用较短的pingTimeout3s/pingInterval1sjoin 中携带signal.go让超时测试快速完成。模式选择lk.mock参与者属性token 校验通过后服务器读取 token 的attributes声明ClaimGrants.Attributesmap[string]string中的lk.mock条目。该属性的值是一个字符串化的 JSON 控制对象其signal字段选择行为。lk.mock命名空间是属性的键点分记法符合 LiveKit 内部属性的惯例值内部没有父级嵌套attribute key: lk.mock attribute value: {signal:no_pong}控制对象还接受一个可选字段leaveAction——一个LeaveRequest_Action既可用数字0DISCONNECT、1RESUME、2RECONNECT也可用枚举名RECONNECT大小写不敏感给出——它设置发送离开的模式leave_when_connected、leave_first_message、leave_during_reconnect所发出的LeaveRequest的action字段。缺省时为0DISCONNECT。示例attribute value: {signal:leave_when_connected,leaveAction:RECONNECT}如果lk.mock属性缺失/为空、值无法解析、或signal未知模式默认回退到happy。WS 处理器与 validate 处理器都从同一属性读取模式。leaveAction的双格式解析实现在 signal.go先尝试按 JSON 数字解码再按枚举名字符串解码LeaveRequest_Action_value[strings.ToUpper(s)]无法识别则解码为 0DISCONNECT而不使整个控制对象解析失败。行为模式总表任何未知/缺失的signal都等同于happysignal值效果happyvalidate → 200WS 发送JoinResponse若reconnect1则发ReconnectResponse对 ping 回 pong客户端发LeaveRequest时干净关闭1000validate_500validate → 500WS 以 500 拒绝升级validate_service_not_foundvalidate → 404响应体不含房间标记客户端 → serviceNotFoundWS 以 404 拒绝room_not_foundvalidate → 404响应体为requested room does not exist客户端 → notAllowedWS 以 404 拒绝no_first_messageWS 接受连接但服务器不发送任何消息客户端触发连接超时no_pongWS 发送 join然后从不回 pong客户端触发 ping 超时close_before_joinWS 升级成功约 50ms 后在任何首条消息之前干净关闭1011空 reason——连接期间发生意外关闭close_when_connectedWS 发送 join约 200ms 后以 1011 关闭drop_when_connectedWS 发送 join约 200ms 后不做关闭握手直接粗暴断开 TCP 连接——客户端观察到异常关闭1006leave_when_connectedWS 发送 join约 200ms 后发送LeaveRequestleave_first_messageWS 把LeaveRequest作为第一条也是唯一一条消息发送leave_during_reconnect在reconnect1的连接上先发送LeaveRequest否则行为等同happy发出的LeaveRequest携带reasonSERVER_SHUTDOWNaction来自控制对象的可选leaveAction默认DISCONNECT (0)——见 signal.go。实现上还有 README 未展开的两个细节drop_on_close模式happy 路径但在客户端发起关闭握手时直接断 TCP 而非回关闭帧见 signal.go以及重连判定会同时看 URL 查询参数reconnect1和解开 v1join_request参数支持 gzip 压缩的WrappedJoinRequest中的Reconnect标志signal.go。源码佐证signal_test.go 中的模式验证signal_test.go 用httptest起单区域regionIndex: 0Mock 验证了大部分模式TestHappyJoinAndPingPongjoin 含非零 ping 配置、pingReq→pongResp回显时间戳、legacyping→pong、TestNoPong发 ping 后 500ms 内无任何消息、TestLeaveFirstMessage、TestCloseWhenConnected断言 1011、TestDropWhenConnected断言非 1000 的异常关闭、TestNoFirstMessage、TestCloseBeforeJoin首读即 close、1011、空 reason、TestLeaveDuringReconnectreconnect1时首消息即 leave、TestValidateModeshappy/validate_500/service_not_found/room_not_found/bad token/missing token 的 validate 状态码以及TestLeaveActionOverride/TestLeaveActionByName数字与枚举名两种 leaveAction 写法都解出 RECONNECT。五、权限校验Mock 兼任一致性检查每个 API 方法都要求与真实 LiveKit 服务器相同的 token 授权对应真实代码见 pkg/service/auth.go因此 Mock 同时充当SDK 是否自动附带正确权限的一致性检查。token 用协议自带的auth帮助函数解析与校验与真实服务器同一代码路径auth.go 的verifyToken使用 Mock 配置的 API secret默认secret与livekit-server --dev一致用--api-secret/LK_TEST_SERVER_API_SECRET覆盖。规则缺失、格式错误或签名错误的Authorization→401 unauthenticated。签名正确但缺少所需授权的 token →403 permission_denied。roomAdmin作用域的方法还要求 token 的room与请求的 room 匹配ForwardParticipant/MoveParticipant额外要求destinationRoom匹配。SDK 若要做权限测试应使用与 Mock 相同的 API secret默认secret签发 token。授权与方法的对应关系Grant方法video.roomCreateCreateRoom、DeleteRoom、所有Connector调用video.roomListListRoomsvideo.roomRecord所有Egress方法video.ingressAdmin所有Ingress方法video.roomAdminroomroom participant/data/metadata 方法、AgentDispatchService方法video.roomAdminroomdestinationRoomForwardParticipant、MoveParticipantsip.adminSIP trunk 与 dispatch-rule 的增删改查sip.callCreateSIPParticipantTransferSIPParticipant还需roomAdmin完整的方法→授权映射表在 auth.go 的methodPerms中逐条对齐真实服务器的Ensure*Permission检查授权判定逻辑见perm.satisfiedByauth.go。roomAdmin作用域的校验顺序是先校验room从请求的room或room_name字段读取再在destRoom场景校验destination_room。发送X-Lk-Mock: {skipAuth:true}可绕过校验用于与权限无关的测试。六、常见测试配方速查目标X-Lk-Mock值正常路径不带头— 带方法所需授权且签名正确的 token → 区域0返回 200绕过认证容灾测试{skipAuth:true}缺少权限错误不带头— 缺少所需授权的 token → 403容灾成功落在区域 1{failRegions:[0]}耗尽到区域 2{failRegions:[0,1]}全部区域宕机{failRegions:[0,1,2,3]}4xx不重试{failRegions:[0],failStatus:400}传输层错误容灾{failRegions:[0],failMode:drop}超时测试{delayMs:30000}区域发现不可达{regionsStatus:500}自定义响应载荷{response:{sid:RM_x,name:my-room}}SIP 占线信号{sipStatus:{code:486,status:Busy Here}}SIP 运营商拒接{sipStatus:{code:603}}注意SDK 的区域容灾通常只对*.livekit.cloud主机生效。由于测试指向127.0.0.1需要把 SDK 的 failover 启用选项设为强制开启值容灾才会在 localhost 上生效。七、拓展阅读控制协议与配置结构的完整源码cmd/test-server/config.goTwirp API 路由与响应填充逻辑cmd/test-server/handlers.go权限映射与 token 校验cmd/test-server/auth.goWebSocket 信号模拟cmd/test-server/signal.go信号模式的单元测试cmd/test-server/signal_test.goDocker 镜像构建cmd/test-server/Dockerfile赞分享后端音视频即时通讯AI Agent【免费下载链接】livekitEnd-to-end realtime stack for connecting humans and AI项目地址https://gitcode.com/GitHub_Trending/li/livekit点击查看免费下载相关推荐3步构建私有AI聊天平台Open WebUI实践指南3步构建私有AI聊天平台Open WebUI实践指南 在数据隐私日益重要的今天你是否在为云端AI服务的数据安全而担忧想要拥有一个完全掌控在自己手中的智能助人工智能大模型AI 应用RAGAI Agent本地部署交互助手后端前端Blender 模型精简完整指南用 Decimate 修改器把百万面压到十万面Blender 模型精简完整指南用 Decimate 修改器把百万面压到十万面 打开 Blender视图转不动FBX 导出后发给引擎侧又大又卡——十有八九文档教程LoopX Explore能力入门假设、发现与护栏如何不丢失LoopX Explore能力入门假设、发现与护栏如何不丢失 LoopX Explore 是 LoopX 长任务 Agent 控制面Control Plan人工智能AI AgentAgent 编排dsh-plugin上一篇HYG星际数据库终极指南从数据探索到天文应用完整教程下一篇Jspreadsheet CE 在 Vue.js 项目中的 Jest 单元测试完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考