ErisPulse API 動作標準
本文檔定義 ErisPulse 适配器中 OneBot12 標準 API 動作的統一接口規範,使模組開發者可以面向標準接口編程,由适配器負責映射到平台原生 API。
覆蓋範圍:OneBot12 標準動作中,
ApiDSL提供使用者 / 群組 / 頻道(Guild)/ 消息管理 / 元(Meta)常規接口的強類型方法(send_message由SendDSL.Raw_ob12承擔)。檔案資源動作(upload_file/get_file/ 分片)僅作 降級透傳保留,見 §3.5 說明。平台擴展動作經Api.call("prefix.action", ...)逃生艙調用。動作參數與返回結構以 OneBot12 規範(倉庫內onebot/specs/interface/)為準。
1. 設計背景
在 ErisPulse 中,消息段(消息收發)和事件格式已經完全遵循 OneBot12 標準,但 API 動作呼叫(如獲取用戶資訊、獲取群組列表、撤回消息等)此前未統一——模組開發者必須為每個平台撰寫不同的 call_api 呼叫。
ApiDSL 透過提供強類型的標準動作方法,解決此問題:
模組程式碼(跨平台統一) 適配器實作(平台特定)
───────────────── ──────────────────
adapter.Api.get_user_info("123") → 適配器 call_api / 覆蓋
adapter.Api.get_group_list() → 適配器 call_api / 覆蓋
adapter.Api.delete_message("id") → 適配器 call_api / 覆蓋
2. 三層 DSL 並行結構
ErisPulse 适配器有三個並行的 DSL 內部類,各司其職:
BaseAdapter
├── Send(SendDSL) ← 消息發送(Text/Image/Raw_ob12)
├── Request(RequestDSL) ← 請求操作(accept/reject)
└── Api(ApiDSL) ← 標準 API 動作(用戶/群組/頻道/消息管理/文件/元)★
| DSL | 職責 | 方法風格 | 返回值 |
|---|---|---|---|
Send |
發送消息 | 串鏈 + asyncio.Task |
標準回應 |
Request |
處理請求事件 | asyncio.Task |
標準回應 |
Api |
查詢/管理操作 | async 方法 |
標準回應 |
3. 標準動作列表
3.1 用戶相關
| 方法 | OB12 動作 | 參數 | data 返回 |
|---|---|---|---|
get_self_info() |
get_self_info |
無 | user_id, user_name, user_displayname |
get_user_info(user_id) |
get_user_info |
user_id: str |
user_id, user_name, user_displayname, user_remark |
get_friend_list() |
get_friend_list |
無 | list[get_user_info 响應] |
3.2 群組相關
| 方法 | OB12 動作 | 參數 | data 返回 |
|---|---|---|---|
get_group_info(group_id) |
get_group_info |
group_id: str |
group_id, group_name |
get_group_list() |
get_group_list |
無 | list[get_group_info 响應] |
get_group_member_info(group_id, user_id) |
get_group_member_info |
group_id: str, user_id: str |
user_id, user_name, user_displayname |
get_group_member_list(group_id) |
get_group_member_list |
group_id: str |
list[get_group_member_info 响應] |
set_group_name(group_id, group_name) |
set_group_name |
group_id: str, group_name: str |
無 |
leave_group(group_id) |
leave_group |
group_id: str |
無 |
3.3 消息管理
| 方法 | OB12 動作 | 參數 | 說明 |
|---|---|---|---|
delete_message(message_id) |
delete_message |
message_id: str |
撤回/刪除消息 |
發送消息(
send_message)由SendDSL的Raw_ob12處理,不在ApiDSL中重複。
3.4 頻道(Guild)相關
OneBot12 頻道體系分兩級:頻道(guild) 與 子頻道(channel)。
| 方法 | OB12 動作 | 參數 | data 返回 |
|---|---|---|---|
get_guild_info(guild_id) |
get_guild_info |
guild_id: str |
guild_id, guild_name |
get_guild_list() |
get_guild_list |
無 | list[get_guild_info 响應] |
set_guild_name(guild_id, guild_name) |
set_guild_name |
guild_id: str, guild_name: str |
無 |
get_guild_member_info(guild_id, user_id) |
get_guild_member_info |
guild_id: str, user_id: str |
user_id, user_name, user_displayname |
get_guild_member_list(guild_id) |
get_guild_member_list |
guild_id: str |
list[get_guild_member_info 响應] |
leave_guild(guild_id) |
leave_guild |
guild_id: str |
無 |
get_channel_info(guild_id, channel_id) |
get_channel_info |
guild_id: str, channel_id: str |
channel_id, channel_name |
get_channel_list(guild_id, *, joined_only) |
get_channel_list |
guild_id: str, joined_only: bool=false |
list[get_channel_info 响應] |
set_channel_name(guild_id, channel_id, channel_name) |
set_channel_name |
guild_id, channel_id, channel_name |
無 |
get_channel_member_info(guild_id, channel_id, user_id) |
get_channel_member_info |
guild_id, channel_id, user_id |
user_id, user_name, user_displayname |
get_channel_member_list(guild_id, channel_id) |
get_channel_member_list |
guild_id, channel_id |
list[get_channel_member_info 响應] |
leave_channel(guild_id, channel_id) |
leave_channel |
guild_id, channel_id |
無 |
頻道體系與群組(group)彼此獨立:Discord / QQ 頻道 / Kook 等平台實現頻道接口,
傳統 QQ / 微信實現群組接口,兩者可同時存在或僅其一。
3.5 文件資源操作
警告
文件資源模型(file_id 兩段式)在 ErisPulse 屬「降級可用」:
ErisPulse 的文件收發不走「先上傳拿 file_id 再引用」模型——模組發文件用SendDSL.File(file, filename)(URL / 路徑 / 字節發送時直傳,見
發送方法規範)。
本節upload_file/get_file/ 分片動作依賴平台特有的file_id文件資源
能力,通用性不足;僅當適配器後端天然具備該能力時才可透傳,框架內置
適配器不實現也不建議實現,調用時通常返回retcode=10002。
模組需要跨平台傳文件時,請使用SendDSL.File,勿依賴 file_id。展望:
file_id資源模型標準化到框架層是未來的方向,當前版本不提供。
整包傳輸(小文件):
| 方法 | OB12 動作 | 參數 | data 返回 |
|---|---|---|---|
upload_file(*, type, name, ...) |
upload_file |
type, name, url/path/data, headers?, sha256? |
file_id |
get_file(file_id, type) |
get_file |
file_id: str, type: str |
name, url/path/data |
upload_file 的 type 參數:
"url":通過 URL 上傳(需提供url)"path":通過本地路徑上傳(需提供path)"data":通過二進制數據上傳(需提供data)
3.5.1 分片傳輸(大文件,屬上述降級範圍)
OneBot12 分片動作按 stage 區分階段。ApiDSL 將同一動作的三/兩階段拆分為獨立方法
(offset 為字節偏移,data 在 JSON 中為 Base64);下表僅為查閱保留,
適配器無需也不應強制實現:
分片上傳三步:prepare → transfer(循環逐片)→ finish
| 方法 | 對應 stage | 參數 | data 返回 |
|---|---|---|---|
upload_file_fragmented_prepare(name, total_size) |
prepare |
name: str, total_size: int |
file_id(傳輸期用) |
upload_file_fragmented_transfer(file_id, offset, data) |
transfer |
file_id, offset: int, data: bytes |
無 |
upload_file_fragmented_finish(file_id, sha256) |
finish |
file_id, sha256: str(整文件校驗) |
file_id |
total = os.path.getsize(path)
r = await adapter.Api.upload_file_fragmented_prepare(os.path.basename(path), total)
fid = r["data"]["file_id"]
offset = 0
with open(path, "rb") as f:
while chunk := f.read(65536):
await adapter.Api.upload_file_fragmented_transfer(fid, offset, chunk)
offset += len(chunk)
sha256 = hashlib.sha256(open(path, "rb").read()).hexdigest()
await adapter.Api.upload_file_fragmented_finish(fid, sha256)
分片下載兩步:prepare → transfer(循環取片)
| 方法 | 對應 stage | 參數 | data 返回 |
|---|---|---|---|
get_file_fragmented_prepare(file_id) |
prepare |
file_id |
name, total_size, sha256 |
get_file_fragmented_transfer(file_id, offset, size) |
transfer |
file_id, offset: int, size: int |
data(本次分片字節) |
3.6 元(Meta)動作
元動作不針對具體帳號,無需 Using() 指定 Bot。
| 方法 | OB12 動作 | 參數 | data 返回 |
|---|---|---|---|
get_latest_events(limit, timeout) |
get_latest_events |
limit: int=0, timeout: int=0 |
事件對象數組(不含元事件) |
get_supported_actions() |
get_supported_actions |
無 | list[str] 支持的動作名 |
get_status() |
get_status |
無 | good: bool, bots: list[{self, online, ...}] |
get_version() |
get_version |
無 | impl, version, onebot_version |
3.7 通用擴展動作
| 方法 | 說明 |
|---|---|
call(action, **params) |
平台擴展動作的逃生艙,遵循 OB12 擴展命名規則 {prefix}.{action} |
4. 使用方式
4.1 基本調用
from ErisPulse import adapter
# 獲取用戶信息(跨平台統一)
result = await adapter.myplatform.Api.get_user_info("123456")
if result["status"] == "ok":
user_name = result["data"]["user_name"]
print(f"用戶名: {user_name}")
# 獲取群列表
result = await adapter.myplatform.Api.get_group_list()
groups = result["data"]
# 撤回消息
await adapter.myplatform.Api.delete_message("msg_123456")
4.2 指定 Bot 賬號(多帳戶模式)
# 使用指定 Bot 賬號執行操作
info = await adapter.myplatform.Api.Using("bot1").get_self_info()
4.3 平台擴展動作
# 調用平台特有的擴展動作(建議使用 {prefix}.{action} 命名)
result = await adapter.telegram.Api.call(
"telegram.send_sticker",
sticker_id="CAACAgIAAxkBAA...",
)
4.4 在事件處理器中使用
from ErisPulse.Core.Event import message
@message()
async def handle(event):
# 獲取發送者詳細信息
user_id = event.get_user_id()
platform = event.get_platform()
result = await getattr(adapter, platform).Api.get_user_info(user_id)
if result["status"] == "ok":
user_name = result["data"]["user_name"]
await event.reply(f"你好,{user_name}!")
5. 适配器實現
5.1 默認行為(零配置)
ApiDSL 的默認實現將標準動作名作為 endpoint 直接傳遞給 adapter.call_api():
# ApiDSL 默認實現等價於:
async def get_user_info(self, user_id: str) -> dict:
return await self._adapter.call_api("get_user_info", user_id=user_id, account_id=self._account_id)
適用場景:當適配器的底層後端本身即遵循 OneBot12 標準動作協議時,
call_api 天然支援標準動作名(如直接對接遵循該協議的服務端)。
5.2 覆蓋標準方法(映射到平台原生 API)
適配器可覆蓋單個標準方法,將其映射到平台原生 API:
class MyAdapter(BaseAdapter):
class Api(BaseAdapter.Api):
"""MyPlatform 標準 API 動作實現"""
async def get_user_info(self, user_id: str) -> dict:
# 映射到平台原生 API
raw = await self._adapter._request("GET", f"/users/{user_id}")
if raw.get("code") != 0:
return self._adapter.make_error(retcode=34600, message="用戶不存在")
user = raw["data"]
return self._adapter.make_response(
data={
"user_id": str(user["id"]),
"user_name": user.get("nick", ""),
"user_displayname": user.get("display_name", ""),
"user_remark": user.get("remark", ""),
},
raw=raw,
)
async def get_friend_list(self) -> dict:
raw = await self._adapter._request("GET", "/friends")
friends = [
{
"user_id": str(u["id"]),
"user_name": u.get("nick", ""),
"user_displayname": u.get("display_name", ""),
"user_remark": u.get("remark", ""),
}
for u in raw.get("data", [])
]
return self._adapter.make_response(data=friends, raw=raw)
5.3 未支援的動作
適配器未覆蓋的標準方法走默認實現(委託給 call_api)。如果 call_api 也不支援該動作,應返回標準錯誤回應:
async def call_api(self, endpoint: str, **params):
if endpoint not in self._supported_endpoints:
return self.make_error(retcode=10002, message=f"不支援的動作: {endpoint}")
# ... 平台 API 調用
模組開發者可透過回傳值的 retcode 判斷是否支援:
result = await adapter.myplatform.Api.get_friend_list()
if result["retcode"] == 10002:
print("該平台不支援獲取好友列表")
6. 响應格式
所有 ApiDSL 方法返回標準 API 响應格式(詳見 API 响應標準):
{
"status": "ok",
"retcode": 0,
"data": { ... },
"message_id": "",
"message": "",
"myplatform_raw": { ... }
}
注意:資訊查詢類動作的
message_id為空字串(僅訊息發送類動作才有message_id)。
7. 與 SendDSL / RequestDSL 的關係
| 場景 | 使用 DSL | 示例 |
|---|---|---|
| 發送訊息 | Send |
adapter.Send.To("group", "123").Text("hi") |
| 同意/拒絕請求 | Request |
adapter.Request("req_id").accept() |
| 獲取使用者/群組資訊 | Api |
adapter.Api.get_user_info("123") |
| 撤回訊息 | Api |
adapter.Api.delete_message("msg_id") |
| 離開群組 | Api |
adapter.Api.leave_group("group_id") |
8. 适配器實現檢查清單
標準動作
-
call_api能處理標準動作名(或覆蓋對應ApiDSL方法) - 不支援的動作返回
retcode=10002 - 返回值遵循標準 API 回應格式
-
data欄位包含 OB12 標準定義的欄位 - 頻道平台需實現
get_guild_*/get_channel_*/leave_guild/leave_channel - 元動作(
get_status/get_version/get_supported_actions)建議實現 - 檔案收發使用
SendDSL.File(直傳);檔案資源動作(upload_file/get_file/分片)不強制實現,僅當後端具備file_id資源能力時才需透傳
擴展動作
- 平台擴展動作使用
{prefix}.{action}命名 - 擴展動作的參數和回應仍遵循 OB12 動作請求/回應結構