30 KiB
服务端 API 文档
本文档详细介绍 Tinode 服务端 API,包括消息格式、协议细节和使用方法。
目录
工作原理
Tinode 是一个 IM 路由器和存储系统。概念上它松散地遵循 发布-订阅 模式。
服务器连接会话、用户和话题:
- 会话(Session):客户端应用与服务器之间的网络连接
- 用户(User):通过会话连接到服务器的人
- 话题(Topic):在会话之间路由内容的命名通信通道
用户和话题被分配唯一 ID:
- 用户 ID:字符串,格式为
usr前缀 + base64-URL 编码的伪随机 64 位数字,如usr2il9suCbuko - 话题 ID:见下文话题类型说明
客户端(如移动应用或 Web 应用)通过 WebSocket 或长轮询建立会话。大多数操作需要客户端认证。客户端通过发送 {login} 数据包认证会话。认证后,客户端收到一个令牌用于后续认证。同一用户可建立多个并发会话。不支持登出设计。
会话建立后,用户可通过话题与其他用户交互。可用的话题类型:
| 类型 | 名称格式 | 说明 |
|---|---|---|
me |
me |
管理用户资料和接收通知;每个用户都有一个 |
fnd |
fnd |
查找其他用户和话题;每个用户都有一个 |
| 点对点 | usrXXX |
两个用户之间的通信通道 |
| 群组 | grpXXX |
多用户通信通道;必须显式创建 |
| 频道 | chnXXX |
只读群组;无限订阅者 |
会话通过发送 {sub} 数据包加入话题。{sub} 有三个功能:
- 创建新话题
- 订阅话题
- 将会话附加到话题
会话加入话题后,用户可通过 {pub} 数据包生成内容。内容以 {data} 数据包传递给其他附加会话。
用户可通过 {get} 和 {set} 数据包查询或更新话题元数据。
话题元数据变更(如描述变更、用户加入/离开)通过 {pres}(在线状态)数据包报告给活跃会话。
通用说明
时间戳格式
时间戳始终表示为 RFC 3339 格式字符串,精度到毫秒,时区始终为 UTC:
"2015-10-06T18:07:29.841Z"
Base64 编码
文档中提到的 base64 编码指 base64 URL 编码,去掉填充字符,见 RFC 4648。
消息 ID
{data}数据包有服务端生成的顺序 ID:从 1 开始的十进制数字,每条消息递增 1- 保证在每个话题内唯一
客户端消息 ID
客户端可为所有数据包分配消息 ID 来连接请求和响应:
- ID 是客户端定义的字符串
- 应至少在会话内唯一
- 服务端不解释,原样返回
连接服务器
有三种网络访问方式:WebSocket、长轮询和 gRPC。
端点
当客户端通过 HTTP(S) 建立连接时,服务器提供以下端点:
| 端点 | 用途 |
|---|---|
/v0/channels |
WebSocket 连接 |
/v0/channels/lp |
长轮询 |
/v0/file/u |
文件上传 |
/v0/file/s |
文件下载 |
v0 表示 API 版本(当前为零)。
API Key
每个 HTTP(S) 请求必须包含 API Key,服务器按以下顺序检查:
- HTTP 头
X-Tinode-APIKey - URL 查询参数
apikey(如/v0/file/s/abcdefg.jpeg?apikey=...) - 表单值
apikey - Cookie
apikey
演示应用包含默认 API Key。生产环境请使用 keygen 工具生成自己的 Key。
握手
连接建立后,客户端必须向服务器发送 {hi} 消息。服务器以 {ctrl} 消息响应,表示成功或错误。响应的 params 字段包含服务器协议版本 "params":{"ver":"0.15"} 等信息。
gRPC
gRPC API 定义见 proto 文件。gRPC API 比本文档描述的 API 功能更多:
- 允许
root用户代表其他用户发送消息 - 允许删除用户
注意:protobuf 消息中的 bytes 字段期望 JSON 编码的 UTF-8 内容。例如,字符串在转换为 bytes 前应加引号:
- Go:
[]byte("\"some string\"") - Python 3:
'"another string"'.encode('utf-8')
WebSocket
消息在文本帧中发送,每帧一条消息。二进制帧保留供将来使用。
默认服务器允许任意 Origin 头值的连接。
长轮询
长轮询通过 HTTP POST(推荐)或 GET 工作。
首次请求时,服务器在响应中发送包含 sid(会话 ID)的 {ctrl} 消息。长轮询客户端必须在后续每个请求中包含 sid(URL 或请求体)。
服务器允许所有来源的连接:Access-Control-Allow-Origin: *
带外大文件
大文件使用 HTTP POST 以 Content-Type: multipart/form-data 带外发送。详见带外大文件处理部分。
反向代理
Tinode 服务器可在反向代理(如 NGINX)后运行:
- 通过 Unix socket 接收连接:设置
listen和/或grpc_listen为 socket 文件路径,如unix:/run/tinode.sock - 从
X-Forwarded-ForHTTP 头读取对端 IP:设置use_x_forwarded_for为true
用户
用户表示一个人,即消息的生产者和消费者。
认证级别
用户通常分配以下两种认证级别之一:
| 级别 | 说明 |
|---|---|
auth |
已认证用户 |
anon |
匿名用户 |
root |
仅 gRPC 可访问,允许代表其他用户发送消息 |
用户 ID 格式
用户 ID 格式为 usr + base64 编码的 64 位数值,如 usr2il9suCbuko。
用户属性
| 属性 | 类型 | 说明 |
|---|---|---|
created |
timestamp | 用户记录创建时间 |
updated |
timestamp | public 或 trusted 最后更新时间 |
status |
string | 账户状态(见下表) |
username |
string | basic 认证使用的唯一字符串;其他用户不可见 |
defacs |
object | 用户 P2P 会话的默认访问模式 |
trusted |
object | 应用定义对象,由系统管理,所有人可读 |
public |
object | 应用定义对象,描述用户,所有人可查询 |
private |
object | 应用定义对象,仅当前用户可访问 |
tags |
array | 发现和凭证标签 |
账户状态
| 状态 | 说明 |
|---|---|
ok |
正常,默认状态 |
susp |
暂停,禁止访问,搜索不可见,可恢复 |
del |
软删除,标记为已删除但保留数据,目前不支持恢复 |
undef |
未定义,内部使用 |
多会话
用户可维护与服务器的多个并发会话。每个会话用客户端提供的 User Agent 字符串标记以区分客户端软件。
不支持登出。如需切换用户,应打开新连接并用新用户凭证认证。
认证
认证概念上类似于 SASL:通过适配器集合实现不同认证方法。
内置认证方法
| 方法 | 说明 |
|---|---|
token |
通过加密令牌认证(主要方式) |
basic |
通过登录名-密码对认证 |
anonymous |
用于临时用户,如客服聊天 |
rest |
元方法,通过 JSON RPC 使用外部认证系统 |
认证流程
-
令牌是主要认证方式
- 轻量级,通常不访问数据库
- 所有处理在内存中完成
-
其他方法用于获取令牌
- 一旦获得令牌,后续登录应使用令牌
-
basic 认证
secret为 base64 编码的用户名:密码字符串- 用户名不能包含冒号
:
-
anonymous 认证
- 仅用于创建账户,不能用于登录
- 用户使用
anonymous创建账户并获得令牌 - 如果令牌丢失或过期,用户将无法再访问账户
创建账户
创建新账户时,用户必须:
- 告知服务器后续将使用的认证方法
- 提供共享密钥(如适用)
仅 basic 和 anonymous 可用于账户创建。
立即登录:设置 {acc login=true} 使用新账户认证当前会话。
登录
通过 {login} 请求执行登录。仅支持 basic 和 token。
响应为 {ctrl} 消息:
- 成功(200):包含可用于后续
token登录的令牌 - 需要信息(300):请求验证凭证或多步认证挑战
- 错误(4xx):认证失败
令牌有服务器配置的过期时间,需要定期刷新。
修改认证参数
通过 {acc} 请求修改认证参数(如修改登录名和密码):
{
"acc": {
"id": "1a2b3",
"user": "usr2il9suCbuko",
"scheme": "basic",
"secret": "base64encode('new_username:new_password')"
}
}
修改密码:secret 中用户名留空,即 base64encode(':new_password')
重置密码("忘记密码")
发送 {login} 消息,scheme 设为 reset:
{
"login": {
"id": "1a2b3",
"scheme": "reset",
"secret": "base64encode('basic:email:jdoe@example.com')"
}
}
服务器将发送包含重置说明的消息。邮件包含受限安全令牌,用户可在 {acc} 请求中使用该令牌设置新密码。
凭证验证
服务器可配置要求验证与用户账户关联的某些凭证,如:
- 唯一邮箱
- 电话号码
- 验证码
验证流程
如果需要某些凭证:
- 用户必须始终保持其验证状态
- 如需更改凭证,必须先添加并验证新凭证,再删除旧凭证
凭证操作
| 操作 | 消息 |
|---|---|
| 注册时分配 | {acc} |
| 添加 | {set topic="me"} |
| 删除 | {del topic="me"} |
| 查询 | {get topic="me"} |
| 验证 | {login} 或 {acc} |
访问控制
访问控制通过访问控制列表(ACL)管理用户对话题的访问。
权限定义
权限以位图表示,通过 ASCII 字符集合表示:
| 字符 | 权限 | 说明 |
|---|---|---|
N |
无访问 | 表示权限已清除/未设置,不应使用默认权限 |
J |
加入 | 订阅话题的权限 |
R |
读取 | 接收 {data} 数据包的权限 |
W |
写入 | 向话题 {pub} 的权限 |
P |
在线状态 | 接收在线状态更新 {pres} 的权限 |
A |
审批 | 批准加入请求、删除和禁止成员的权限(管理员) |
S |
分享 | 邀请他人加入话题的权限 |
D |
删除 | 硬删除消息的权限;仅所有者可完全删除话题 |
O |
所有者 | 话题所有者;可分配任何权限给成员、更改话题描述、删除话题;单所有者;某些话题无所有者 |
实际访问权限
实际访问权限 = want AND given(按位与)
默认访问权限
默认访问为两类用户定义:
- 已认证用户:
auth - 匿名用户:
anon
默认访问值作为 "given" 权限应用于所有新订阅。
话题
话题是一个或多个人的命名通信通道。话题有持久属性,可通过 {get what="desc"} 查询。
话题属性
与用户无关的属性:
| 属性 | 说明 |
|---|---|
created |
话题创建时间 |
updated |
trusted、public、private 最后更新时间 |
touched |
最后一条消息发送时间 |
defacs |
话题默认访问模式 |
seq |
最新 {data} 消息的服务端顺序 ID |
trusted |
应用定义对象,系统管理,所有人可读 |
public |
应用定义对象,描述话题,所有订阅者可读 |
用户相关属性:
| 属性 | 说明 |
|---|---|
acs |
当前用户的访问权限 |
private |
应用定义对象,仅当前用户可访问 |
me 话题
me 话题在账户创建时自动为每个用户创建。用途:
- 管理账户信息
- 接收关注的人和话题的在线状态通知
特点:
- 无所有者
- 不能删除或取消订阅
- 可以
leave(停止通信,表示离线) - 只读(
{pub}消息被拒绝)
{get what="desc"}:返回用户参数,public 更新会影响所有 P2P 话题。
{get what="sub"}:返回用户订阅的话题列表,而非用户对 me 的订阅。
返回字段:
seq:话题最后消息 IDrecv:用户报告已收到的 seq 值read:用户报告已读的 seq 值seen:P2P 订阅中,对方最后在线时间和 User Agent
slf 话题
slf(self)话题用于存储信息,如书签或保存的消息。发送到 slf 的消息仅发送者可访问。
用户首次订阅时自动创建。
fnd 话题与标签
fnd 话题在账户创建时自动为每个用户创建,用于发现其他用户和群组话题。
标签
标签是用于发现的任意大小写不敏感的 Unicode 字符串:
- 最大 96 字符
- 可包含字母、数字和
_,.,+,-,@,#,!,? - 可有前缀(命名空间):如
tel:+14155551212、email:alice@example.com - 某些带前缀标签可强制唯一
- 某些标签可强制不可变
查询语言
查询字符串包含原子术语,用空格或逗号分隔:
- 空格:
AND操作 - 逗号:
OR操作 OR优先于AND
示例:
flowers:匹配包含flowers标签flowers travel:同时包含flowers和travelflowers, travel:包含flowers或travelflowers travel, puppies:包含flowers且包含travel或puppies
查询方式
设置 fnd 话题的 public 或 private 为查询字符串,然后发送 {get topic="fnd" what="sub"}。
private:跨会话和设备持久化,适合大查询(如通讯录匹配)public:不保存到数据库,适合简短特定查询
点对点话题
点对点(P2P)话题表示严格两个用户之间的通信通道。
特点:
- 话题名对两个参与者不同:每人看到的是对方的用户 ID
- 例:用户
usrOj0B3-gSBSs和usrIU_LOVwRNsc的 P2P 话题:- 第一个用户看到:
usrIU_LOVwRNsc - 第二个用户看到:
usrOj0B3-gSBSs
- 第一个用户看到:
- 无所有者
- 内部存储为
p2p+ 两个 64 位用户 ID 的拼接(数值小的在前)
创建:发送 {sub topic="usrXXX"}(对方用户 ID)。
public:用户相关,自动同步到所有 P2P 话题。
群组话题
群组话题表示多个用户之间的通信通道。
名称格式:grp 或 chn + base64 URL 字符串
特点:
- 支持有限数量订阅者(
max_subscriber_count配置) - 每个订阅者的访问权限单独管理
- 可启用频道功能,支持无限只读订阅者(读者)
创建:
- 普通群组:
{sub topic="new"} - 频道:
{sub topic="nch"} - 服务器返回新话题名,如
grpYiqEXb4QY6s - 创建者成为所有者
频道与普通群组的区别:
| 特性 | 普通群组 | 频道 |
|---|---|---|
| 创建 | {sub topic="new"} |
{sub topic="nch"} |
| 订阅 | {sub topic="grpXXX"} |
{sub topic="chnXXX"} |
| 消息 From 字段 | 包含发送者 | 无 |
| 默认权限 | JRWPS | 无 |
| 加入通知 | 有 | 无 |
sys 话题
sys 话题是与系统管理员通信的始终可用通道。
普通用户:
- 不能订阅
sys - 可以不订阅就向
sys发布(如举报滥用)
root 用户:
- 可以订阅
sys - 订阅后接收其他用户发送到
sys的消息
消息
消息是逻辑关联的数据集合。消息以 JSON 格式的 UTF-8 文本传递。
消息格式说明
- 所有客户端到服务端消息可有可选
id字段 - 服务器要求严格有效的 JSON(包括字段名的双引号)
- 清除字段:发送单个 Unicode DEL 字符
\u2421(而非null) - 未知字段被静默忽略
客户端到服务端消息
每条消息可包含顶层 extra 字段:
{
"abc": { ... }, // 主载荷
"extra": {
"attachments": ["/v0/file/s/sJOD_tZDPz0.jpg"],
"obo": "usr2il9suCbuko",
"authlevel": "auth"
}
}
| 字段 | 说明 |
|---|---|
attachments |
带外附件 URL 数组,递增文件使用计数 |
obo |
root 用户设置的代理用户 ID |
authlevel |
代理时的认证级别 |
{hi} - 握手
客户端向服务器告知其版本和用户代理。必须是第一条消息。
{
"hi": {
"id": "1a2b3",
"ver": "0.15.8-rc2",
"ua": "JS/1.0 (Windows 10)",
"dev": "L1iC2...dNtk2",
"platf": "android",
"lang": "en-US",
"tenant": "acme"
}
}
| 字段 | 必需 | 说明 |
|---|---|---|
id |
否 | 客户端消息 ID |
ver |
是 | 支持的协议版本 |
tenant |
是 | 企业码;首次握手时解析并固定当前 Session 的租户 |
ua |
否 | 用户代理字符串 |
dev |
否 | 设备唯一标识(用于推送) |
platf |
否 | 平台:android/ios/web |
lang |
否 | 客户端语言 |
服务器响应 {ctrl},包含 build、ver、sid 以及公开租户信息等参数。租户绑定后不能在当前 Session 中切换。
{acc} - 账户
创建用户或更新认证凭证。
{
"acc": {
"id": "1a2b3",
"user": "newABC123",
"token": "XMgS...8+BO0=",
"scheme": "basic",
"secret": "base64encode('username:password')",
"login": true,
"tags": ["alice johnson"],
"cred": [{"meth": "email", "val": "alice@example.com"}],
"desc": {
"defacs": {"auth": "JRWS", "anon": "N"},
"public": {...},
"private": {...}
}
}
}
| 字段 | 说明 |
|---|---|
user |
"new" 创建新用户;默认当前用户 |
token |
未认证时使用的令牌 |
scheme |
认证方案:basic/anonymous |
secret |
base64 编码的密钥 |
login |
是否立即使用新账户登录 |
tags |
发现标签数组 |
cred |
凭证数组 |
desc |
用户初始化数据 |
{login} - 登录
认证当前会话。
{
"login": {
"id": "1a2b3",
"scheme": "basic",
"secret": "base64encode('username:password')",
"cred": [{"meth": "email", "resp": "178307"}]
}
}
| 字段 | 说明 |
|---|---|
scheme |
认证方案:basic/token/reset |
secret |
base64 编码的密钥 |
cred |
凭证验证响应 |
服务器响应 {ctrl},params 包含:
user:登录用户 IDtoken:加密令牌expires:过期时间
{sub} - 订阅
功能:
- 创建新话题
- 订阅现有话题
- 将会话附加到话题
- 获取话题数据
{
"sub": {
"id": "1a2b3",
"topic": "me",
"set": {
"desc": {"defacs": {"auth": "JRWS", "anon": "N"}},
"sub": {"mode": "JRWS"},
"tags": ["email:alice@example.com"]
},
"get": {
"what": "desc sub data",
"desc": {"ims": "2015-10-06T18:07:30.038Z"},
"sub": {"limit": 20},
"data": {"since": 123, "before": 321, "limit": 20}
}
}
}
| 字段 | 说明 |
|---|---|
topic |
话题名;new 创建群组,nch 创建频道 |
set |
设置参数(镜像 {set}) |
get |
查询参数(镜像 {get}) |
{leave} - 离开
功能:
- 离开话题但不取消订阅(
unsub=false) - 取消订阅(
unsub=true)
{
"leave": {
"id": "1a2b3",
"topic": "grp1XUtEhjv6HND",
"unsub": true
}
}
{pub} - 发布
向话题订阅者分发内容。
{
"pub": {
"id": "1a2b3",
"topic": "grp1XUtEhjv6HND",
"noecho": false,
"head": {"mime": "text/x-drafty"},
"content": {...}
}
}
| 字段 | 说明 |
|---|---|
noecho |
禁止回显(不接收自己发布的消息) |
head |
消息头键值对 |
content |
应用定义内容 |
head 字段值:
| 字段 | 说明 |
|---|---|
attachments |
附件路径数组 |
auto |
消息由机器人自动发送 |
forwarded |
转发消息的原始消息 ID |
mentions |
提及的用户 ID 数组 |
mime |
内容 MIME 类型 |
replace |
替换的消息 ID |
reply |
回复的消息 ID |
thread |
线程首消息 ID |
{get} - 查询
查询话题元数据或消息历史。
{
"get": {
"id": "1a2b3",
"topic": "grp1XUtEhjv6HND",
"what": "sub desc data del cred",
"desc": {"ims": "2015-10-06T18:07:30.038Z"},
"sub": {"user": "usr2il9suCbuko", "limit": 20},
"data": {"since": 123, "before": 321, "limit": 20},
"del": {"since": 5, "before": 12, "limit": 25}
}
}
what 值:
| 值 | 说明 |
|---|---|
desc |
话题描述 |
sub |
订阅者列表 |
tags |
索引标签 |
data |
消息历史 |
del |
删除历史 |
cred |
凭证 |
aux |
辅助数据 |
{set} - 更新
更新话题元数据。
{
"set": {
"id": "1a2b3",
"topic": "grp1XUtEhjv6HND",
"desc": {
"defacs": {"auth": "JRWP", "anon": "JRW"},
"public": {...}
},
"sub": {
"user": "usr2il9suCbuko",
"mode": "JRWP"
},
"tags": ["email:alice@example.com"]
}
}
{del} - 删除
删除消息、订阅、话题、用户。
{
"del": {
"id": "1a2b3",
"topic": "grp1XUtEhjv6HND",
"what": "msg",
"hard": false,
"delseq": [{"low": 123, "hi": 125}, {"low": 156}],
"user": "usr2il9suCbuko"
}
}
what 值:
| 值 | 说明 |
|---|---|
msg |
删除消息 |
sub |
删除订阅 |
topic |
删除话题 |
user |
删除用户 |
cred |
删除凭证 |
消息删除:
hard=false:软删除(仅对当前用户隐藏),需R权限hard=true:硬删除(物理删除),需D权限
{note} - 通知
客户端生成的临时通知,如输入通知或送达回执。
{
"note": {
"topic": "grp1XUtEhjv6HND",
"what": "kp",
"seq": 123,
"unread": 10
}
}
what 值:
| 值 | 说明 |
|---|---|
kp |
按键(正在输入) |
kpa |
正在录制语音消息 |
kpv |
正在录制视频消息 |
recv |
消息已接收 |
read |
消息已读取 |
call |
视频通话状态更新 |
data |
结构化数据包 |
服务端到客户端消息
对特定请求的响应消息包含等于原始消息 ID 的 id 字段。大多数消息有 ts 时间戳字段。
{data} - 数据内容
话题中发布的内容。唯一持久化到数据库的消息。
{
"data": {
"topic": "grp1XUtEhjv6HND",
"from": "usr2il9suCbuko",
"head": {...},
"ts": "2015-10-06T18:07:30.038Z",
"seq": 123,
"content": {...}
}
}
| 字段 | 说明 |
|---|---|
topic |
发布此消息的话题 |
from |
发布者用户 ID |
head |
消息头(从 {pub} 原样传递) |
seq |
服务端顺序 ID(话题内唯一) |
content |
应用定义内容 |
{ctrl} - 控制响应
表示错误或成功条件的通用响应。
{
"ctrl": {
"id": "1a2b3",
"topic": "grp1XUtEhjv6HND",
"code": 200,
"text": "OK",
"params": {...},
"ts": "2015-10-06T18:07:30.038Z"
}
}
| 字段 | 说明 |
|---|---|
code |
状态码(遵循 HTTP 状态码模型) |
text |
结果详情文本 |
params |
上下文相关参数 |
{meta} - 元数据
话题元数据或订阅者信息,响应 {get}、{set} 或 {sub}。
{
"meta": {
"id": "1a2b3",
"topic": "grp1XUtEhjv6HND",
"ts": "2015-10-06T18:07:30.038Z",
"desc": {
"created": "2015-10-24T10:26:09.716Z",
"defacs": {"auth": "JRWP", "anon": "N"},
"acs": {"want": "JRWP", "given": "JRWP", "mode": "JRWP"},
"seq": 123,
"read": 112,
"recv": 115,
"public": {...}
},
"sub": [
{
"user": "usr2il9suCbuko",
"updated": "2015-10-24T10:26:09.716Z",
"acs": {"want": "JRWP", "given": "JRWP", "mode": "JRWP"},
"read": 112,
"online": true
}
],
"tags": ["email:alice@example.com"],
"del": {"clear": 3, "delseq": [{"low": 15}]}
}
}
{pres} - 在线状态
通知客户端重要事件。
{
"pres": {
"topic": "me",
"src": "grp1XUtEhjv6HND",
"what": "on",
"seq": 123,
"ua": "Tinode/1.0 (Android 2.2)"
}
}
what 值:
| 值 | 说明 |
|---|---|
on |
上线 |
off |
下线 |
ua |
用户代理变更 |
upd |
话题描述变更 |
tags |
标签变更 |
acs |
访问权限变更 |
gone |
话题不可用 |
term |
订阅终止 |
msg |
新消息可用 |
read |
消息已读 |
recv |
消息已接收 |
del |
消息已删除 |
{info} - 信息
转发的客户端通知 {note}。
{
"info": {
"topic": "grp1XUtEhjv6HND",
"from": "usr2il9suCbuko",
"what": "read",
"seq": 123
}
}
内容格式
{pub} 和 {data} 的 content 字段格式由应用定义,服务器不强制特定结构。
支持的内容类型
| 类型 | 说明 |
|---|---|
| 纯文本 | 普通字符串 |
| Drafty | 富文本格式,见 Drafty 文档 |
使用 Drafty:消息头必须设置 "head": {"mime": "text/x-drafty"}。
可信、公开、私有、辅助字段
话题有 trusted、public、aux 字段,订阅有 private 字段。
访问控制区别
| 字段 | 写权限 | 读权限 |
|---|---|---|
trusted |
ROOT 用户 | 所有人 |
public |
所有者或用户 | 所有人 |
aux |
话题管理员 | 订阅者 |
private |
用户自己 | 用户自己 |
trusted 格式
{
"trusted": {
"verified": true,
"staff": true,
"danger": false
}
}
| 字段 | 说明 |
|---|---|
verified |
已验证/可信用户或话题标识 |
staff |
属于服务器管理团队 |
danger |
不可信标识 |
public 格式
群组、P2P、系统话题的 public 字段应为 theCard 格式。
fnd 话题的 public 应为搜索查询字符串。
private 格式
{
"private": {
"comment": "some comment",
"arch": true,
"accepted": "JRWS",
"tpins": ["grpmiKBkQVXnm3P"]
}
}
| 字段 | 说明 |
|---|---|
comment |
用户对话题或对方的备注 |
arch |
话题已归档 |
accepted |
用户接受的 'given' 模式 |
tpins |
置顶的话题 ID(仅 me 话题) |
aux 格式
{
"aux": {
"pins": [1001, 23456]
}
}
| 字段 | 说明 |
|---|---|
pins |
置顶的消息 ID 数组 |
带外大文件处理
大文件通过 HTTP POST 以 multipart/form-data 带外处理。
端点
| 端点 | 用途 |
|---|---|
/v0/file/u |
文件上传 |
/v0/file/s |
文件下载 |
认证
需要 API Key 和登录凭证,检查顺序:
- HTTP 头
Authorization - URL 参数
auth和secret - 表单值
auth和secret - Cookie
auth和secret
上传流程
- 创建 RFC 2388 multipart 请求
- POST 到服务器
- 响应
307 Temporary Redirect或200 OK+{ctrl} ctrl.params.url包含文件路径
{
"ctrl": {
"params": {
"url": "/v0/file/s/mfHLxDWFhfU.pdf"
},
"code": 200,
"text": "ok"
}
}
在消息中使用
将 URL 用于 {pub} 消息的 Drafty 内容:
{
"pub": {
"head": {"mime": "text/x-drafty"},
"content": {
"ent": [{"data": {"mime": "image/jpeg", "ref": "/v0/file/s/sJOD_tZDPz0.jpg"}}]
}
},
"extra": {
"attachments": ["/v0/file/s/sJOD_tZDPz0.jpg"]
}
}
重要:必须在 extra.attachments 中列出使用的 URL,服务器使用此字段维护文件使用计数。
推送通知
Tinode 使用编译时适配器处理推送通知。
内置适配器
| 适配器 | 支持平台 |
|---|---|
| Tinode Push Gateway (TNPG) | Android (Play Services)、iOS、Web 浏览器(Safari 除外) |
| Google FCM | Android (Play Services)、iOS、Web 浏览器(Safari 除外) |
| stdout | 调试、测试、日志 |
通知载荷
{
"topic": "grpnG99YhENiQU",
"xfrom": "usr2il9suCbuko",
"ts": "2019-01-06T18:07:30.038Z",
"seq": "1234",
"mime": "text/x-drafty",
"content": "Lorem ipsum..."
}
视频通话
详见 视频通话文档。
链接预览
Tinode 提供可选服务帮助客户端生成链接预览。
端点:/v0/urlpreview?url=...
响应:
{
"title": "Page title",
"description": "Page description",
"image_url": "https://..."
}
需要认证,方式同带外大文件。
附录:状态码
服务器响应使用 HTTP 状态码模型:
| 状态码范围 | 说明 |
|---|---|
| 2xx | 成功 |
| 3xx | 需要更多信息 |
| 4xx | 客户端错误 |
| 5xx | 服务器错误 |
附录:错误消息
错误以 JSON 返回:{"err": "error-message"}
| 错误 | 说明 |
|---|---|
internal |
数据库失败或其他内部错误 |
malformed |
请求无法解析 |
failed |
认证失败 |
duplicate value |
重复凭证 |
unsupported |
不支持的操作 |
expired |
密钥已过期 |
policy |
策略违规 |
credentials |
需要验证凭证 |
not found |
对象未找到 |
denied |
操作不允许 |