This release is a pre-release and may not be stable for production use.
deeprespond-im-server-sdk
深应智能(DeepRespond)IM 的服务端 SDK(Python 版):在业务服务端调用 OpenAPI(管理用户、好友、群组、消息、文件、聊天室、内容安全等,签发登录凭证),并接收回调(校验签名、防重放、按事件 ID 去重、分派事件回调和同步回调)。
- Python 3.11 以上;直接依赖只有
httpx。 - 同步的
DRClient和异步的AsyncDRClient,服务、方法和行为完全相同。 - 不要在浏览器和 App 中使用:Client Secret 和 App Token 等同应用管理员的密码。
用户权限与消息可见性
OpenAPI 以应用管理员身份运行,SDK 不会根据业务系统的当前登录用户自动做授权。
将 SDK 接到浏览器或 App 的业务接口时,业务后端必须验证用户身份,并检查会话参与者、群成员及管理角色。
messages.recall 是不受用户角色和撤回时间窗口限制的管理撤回,不能直接暴露成用户的撤回接口。
conversations.list_messages / iter_messages 是服务端全量视角,不应用用户删除、清空记录、入退群时间的过滤。
需要展示用户自己的聊天记录时,应由客户端 SDK 或已登录设备的 User Token 调用客户端消息接口;
仅在全量结果上检查会话 ID 或 cleared_seq,无法恢复逐用户删除的完整语义。
本仓库的 Web Demo 展示了如何组合服务端管理 SDK 与保存在后端的设备身份。
安装
pip install deeprespond-im-server-sdk==1.0.0a2
当前为第三个 Alpha 预发布版本(按 Python 版本规则写作 1.0.0a2)。
已发布的 wheel 与源码包见 PyPI 版本页。
Demo 单独提供 源码 ZIP 和 SHA256 校验文件,不包含在 SDK 安装包内。
解压后安装包内的 requirements.txt,再运行 python -m demo;详细步骤见 Demo 指南。
调用 OpenAPI
import os
from deeprespond_im import DRClient, NotFoundError
client = DRClient(
base_url="https://im.example.com",
org_name="1100250925",
app_name="demo",
client_id=os.environ["IM_CLIENT_ID"],
client_secret=os.environ["IM_CLIENT_SECRET"],
)
# 用户登录业务系统后,为他签发登录凭证,交给 App 用客户端 SDK 登录
ticket = client.users.issue_login_ticket("zhangsan", auto_create=True)
# 以业务的通知账号发单聊;业务单号作为 client_msg_id,重试也不会重复发送
result = client.messages.send(
from_="notice", to_user="zhangsan", client_msg_id="order-1001-paid",
type="custom", body={"card": "order", "order_id": "1001"},
)
for user in client.users.iter(status="active"): # 自动翻页
...
client.close() # 或 with DRClient(...) as client:
异步:方法相同,加 await,遍历用 async for:
from deeprespond_im import AsyncDRClient
async with AsyncDRClient(base_url=..., org_name=..., app_name=..., client_id=..., client_secret=...) as client:
user = await client.users.get("zhangsan")
- 客户端在进程中复用:它持有连接池和 App Token;App Token 由 SDK 换取、缓存、提前续期,失效后自动重新换取。多进程(gunicorn、Celery)的每个工作进程各建一个。
- 重试:查询、带幂等键的写操作(发消息)、本身幂等的写操作在网络错误、超时、5xx 时自动重试;建群、设置密码等不幂等的写操作发出后不重试。被限流时按
Retry-After等待后重发:应用额度用完时整个客户端一起等待,某个群、聊天室被限流时只有这个请求等待。 - 三种状态的参数:修改类方法的参数默认为
UNSET(不发送),None发送null:client.users.update("zhangsan", attributes={"level": None})删除一项属性,attributes=None清空全部。 - 原样发送 JSON:
body=RawJSON('{"price":1.00}');响应中消息的body_raw是原文,逐字节相同。 - 单次调用的选项:每个方法都有
timeout、deadline(总时限)、request_id(追踪 ID);client.with_options(max_retries=0, timeout=3)返回共用令牌和连接池的视图。
错误
from deeprespond_im import DRError, RateLimitError, ServiceUnavailableError
try:
client.users.create("zhangsan")
except DRError as e:
print(e.code, e.reason, e.request_id) # 按 code 判断,不解析 message
子类:AuthenticationError、PermissionDeniedError、NotFoundError、ConflictError、LimitExceededError、RateLimitError、ServiceUnavailableError、InvalidRequestError、ContentRejectedError、ServerError、NetworkError(同时是 ConnectionError)、DRTimeoutError(同时是 TimeoutError)、InvalidResponseError、ClientUnavailableError。具体的失败原因在 e.reason(details.reason,如 room_id_used)。自动重试后得到 already_exists、not_found、version_conflict 时,e.retried 为真:前一次尝试可能已经执行。
文件
file = client.media.upload("/data/a.jpg", purpose="attachment", kind="image")
client.messages.send(from_="notice", to_user="zhangsan", type="image", body={"url": file.url})
client.media.download(file.url, "/tmp/a.jpg")
不超过 32 MB 的一次上传,更大的分片并发上传;中断后可以用 resume_upload(file_id, source) 续传。
media.download 将字节写入目标,不会替 Web 框架设置下载响应头。代理用户上传的附件时,
HTML、SVG 等主动内容应通过 Content-Disposition: attachment 下载,或放在隔离的域名;
不要用浏览器传入的 MIME 类型决定同源响应类型。Demo 同时设置 nosniff 和沙箱 CSP,并只内联识别出的光栅图片。
游戏房间
client.game 用于游戏的业务服务端:匹配成功后建房、给每个玩家签加入票据,对局结束时带结算结果结束房间;玩家的 App 用客户端 SDK 凭票据加入。完整示例见 examples/game_room.py,接口说明见仓库 docs/server-python/2.接口设计.md 第 7 节(行为规则见 docs/server-go/2.接口设计.md 第 7.10 节)。
from deeprespond_im import ServiceUnavailableError
# 房间 ID 用匹配 ID:同参数重复建房返回同一房间(created 为 False),超时重试不会建出两个房间
try:
res = client.game.create_room(match_id, max_players=2, start_mode="all_ready")
except ServiceUnavailableError as e:
# 当前大区没有可用的游戏节点(reason 为 game_capacity_unavailable):SDK 已自动重试过,稍后再建
raise RuntimeError("游戏服务繁忙,请稍后重试") from e
tickets = client.game.issue_tickets(match_id, users=[{"username": "alice"}, {"username": "bob"}])
# 不自动重试:重新签发会作废旧票据,超时后直接再签一次
client.game.close_room(match_id, result={"winner": "alice"})
房间结束(包括到期、空房间、节点故障)时收到 game_room.closed,其中有每个玩家的在线时长和计费分钟数(@handler.on_event("game_room.closed"),数据类为 GameRoomClosed)。
接收回调
from deeprespond_im.callback import CallbackHandler, MemoryNonceStore, MemoryDedupStore, Allow, Reject
handler = CallbackHandler(
secrets={"1840200000000000007": ["cbs_新密钥…", "cbs_旧密钥…"]}, # 地址 ID → 密钥
nonce_store=MemoryNonceStore(), # 多进程、多台服务器部署时用 deeprespond_im.redis 中的实现
dedup_store=MemoryDedupStore(),
)
@handler.on_event("message.sent")
def archive(event, data):
save(data.message_id, data.body_raw) # body_raw 与请求体中的逐字节相同
@handler.on_hook("message.before_send")
def check(request):
if "广告" in (request.body or {}).get("text", ""):
return Reject("ad", "消息中有不允许的内容")
return Allow()
挂到框架上(适配器取原始请求体,签名按原始字节计算):
# Flask
from deeprespond_im.callback.flask import callback_view
app.add_url_rule("/im/callback", view_func=callback_view(handler), methods=["POST"])
# FastAPI / Starlette(异步处理器 AsyncCallbackHandler)
from deeprespond_im.callback.fastapi import callback_endpoint
app.add_api_route("/im/callback", callback_endpoint(async_handler), methods=["POST"], include_in_schema=False)
# Django
from deeprespond_im.callback.django import callback_view
urlpatterns = [path("im/callback", callback_view(handler))]
- 重复的事件(同一个事件 ID)不再调用处理函数,返回 2xx;一批事件中有处理失败的整批返回 503,服务端稍后重发。
- 同步回调的处理函数在
timeout_ms减 50 毫秒内没有返回时,返回 503(或hook_fallback给出的结果)。
测试自己的代码
from deeprespond_im.testing import FakeOpenAPI, signed_request, event_body
fake = FakeOpenAPI()
fake.fail("messages.send", "rate_limited", retry_after=1)
client = fake.client() # 连到假的 OpenAPI 的 DRClient
...
assert fake.calls("messages.send")[0].json["to_user"] == "zhangsan"
文档
完整的说明见仓库中的 Python 文档(行为规则另见 Go 文档)。
独立 RTC 频道管理已提供生成的强类型 Channels/channels API:创建、修改、关闭、票据、成员管理、统计与更正列表。Go 使用 RTCChannel*Params/Result,Node.js/Python 返回具体模型;Python 支持同步/异步。期限保留未设置/null/值三态,票据签发不自动重试。旧 Go 原始 JSON 接口需迁移到新参数/结果;管理 API 不能代替用户登录获取媒体 Token。完整契约及计费规则见仓库 docs/RTC频道/4.实现与部署.md。
Metadata
Release files for deeprespond-im-server-sdk 1.0.0a2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| deeprespond_im_server_sdk-1.0.0a2.tar.gz | 233.5 kB | Without provenance | Details for deeprespond_im_server_sdk-1.0.0a2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| deeprespond_im_server_sdk-1.0.0a2-py3-none-any.whl | Python 3 | none | any | Details for deeprespond_im_server_sdk-1.0.0a2-py3-none-any.whl |
Total release size: 504.4 kB
Release files / deeprespond_im_server_sdk-1.0.0a2.tar.gz
| Download URL | deeprespond_im_server_sdk-1.0.0a2.tar.gz |
|---|---|
| Size | 233.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
12241d97e998af3df50e145d78e3343451e199912bc84dbe6b46746596b3325b
|
|
BLAKE2b-256 checksum How to use checksums |
61fb5f41bc4a8792f9b48a9bcf8ee2b806753d2cc04bbc57ff76cda8c9304be6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / deeprespond_im_server_sdk-1.0.0a2-py3-none-any.whl
| Download URL | deeprespond_im_server_sdk-1.0.0a2-py3-none-any.whl |
|---|---|
| Size | 270.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d763cfe9d05d69d87d7d73afc72fa30b4fef32437d4e9866c06b0f63b4a9b3c0
|
|
BLAKE2b-256 checksum How to use checksums |
6058430fed54b839c48058ac91cdf5eb4cf3f95216c91cd642074585814c956f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for deeprespond-im-server-sdk 1.0.0a2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.