本文档汇总 PMP 对外暴露的接口:
- HTTP / SSE / WebSocket — 内部 HTTP/SSE/WS 端口(默认 12347)
- 插件 API — WASM 插件的 WIT host API 参考(自动生成自
wit/phira-plugin.wit) - Capability 映射表 — 插件能力声明与 WIT 方法的映射
- OpenUDS — Unix Domain Socket 管理 API
这些端点只供可信反向代理或受控运维网络使用;生产部署不得直接把该端口开放给不可信客户端。
HTTP API 由 plugin_http 提供。
SSE(Server-Sent Events)实时事件流。连接后推送 ready 事件,随后转发所有广播事件。心跳每 15 秒。
WebSocket 实时事件流。与 SSE 相同的事件内容,通过二进制 WebSocket 连接传输。
插件通过 sse.register_stream 注册 SSE 事件流后,宿主自动创建对应路由。
连接后推送 ready 事件,事件通过对应插件的 on_api("sse:translate", ...) 翻译后推送。
插件返回 null 的事件会被跳过。event_types 为空时接收全部事件,否则宿主会先按事件类型过滤。内置房间事件名为 create_room、update_room、join_room、leave_room、new_round。插件启用或重载后新增的 SSE 端点即时生效。心跳每 15 秒。
示例:HSNPhira 插件注册了 /api/rooms/listen。
WASM 插件可在运行时通过 http.register_route 动态注册路由。路径缺少前导 / 时自动补全,重复注册同一路径会替换旧处理器;插件重载后无需重启 HTTP 服务。插件注册的路由通过 /{*path} 通配符派发。
GET /health/live:存活探针GET /health/ready:就绪探针(supervisor degraded → 503)
自动生成自
wit/phira-plugin.wit。请勿手动编辑。 重新生成:bash scripts/docgen.sh(输出到docs/api/)
| 接口 | 方法数 | 描述 |
|---|---|---|
| phira-types | 0 | 核心数据类型 |
| phira-host | 6 | 核心主机 API |
| phira-events | 0 | 事件类型定义 |
| phira-query | 8 | 用户/房间数据查询 |
| phira-room-mgmt | 8 | 房间管理操作 |
| phira-user-mgmt | 5 | 用户管理与封禁 |
| phira-messaging | 3 | 消息发送与广播 |
| phira-persistence | 6 | 持久化数据查询 |
| phira-admin | 5 | 管理员 ID 配置 |
| phira-config | 5 | 插件配置管理 |
| phira-crypto | 4 | 密码学操作 |
| phira-timer | 2 | 非实时定时器 |
| phira-tcp | 4 | TCP 网络连接 |
| phira-runtime | 3 | 运行时诊断 |
| exports(插件导出) | 5 | 插件生命周期与事件回调 |
Core data types shared between host and guest.
本接口仅定义类型,不包含可调用方法。
Host functions available to WASM plugins.
Log a message from the plugin.
参数:
level:stringmessage:string
返回值: (无)
所需 Capability: (无 — 公开 API)
Generate a UUID v4 string.
参数: (无)
返回值: string
所需 Capability: (无 — 公开 API)
Get current timestamp in milliseconds.
参数: (无)
返回值: u64
所需 Capability: (无 — 公开 API)
Call a server API method. Matches the host's ServerStateQuery interface.
参数:
method:stringargs:list<json-value>
返回值: api-result
所需 Capability: (无 — 公开 API)
Send a chat message as system (user-id 0) or as a specific user.
参数:
user-id:u32message:string
返回值: (无)
所需 Capability: send
Make an outbound HTTP request (sandboxed by WasmRuntimeConfig).
参数:
url:stringmethod:stringheaders:list<tuple<string, string>>body:list<u8>
返回值: result<http-response, string>
所需 Capability: http
Events the host sends to plugins.
本接口仅定义类型,不包含可调用方法。
User and room data query APIs available to plugins.
Get user basic info (id, name, language, monitor status).
参数:
user-id:u32
返回值: api-result
所需 Capability: state.read
Get user's extra extension data by key.
参数:
user-id:u32key:string
返回值: api-result
所需 Capability: ext
Set user's extra extension data.
参数:
user-id:u32key:stringvalue:string
返回值: api-result
所需 Capability: ext
Get room basic info (id, host, players, state, endpoint).
参数:
room-id:string
返回值: api-result
所需 Capability: state.read
Get room's extra extension data by key.
参数:
room-id:stringkey:string
返回值: api-result
所需 Capability: ext
List all active room IDs.
参数: (无)
返回值: api-result
所需 Capability: state.read
List online user IDs.
参数: (无)
返回值: api-result
所需 Capability: state.read
Check if a user is currently online.
参数:
user-id:u32
返回值: bool
所需 Capability: state.read
Room management operations.
Create an empty persistent room with optional endpoint override.
参数:
room-id:stringendpoint:option<string>
返回值: api-result
所需 Capability: room.manage
Kick a user from a room.
参数:
room-id:stringtarget-id:u32
返回值: api-result
所需 Capability: room.manage
Transfer host to another user in the room.
参数:
room-id:stringtarget-id:u32
返回值: api-result
所需 Capability: room.manage
Set room host (none = system ? host).
参数:
room-id:stringtarget-id:option<u32>
返回值: api-result
所需 Capability: room.manage
Lock or unlock a room.
参数:
room-id:stringlocked:bool
返回值: api-result
所需 Capability: room.manage
set-room-hidden
Hide or unhide a room (hidden rooms excluded from Web API).
参数:
room-id:stringhidden:bool
返回值: api-result
所需 Capability: room.manage
Close / disband a room.
参数:
room-id:string
返回值: api-result
所需 Capability: room.manage
Set room-level phira_api_endpoint override.
参数:
room-id:stringendpoint:option<string>
返回值: api-result
所需 Capability: room.manage
User management and moderation.
Kick a user from the server.
参数:
user-id:u32reason:string
返回值: api-result
所需 Capability: admin
Ban a user.
参数:
user-id:u32reason:string
返回值: api-result
所需 Capability: admin
Unban a user.
参数:
user-id:u32
返回值: api-result
所需 Capability: admin
List banned users.
参数: (无)
返回值: api-result
所需 Capability: admin
Check if a user is banned.
参数:
user-id:u32
返回值: bool
所需 Capability: admin
Messaging — send messages and broadcast.
Send a direct message to a specific user.
参数:
user-id:u32message:string
返回值: api-result
所需 Capability: send
Broadcast a message to all users in a room.
参数:
room-id:stringmessage:string
返回值: api-result
所需 Capability: send
Broadcast a message to all connected users.
参数:
message:string
返回值: api-result
所需 Capability: send
Persistence read API — incremental event/snapshot queries.
Query sequential events since a sequence number.
参数:
since-sequence:u64limit:u32kind:option<string>room-id:option<string>user-id:option<u32>
返回值: api-result
所需 Capability: state.read
Query room snapshots since a sequence number.
参数:
since-sequence:u64limit:u32
返回值: api-result
所需 Capability: state.read
Query touch batches.
参数:
since-sequence:u64limit:u32round-uuid:option<string>player-id:option<u32>
返回值: api-result
所需 Capability: state.read
Query judge batches.
参数:
since-sequence:u64limit:u32round-uuid:option<string>player-id:option<u32>
返回值: api-result
所需 Capability: state.read
Get playtime for a user.
参数:
user-id:u32
返回值: api-result
所需 Capability: state.read
Get top playtime ranking.
参数:
limit:u32
返回值: api-result
所需 Capability: state.read
Admin Phira ID configuration.
List admin Phira IDs.
参数: (无)
返回值: api-result
所需 Capability: admin
Check if a user is an admin.
参数:
user-id:u32
返回值: bool
所需 Capability: admin
Add an admin Phira ID.
参数:
user-id:u32
返回值: api-result
所需 Capability: admin
Remove an admin Phira ID.
参数:
user-id:u32
返回值: api-result
所需 Capability: admin
Set the full admin ID list.
参数:
ids:list<u32>
返回值: api-result
所需 Capability: admin
Plugin configuration (key-value, JSON, per-plugin config.json on disk).
Returns null if the key does not exist.
参数:
key-path:string
返回值: api-result
所需 Capability: config
Persisted to data/plugins/<name>/config.json.
参数:
key-path:stringvalue:string
返回值: api-result
所需 Capability: config
List all keys at the given prefix.
参数:
prefix:string
返回值: api-result
所需 Capability: config
Reload config.json from disk.
参数: (无)
返回值: api-result
所需 Capability: config
Poll for config changes since a version counter.
参数:
since-version:u64
返回值: api-result
所需 Capability: config
Non-realtime timer for plugin-internal scheduling. Cryptographic operations (host-side key management).
The private key never leaves the host process.
参数:
payload:list<u8>
返回值: result<list<u8>, string>
所需 Capability: crypto
Verify a signature against a public key.
参数:
pubkey:list<u8>payload:list<u8>signature:list<u8>
返回值: result<bool, string>
所需 Capability: crypto
SHA-256 hash of arbitrary data.
参数:
data:list<u8>
返回值: result<list<u8>, string>
所需 Capability: crypto
Get the server's node public key (for peer verification).
参数: (无)
返回值: result<list<u8>, string>
所需 Capability: (无 — 公开 API)
Set a one-shot timer. When fired, host calls on-api("timer:fired", [timer-id]).
参数:
delay-ms:u64timer-id:string
返回值: result<_, string>
所需 Capability: (无 — 公开 API)
Cancel a pending timer. No-op if timer already fired or unknown.
参数:
timer-id:string
返回值: result<_, string>
所需 Capability: (无 — 公开 API)
Plain TCP networking — connect/listen/send/close for WASM plugins.
Connect to a remote TCP endpoint. Returns a connection handle.
参数:
addr:string
返回值: result<u64, string>
所需 Capability: tcp
Start a TCP listener. Returns a listener handle.
参数:
addr:string
返回值: result<u64, string>
所需 Capability: tcp
Send raw bytes on an established connection.
参数:
handle:u64bytes:list<u8>
返回值: result<_, string>
所需 Capability: tcp
Close a connection or stop a listener by handle.
参数:
handle:u64
返回值: result<_, string>
所需 Capability: tcp
Runtime diagnostics.
Get runtime status summary (event bus, worker, registry).
参数: (无)
返回值: api-result
所需 Capability: state.read
Get EventBus stats.
参数:
limit:option<u32>
返回值: api-result
所需 Capability: state.read
Get registered command stats.
参数: (无)
返回值: api-result
所需 Capability: state.read
插件必须实现的导出函数(由主机调用)。
参数: (无)
返回值: result<_, string>
所需 Capability: (无 — 插件自身实现)
参数: (无)
返回值: plugin-info
所需 Capability: (无 — 插件自身实现)
参数: (无)
返回值: (无)
所需 Capability: (无 — 插件自身实现)
参数:
event:plugin-event
返回值: result<bool, string>
所需 Capability: (无 — 插件自身实现)
参数:
method:stringargs:list<json-value>
返回值: api-result
所需 Capability: (无 — 插件自身实现)
自动生成。每项 Capability 对应一组 WIT 方法,主机根据插件的 manifest 授予。
| Capability | 覆盖方法 | 默认可用 |
|---|---|---|
state.read |
phira-query.get-user, phira-query.get-room, phira-query.list-rooms, phira-query.list-online-users, phira-query.is-user-online, phira-persistence.query-events, phira-persistence.query-room-snapshots, phira-persistence.query-touches, phira-persistence.query-judges, phira-persistence.get-playtime, phira-persistence.top-playtime, phira-runtime.status, phira-runtime.events, phira-runtime.commands |
✅ |
send |
phira-host.send-chat, phira-messaging.send-to-user, phira-messaging.send-to-room, phira-messaging.send-to-all |
✅ |
ext |
phira-query.get-user-extra, phira-query.set-user-extra, phira-query.get-room-extra |
✅ |
config |
phira-config.get-config, phira-config.set-config, phira-config.list-config, phira-config.reload-config, phira-config.poll-config-changes |
✅ |
file.read |
(无) | ✅ |
file.write |
(无) | ✅ |
plugin.call |
(无) | ✅ |
plugin.register |
(无) | ✅ |
http |
phira-host.http-request |
❌ 需 manifest |
room.manage |
phira-room-mgmt.create-empty-room, phira-room-mgmt.kick-from-room, phira-room-mgmt.transfer-host, phira-room-mgmt.set-host, phira-room-mgmt.set-room-lock, phira-room-mgmt.set-room-hidden, phira-room-mgmt.close-room, phira-room-mgmt.set-room-phira-api-endpoint |
❌ 需 manifest |
admin |
phira-user-mgmt.kick-user, phira-user-mgmt.ban-user, phira-user-mgmt.unban-user, phira-user-mgmt.get-ban-list, phira-user-mgmt.is-banned, phira-admin.list-admin-ids, phira-admin.is-admin, phira-admin.add-admin-id, phira-admin.remove-admin-id, phira-admin.set-admin-ids |
❌ 需 manifest |
crypto |
phira-crypto.sign, phira-crypto.verify, phira-crypto.sha256 |
❌ 需 manifest |
timer |
(无) | ❌ 需 manifest |
tcp |
phira-tcp.connect, phira-tcp.listen, phira-tcp.send, phira-tcp.close |
❌ 需 manifest |
版本: 0.1 | Linux only | 不支持 Windows
PMP 通过 Unix Domain Socket 暴露全部管理能力给外部工具(PPB、Web 后端、运维脚本等)。
设计原则:
- PMP 不依赖任何消费者——没有连接时 PMP 正常运行
- 接口能力 = CLI 能做的事 + 事件订阅 + 数据流
- 不支持 Windows(UDS 是 Linux 特性)
- 消费者无关——接口不绑定 外部工具,任何外部工具都可以接入
┌─────────────────────────────────────────┐
│ PMP 现有模块 │
│ room_commands / ban_manager / CLI / ... │
└──────────┬──────────────────────┬────────┘
│ dispatch │ events
┌──────────▼──────────────────────▼────────┐
│ OpenUDS API 模块 │
│ ┌─────────┐ ┌──────────┐ ┌─────────┐ │
│ │dispatch │ │ events │ │streams │ │
│ │ 命令路由 │ │ 事件推送 │ │高频数据流│ │
│ └────┬────┘ └────┬─────┘ └────┬────┘ │
│ │ │ │ │
│ ┌────▼────────────▼─────────────▼────┐ │
│ │ Session │ │
│ │ 认证 / 帧编码 / 流控 / 订阅 │ │
│ └────────────────┬──────────────────┘ │
└───────────────────┼─────────────────────┘
│ UDS
┌───────────────────▼─────────────────────┐
│ 客户端 │
└─────────────────────────────────────────┘
- 传输: Unix Domain Socket (
tokio::net::UnixStream) - 帧格式: 长度前缀 (u32 LE) + JSON (UTF-8)
┌───────────────┬──────────────────────────────┐
│ payload_len │ payload (JSON) │
│ (4 bytes) │ (payload_len bytes) │
└───────────────┴──────────────────────────────┘
- 单帧上限: 16 MiB
- 控制流和高频数据流建议使用不同连接
外部工具 PMP
│ │
├─ Authenticate ───────────►│ { token: "xxx" }
│◄─ Authenticated ─────────┤ { session_id, server_version }
外部工具 PMP
│ │
├─ Authenticate ───────────►│ { } (socket 文件权限隔离)
│◄─ Authenticated ─────────┤ { session_id, server_version }
| 命令 | 参数 | 说明 |
|---|---|---|
room.create |
{room_id, endpoint?, persistent_empty?} |
创建空房间 |
room.close |
{room_id} |
解散房间 |
room.start |
{room_id} |
强制开始 |
room.cancel_start |
{room_id} |
取消开始 |
room.ready |
{room_id, user_id} |
强制准备 |
room.lock |
{room_id, locked} |
锁定/解锁 |
room.cycle |
{room_id, cycle} |
轮换开关 |
room.set_host |
{room_id, host_id} |
设置房主 |
room.set_tournament |
{room_id, tournament} |
赛事模式房间(禁用默认交互,交 PPB 编排) |
room.set_live |
{room_id, live} |
设置房间 live 状态(供 Panel/PPB 控制) |
room.set_chart |
{room_id, chart_id, chart_name?} |
程序化选谱(chart_name 缺省时从 Phira API 拉取) |
room.kick |
{room_id, user_id, reason?} |
踢人 |
room.force_move |
{room_id, user_id, monitor?} |
强制移入 |
room.info |
{room_id} |
房间详情 |
room.list |
{filters?} |
房间列表;每项含 room_id/uuid/host_id/chart_id/chart_name/state/max_users/player_count 及控制状态 |
room.history |
{room_id} |
房间游玩历史(rounds + 完整记录,上限 play_history_cache_size) |
room.chat_history |
{room_id} |
房间聊天历史(最近 chat_history_limit 条 Chat 消息) |
room.chat_send |
{room_id, user_id, content} |
以房间内真实在线玩家身份发送聊天(复用 Room::send_as);user_id 必须是该房间当前在线玩家,禁止跨房/离线伪造 |
logs.history |
{limit?} |
本进程运行以来的最近日志行(默认 100,上限 2000) |
logs.input |
{limit?} |
本进程运行以来的最近管理输入(CLI/OpenUDS/管理员,默认 100) |
persist.touches |
{since?, limit?, round_uuid?, player_id?} |
触控批次持久化历史(对齐 WIT query-touches;按 seq 递增,limit 上限 500) |
persist.judges |
{since?, limit?, round_uuid?, player_id?} |
判定批次持久化历史(对齐 WIT query-judges;按 seq 递增,limit 上限 500) |
persist.rounds |
{limit?, round_uuid?, player_id?} |
持久化轮次元数据(谱面、房间、玩家、起止时间);供 Replay 索引与 Viewer 使用,limit 上限 1000 |
admin.id_list |
{} |
管理员 ID 列表 |
admin.id_add |
{user_id} |
添加管理员 |
admin.id_remove |
{user_id} |
移除管理员 |
admin.id_set |
{user_ids} |
整体设置管理员列表 |
users.list |
{} |
在线用户列表 |
| 命令 | 参数 | 说明 |
|---|---|---|
player.ban |
{user_id, reason?} |
封禁用户 |
player.unban |
{user_id} |
解封 |
player.banlist |
— | 封禁列表 |
player.ban_ip |
{target, reason?} |
封禁 IP(ID 或 IP) |
player.unban_ip |
{ip} |
解封 IP |
player.ip_history |
{user_id} |
IP 历史 |
player.info |
{user_id} |
用户信息 |
player.kick |
{user_id} |
踢出 |
| 命令 | 参数 | 说明 |
|---|---|---|
server.stats |
— | 运行时统计 |
server.status |
— | 服务器状态 |
server.config_reload |
— | 重载配置 |
server.shutdown |
— | 关闭服务器 |
server.roomcreation |
{enabled} |
建房开关 |
cli.execute |
{command} |
执行任意管理 CLI 命令(rooms / room set ... / config reload 等),返回输出行 |
| 命令 | 参数 | 说明 |
|---|---|---|
broadcast.all |
{message} |
全服广播 |
broadcast.room |
{room_id, message} |
房间广播 |
broadcast.user |
{user_id, message} |
私信 |
| 命令 | 参数 | 说明 |
|---|---|---|
plugin.list |
— | 插件列表 |
plugin.enable |
{name} |
启用插件 |
plugin.disable |
{name} |
禁用插件 |
plugin.reload |
— | 重载全部 |
plugin.info |
{name} |
插件详情 |
plugin.remove |
{name} |
删除插件 |
plugin.call |
{name, method, args} |
调用插件 API |
| 命令 | 参数 | 说明 |
|---|---|---|
runtime.status |
— | 运行时诊断 |
runtime.actors |
— | Actor 状态 |
runtime.persistence |
— | 持久化统计 |
runtime.phira |
— | Phira 客户端统计 |
| 命令 | 参数 | 说明 |
|---|---|---|
subscribe |
{event_types: ["room.*"]} |
订阅事件 |
unsubscribe |
{event_types} |
取消订阅 |
subscribe_stream |
{stream: "touches"|"judges"|"logs", room_id?} |
订阅高频数据流;touches/judges 为对局实时遥测生产投递 |
所有命令的标准响应格式:
{
"type": "response",
"id": "req-uuid",
"ok": true,
"data": { ... }
}
{
"type": "response",
"id": "req-uuid",
"ok": false,
"error": { "code": "ROOM_NOT_FOUND", "message": "..." }
}| 事件 | 数据 | 说明 |
|---|---|---|
room.created |
{room_id, uuid, data} |
房间创建 |
room.joined |
{room_id, user_id, monitor} |
玩家加入 |
room.left |
{room_id, user_id, reason} |
玩家离开 |
room.updated |
{room_id, changes} |
配置变化 |
round.scored |
{room_id, user_id, score, chart_id, ...} |
玩家完成 |
round.completed |
{room_id, round_id, results} |
轮次结束 |
user.online |
{user_id, name} |
玩家上线 |
user.offline |
{user_id} |
玩家离线 |
server.heartbeat |
{users, rooms, sessions, ...} |
定期统计 |
stream.touches |
{user_id, frames, sequence, room, round, timestamp} |
触控数据流(对局实时投递:玩家触控批次,round 为当前轮次 UUID 或 null) |
stream.judges |
{user_id, events, sequence, room, round, timestamp} |
判定数据流(对局实时投递:玩家判定批次,round 为当前轮次 UUID 或 null) |
外部工具 可以精确控制想收的事件类型,避免不必要的数据传输:
// 外部工具 订阅房间和轮次事件
{ "type": "subscribe", "event_types": ["room.*", "round.*"] }
// PMP 确认
{ "type": "subscribed", "active": ["room.*", "round.*"] }通配符: room.* = 全部房间事件, round.scored = 仅单类型
PMP 侧新增 src/openuds/ 模块:
src/openuds/
├── mod.rs # 模块入口
├── server.rs # UDS listener + 连接管理
├── session.rs # 每个客户端连接的会话
├── protocol.rs # 帧编码/解码
├── auth.rs # 认证(token / direct)
├── dispatch.rs # 命令路由(复用 PMP 现有 handler)
├── events.rs # 事件订阅 + 推送
└── streams.rs # 高频数据流(touches/judges)
openuds:
enabled: true
socket_path: "/var/run/pmp-openuds.sock"
auth_token: ""
max_connections: 4
event_buffer_size: 1024
heartbeat_interval_secs: 60