Metadata-Version: 2.4
Name: imbot-sdk-python
Version: 0.1.0
Summary: JuggleIM Python Bot SDK — WebSocket long-connection IM client for bots and server-side agents
Author-email: Tyler <tyler@juggle.im>
Maintainer-email: Tyler <tyler@juggle.im>
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/juggleim/imbot-sdk-python
Project-URL: Repository, https://github.com/juggleim/imbot-sdk-python
Project-URL: Issues, https://github.com/juggleim/imbot-sdk-python/issues
Project-URL: Documentation, https://github.com/juggleim/imbot-sdk-python#readme
Keywords: juggleim,im,instant-messaging,chat,bot,websocket,sdk
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Chat
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: protobuf>=5.0
Requires-Dist: websocket-client>=1.6
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Dynamic: license-file

# imbot-sdk-python

[![PyPI version](https://img.shields.io/pypi/v/imbot-sdk-python.svg)](https://pypi.org/project/imbot-sdk-python/)
[![Python versions](https://img.shields.io/pypi/pyversions/imbot-sdk-python.svg)](https://pypi.org/project/imbot-sdk-python/)
[![License](https://img.shields.io/pypi/l/imbot-sdk-python.svg)](https://github.com/juggleim/imbot-sdk-python/blob/main/LICENSE)

`imbot-sdk-python` 是 JuggleIM 的 Python SDK，基于 WebSocket 与 IM 服务建立长连接，适合 Bot、服务端消息代理或需要主动收发消息的 Python 程序。覆盖连接管理、消息收发、会话查询、历史消息、聊天室、用户状态、RTC 房间和文件凭证查询等常用能力。

- 源码：<https://github.com/juggleim/imbot-sdk-python>
- 包名：`imbot-sdk-python`；导入名：`import imbot_sdk`

## 安装

```bash
pip install imbot-sdk-python
```

依赖（`protobuf>=5.0`、`websocket-client>=1.6`）会自动安装。Python 3.8+。

从源码安装：

```bash
git clone https://github.com/juggleim/imbot-sdk-python.git
cd imbot-sdk-python
pip install .
```

## 测试环境

| 项目 | 值 |
| --- | --- |
| Server API | `http://127.0.0.1` |
| WebSocket | `wss://127.0.0.1` |
| AppKey | `AppKey` |

> Token 由你的 JuggleIM 应用服务端 / 控制台用 AppKey + AppSecret 通过 Server API 颁发。SDK 本身只负责建立长连接与收发消息。

## 能力概览

- 连接管理：`connect`、`disconnect`、`logout`、心跳保活、断线自动重连
- 消息收发：单聊、群聊、聊天室、公共频道消息发送与接收
- 消息管理：历史消息查询、撤回、修改、已读标记、搜索、置顶消息
- 会话管理：会话列表、未读数、置顶、免打扰、标签
- 用户与群信息：用户资料、好友资料、群信息、在线状态订阅
- 聊天室：加入/退出聊天室、聊天室消息、聊天室属性同步
- RTC：创建/加入/查询/退出 RTC 房间
- 文件：文件凭证查询 `get_file_cred`

## 快速说明

### 1. 创建客户端

```python
from imbot_sdk import ImBotClient

client = ImBotClient("wss://127.0.0.1", "your-appkey")
```

说明：

- `address` 传基础地址即可，SDK 会自动拼接为 `ws://host/imbot` 或 `wss://host/imbot`
- `client.platform` 默认是 `"Bot"`
- `client.auto_reconnect` 默认是 `True`

### 2. 建立连接

```python
code, ack = client.connect("your-token")
```

说明：

- 连接成功时 `code == ClientErrorCode.SUCCESS`
- 成功后 `ack.userId` 会写入 `client.user_id`
- `connect` 只能在断开状态下调用；重复连接会返回 `ClientErrorCode.CONNECT_EXISTED`
- 主动调用 `disconnect()` 或 `logout()` 后，不会继续自动重连

### 3. 接收消息的两种方式

推荐优先使用高层监听（拿到的是已经解码后的 `Message`）：

```python
from imbot_sdk import MessageListener, messages

class MyListener(MessageListener):
    def on_message_receive(self, msg):
        if isinstance(msg.msg_content, messages.TextMessage):
            print("text:", msg.msg_content.content)

client.add_message_listener(MyListener())
```

如果你想拿到底层 protobuf 数据：

```python
client.on_message_callback = lambda down_msg: print(down_msg)
client.on_stream_msg_callback = lambda stream_msg: print(stream_msg)
```

### 4. 发送消息

```python
from imbot_sdk import Conversation, messages
from imbot_sdk.pb import appmessages_pb2 as pb

text = messages.TextMessage("hello from imbot-sdk-python")
up = client.build_up_msg(text, client_uid="bot-1")

conv = Conversation(conversation_type=pb.Private, conversation="target-user-id")
code, ack = client.send_message(conv, up)
# ack.msgId / ack.msgSeqNo 为服务端确认结果
```

`build_up_msg` 会把内容模型编码进 `UpMsg.msgType / msgContent / flags`；你也可以直接构造 `pb.UpMsg`。

## 完整示例：连接、监听、回声

```python
import time
from imbot_sdk import ImBotClient, Conversation, MessageListener, ClientErrorCode, messages
from imbot_sdk.pb import appmessages_pb2 as pb

class Echo(MessageListener):
    def __init__(self, client):
        self.client = client
    def on_message_receive(self, msg):
        c = msg.msg_content
        if isinstance(c, messages.TextMessage) and msg.sender_id != self.client.user_id:
            up = self.client.build_up_msg(messages.TextMessage("echo: " + c.content),
                                          client_uid="echo-%d" % time.time_ns())
            self.client.send_message(msg.conversation, up)

client = ImBotClient("wss://127.0.0.1", "AppKey")
client.add_message_listener(Echo(client))

code, ack = client.connect("your-token")
assert code == ClientErrorCode.SUCCESS
print("connected:", ack.userId)

# 主动给某用户发一条单聊
up = client.build_up_msg(messages.TextMessage("hi"), client_uid="greet-1")
client.send_message(Conversation(conversation_type=pb.Private, conversation="target-user-id"), up)

try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    client.disconnect()
```

可运行的版本见 [`examples/echo_bot.py`](examples/echo_bot.py)。推荐用 `.env` + 启动脚本：

```bash
cp examples/.env.example examples/.env
# 编辑 examples/.env，至少填入 IMBOT_TOKEN（可选 IMBOT_TARGET）
bash examples/run.sh
```

`run.sh` 会自动加载 `examples/.env` 并启动 echo bot，多余参数会透传给脚本（如
`bash examples/run.sh --target some-user-id`）。也可以不用脚本，直接传参或导出环境变量：

```bash
python examples/echo_bot.py --token <your-token> --target <target-user-id>
```

配置项（环境变量 / `.env`）：

| 变量 | 说明 | 必填 |
| --- | --- | --- |
| `IMBOT_TOKEN` | 用户 Token | 是 |
| `IMBOT_TARGET` | 启动时打招呼的目标用户 ID | 否 |
| `IMBOT_ADDRESS` | WebSocket 基础地址 | 否 |
| `IMBOT_APPKEY` | 应用 AppKey | 否 |

补充说明：

- 单聊发送使用 `pb.Private`，群聊使用 `pb.Group`，聊天室使用 `pb.Chatroom`，公共频道使用 `pb.PublicChannel`
- 聊天室消息也可以直接 `client.send_chatroom_msg(chatroom_id, up_msg)`
- 接收到的 `msg.msg_content` 已按消息类型解码，可直接 `isinstance` 判断

## 消息类型

内置的消息内容模型位于 `imbot_sdk.messages`：

| 类型 | 标识 | 类 |
| --- | --- | --- |
| 文本 | `jg:text` | `TextMessage` |
| 图片 | `jg:img` | `ImageMessage` |
| 文件 | `jg:file` | `FileMessage` |
| 视频 | `jg:video` | `VideoMessage` |
| 语音 | `jg:voice` | `VoiceMessage` |
| 流式文本 | `jg:streamtext` | `StreamTextMessage` |
| 撤回通知 | `jg:recallinfo` | `RecallInfoMessage` |
| 合并消息 | `jg:merge` | `MergeMessage` |
| 缩略图打包图片 | `jg:tpimg` | `ThumbnailPackedImageMessage` |
| 快照打包视频 | `jg:spvideo` | `SnapshotPackedVideoMessage` |

收到未内置支持的消息类型时，SDK 会回落为 `messages.UnknownMessage`。这些模型的 JSON 编解码字段保持稳定，因此消息可与其它 JuggleIM 客户端互通。

## 常用 API

> 完整方法清单见 [`docs/API.md`](docs/API.md)。命名采用 Python 风格（snake_case）。

### 连接与状态

`connect(token)`、`reconnect()`、`disconnect()`、`logout()`、`ping()`、`add_connection_status_change_listener(listener)`

### 消息

`send_message(conversation, up_msg)`、`qry_history_msgs(req)`、`recall_msg(req)`、`modify_msg(req)`、`mark_read_msg(req)`、`msg_search(req)`、`msg_global_search(req)`、`set_top_msg(req)`、`del_top_msg(req)`

### 会话

`get_conversation(req)`、`get_conversations(req)`、`sync_conversations(req)`、`clear_unread_count(req)`、`set_conversation_top(req)`、`set_mute(req)`、`delete_conversations(req)`

### 用户、群组、状态

`fetch_user_info(user_id)`、`fetch_group_info(group_id)`、`fetch_friend_info(friend_user_id)`、`get_user_status(req)`、`subscribe_user_status(req)`、`unsubscribe_user_status(req)`

### 聊天室

`join_chatroom(chatroom_id)`、`quit_chatroom(chatroom_id)`、`send_chatroom_msg(chatroom_id, up_msg)`、`set_attributes(chatroom_id, attributes)`、`remove_attributes(chatroom_id, keys)`

### RTC

`create_rtc_room(req)`、`join_rtc_room(req)`、`qry_rtc_room(room_id)`、`quit_rtc_room(room_id)`、`rtc_invite(req)`

### 文件

`get_file_cred(req)`

> 当前 SDK 提供文件凭证查询能力，文件上传/下载流程需由业务侧结合存储服务自行处理。

## 使用注意事项

- `publish` 和 `query` 都要求当前连接状态为 `CONNECTED`，否则返回 `ClientErrorCode.CONNECT_CLOSED`
- 发送和查询默认等待 10 秒 ACK，超时分别返回 `ClientErrorCode.SEND_TIMEOUT`、`ClientErrorCode.QUERY_TIMEOUT`
- SDK 内部会自动处理心跳；连续超过两个心跳周期（约 20 秒）未收到下行数据，会断开并尝试自动重连
- 消息监听回调运行在内部线程上，请避免长时间阻塞操作，必要时投递到工作队列
- 图片、文件、语音、视频等消息体只负责内容编解码，不负责上传文件本身

## 重新生成 protobuf

`.proto` 源文件位于 [`proto/`](proto/)。修改后重新生成：

```bash
bash proto/gen.sh
```

## 模块结构

| 模块 | 说明 |
| --- | --- |
| `imbot_sdk.ImBotClient` | 客户端主入口 |
| `imbot_sdk.ClientErrorCode` / `ConnectState` | 错误码与连接状态 |
| `imbot_sdk.models` | 领域模型（`Conversation` / `Message` / `UserInfo` …）|
| `imbot_sdk.messages` | 消息内容模型 |
| `imbot_sdk.pb` | protobuf 类型（`appmessages_pb2` / `connect_pb2` / `chatroom_pb2` / `rtcroom_pb2`）|

## 许可证

[LICENSE](LICENSE)
