openim_sdk
Python SDK and CLI for OpenIM-style login, send message, and receive message.
Install locally
python3 -m pip install . --force-reinstall --no-deps
Modes
OpenIMWSSDK(recommended): websocket direct connection (gob + gzip + protobuf) with heartbeat and auto reconnect.OpenIMSDK: HTTP polling fallback.openim-cli: account bootstrap, auth status, and outbound notification commands built on top ofOpenIMWSSDK.
CLI quick start
Install this repository, then run:
openim-cli --help
openim-cli config init --token "$OPENIM_TOKEN" --ws-addr ws://127.0.0.1:10001/msg_gateway --default true
openim-cli auth status --format pretty
openim-cli notify +send --to user:u2 --text "hello"
openim-cli notify +send --to group:g1 --text '<at user_id="u2">Gimmus</at> 你好'
Supported commands:
config init|list|use|removeauth statusnotify +send
WebSocket quick start
from openim_sdk import OpenIMWSSDK, WSConfig
sdk = OpenIMWSSDK(
WSConfig(ws_addr="ws://127.0.0.1:10001/msg_gateway", data_dir="./openim_py_data")
)
sdk.login(user_id="u1", token="YOUR_TOKEN")
sdk.start()
sdk.send_text("hello", recv_id="u2")
See openim_sdk/example_ws.py for a runnable demo script.
WebSocket detailed usage
1. Build config
WSConfig parameters:
ws_addr(required): websocket gateway address, e.g.ws://127.0.0.1:10001/msg_gatewayapi_addr: HTTP API address for profile fetch (used to cache self info for send), e.g.http://127.0.0.1:10002; when empty, sdk falls back to envOPENIM_API_ADDRdata_dir: local sqlite directory, default./dataplatform_id: platform ID sent to server, default1timeout_seconds: request/response wait timeout, default1000pull_batch_size: sync page size, default100sdk_version: value sent in ws query, defaultpython-ws-0.1.0auto_sync_on_connect: runsync_once()immediately after first connect, defaultFalseauto_sync_on_reconnect: auto sync after reconnect, defaultTrueauto_reconnect: reconnect automatically on disconnect, defaultTruemax_reconnect_attempts: reconnect attempt cap, default300reconnect_backoff_seconds: reconnect interval sequence, default(1, 2, 4, 8, 16)enable_heartbeat: send ws ping periodically, defaultTrueheartbeat_interval_seconds: ping interval, default24heartbeat_pong_timeout_seconds: pong timeout, default30self_user_info_cache_ttl_seconds: in-memory cache ttl for self profile (senderNickname/senderFaceURL), default600seconds
2. Register callbacks
Available callbacks in OpenIMWSSDK(...):
on_recv_new_message(msg: WSMessage): called for online real-time messageson_recv_offline_new_message(msg: WSMessage): called for offline/sync messageson_connecting(): called before connect/reconnect attemptson_connect_success(): called after successful connect/reconnecton_connect_failed(exc): called when one connect attempt failson_kicked_offline(): called when server returns kick eventon_error(exc): called on internal errors (decode/send/read/reconnect, etc.)logger(text): sdk log output callback
2.1 WSMessage fields
Raw payload keys:
conversationID: conversation id (sdk adds this key)sendID,recvID,groupIDclientMsgID,serverMsgIDsenderPlatformID,senderNickname,senderFaceURLsessionType(1single,2group,3super group)msgFrom,contentType,contentseq,sendTime,createTimestatus,isReadoptions(dict[str, bool])offlinePushInfo(dict)atUserIDList(list[str])attachedInfo,ex
Python field names in WSMessage:
conversation_id,send_id,recv_id,group_idclient_msg_id,server_msg_idsender_platform_id,sender_nickname,sender_face_urlsession_type,msg_from,content_type,contentseq,send_time,create_time,status,is_readoptions,offline_push_info,at_user_id_list,attached_info,exraw: original dictionary payloadcontent_json: parsed JSON fromcontent(orNonewhen not valid JSON)content_obj: typed content object parsed bycontent_type
content_type -> content_obj mapping (same as sdk_struct.go):
101->TextElem102->PictureElem103->SoundElem104->VideoElem105->FileElem106->AtTextElem107->MergeElem108->CardElem109->LocationElem110/119/120->CustomElem113->TypingElem114->QuoteElem115->FaceElem117->AdvancedTextElem118->MarkdownTextElem- other content types ->
NotificationElem
Minimal callback example:
from openim_sdk import OpenIMWSSDK, WSConfig, WSMessage, TextElem, PictureElem
def on_new_model(msg: WSMessage) -> None:
if isinstance(msg.content_obj, TextElem):
print("[text]", msg.content_obj.content)
elif isinstance(msg.content_obj, PictureElem):
print("[picture]", msg.content_obj.source_picture)
else:
print("[other]", msg.content_type, msg.content_obj)
sdk = OpenIMWSSDK(
WSConfig(ws_addr="ws://127.0.0.1:10001/msg_gateway"),
on_recv_new_message=on_new_model,
)
3. Full example (recommended pattern)
import time
from openim_sdk import OpenIMWSSDK, TextElem, WSConfig, WSSDKError, WSMessage
def on_new(msg: WSMessage) -> None:
if isinstance(msg.content_obj, TextElem):
print("[new text]", msg.send_id, "->", msg.recv_id, msg.content_obj.content)
else:
print("[new]", msg.send_id, "->", msg.recv_id, msg.content_type, msg.content_obj)
def on_offline(msg: WSMessage) -> None:
print("[offline]", msg.client_msg_id, msg.seq)
def on_err(exc: Exception) -> None:
print("[error]", exc)
sdk = OpenIMWSSDK(
WSConfig(
ws_addr="ws://127.0.0.1:10001/msg_gateway",
api_addr="http://127.0.0.1:10002",
data_dir="./openim_py_data",
auto_sync_on_connect=True,
auto_sync_on_reconnect=True,
),
on_recv_new_message=on_new,
on_recv_offline_new_message=on_offline,
on_connecting=lambda: print("[ws] connecting"),
on_connect_success=lambda: print("[ws] connected"),
on_connect_failed=lambda e: print("[ws] connect failed:", e),
on_kicked_offline=lambda: print("[ws] kicked offline"),
on_error=on_err,
logger=lambda s: print("[sdk]", s),
)
try:
# 1) login first
sdk.login(user_id="u1", token="YOUR_TOKEN")
# 2) then start websocket threads
sdk.start()
# send peer message
ack = sdk.send_text("hello from ws sdk", recv_id="u2")
print("send ack:", ack) # {"serverMsgID": "...", "clientMsgID": "...", "sendTime": ...}
# keep process alive
while True:
time.sleep(1)
except WSSDKError as e:
print("business error:", e.err_code, e.err_msg)
except KeyboardInterrupt:
pass
finally:
# stop background threads and close db
sdk.logout()
4. Sending messages
- Single chat:
sdk.send_text("hello", recv_id="u2")
sdk.send_at_text("@Gimmus 你好", at_user_list=["u2"], at_users_info=[{"atUserID": "u2", "groupNickname": "Gimmus"}], group_id="g1")
- Group chat:
sdk.send_text("hello group", group_id="g123", session_type=2)
send_text(...) notes:
- must pass one of
recv_idorgroup_id session_typedefaults to single chat (1) ifrecv_idis set, otherwise group (2)- if
WSConfig.api_addris set, sdk fetches self profile (/user/get_users_info) and caches it in memory (ttl controlled byself_user_info_cache_ttl_seconds, default 10 minutes), then auto-fillssenderNicknameandsenderFaceURLon send - supported session values:
1: single chat2: group chat3: super group chat
Media/file messages:
sdk.send_image("/absolute/path/demo.png", recv_id="u2")
sdk.send_sound("/absolute/path/demo.mp3", duration=9, recv_id="u2")
sdk.send_video(
"/absolute/path/demo.mp4",
duration=15000,
snapshot_path="/absolute/path/demo-cover.jpg",
recv_id="u2",
)
sdk.send_file("/absolute/path/report.pdf", recv_id="u2")
URL-based variants:
sdk.send_image_by_url(source_url="https://cdn.example.com/demo.png", width=1280, height=720, recv_id="u2")
sdk.send_video_by_url(video_url="https://cdn.example.com/demo.mp4", duration=15000, recv_id="u2")
sdk.send_file_by_url(source_url="https://cdn.example.com/report.pdf", file_name="report.pdf", recv_id="u2")
Media upload notes:
- local media/file sending uses OpenIM object upload APIs before message send
SDKConfig.api_addr/WSConfig.api_addrmust be configured for local media/file sendingsend_video(...)requiresdurationin milliseconds; whensnapshot_pathis omitted, the SDK will try to extract the first video frame as the cover image with localffmpegsend_sound(...)requiresduration- CLI
notify +send --video ...now probes local video duration in milliseconds withffprobeand sends a real video message instead of falling back to file sending - CLI
notify +send --text ...supports mention markup like<at user_id="u2">Gimmus</at> 你好, which is sent as OpenIMAT_TEXT (106) send_pictureis an alias ofsend_image
5. Manual sync
If you want explicit control (instead of auto_sync_on_connect/reconnect), call:
sdk.sync_once()
This pulls missing seq ranges and dispatches them through on_recv_offline_new_message.
6. Lifecycle and best practices
- call order should be:
login(...) -> start() -> send/recv -> logout() stop()only stops ws threads;logout()stops threads and closes local storage- keep your process alive after
start(), otherwise daemon threads exit with process - for production:
- keep
auto_reconnect=True - keep heartbeat enabled
- handle
on_errorandon_connect_failedfor observability/retry alerts - persist your own app-level offsets/state if required
- keep
HTTP polling quick start
from openim_sdk import OpenIMSDK, SDKConfig
sdk = OpenIMSDK(
SDKConfig(api_addr="http://127.0.0.1:10002", data_dir="./openim_py_data")
)
sdk.login(user_id="u1", token="YOUR_TOKEN")
sdk.start_receiving()
sdk.send_text("hello", recv_id="u2")
me = sdk.get_self_user_info()
print(me.user_id, me.nickname, me.face_url)
WebSocket features
- Login with
user_id + token - Send text message with protobuf payload (
MsgData) - Receive
PushMessagesfrom ws binary frames - Gob encode/decode for
GeneralWsReq/GeneralWsResp - Gzip frame compression/decompression
- Heartbeat (
ping/pong) - Auto reconnect with backoff (
1,2,4,8,16seconds loop by default) - Auto sync missed messages on connect/reconnect
- Local SQLite persistence:
- message rows
- per-conversation latest synced seq
Local database
- WS mode:
<data_dir>/OpenIM_pyws_<user_id>.db - HTTP mode:
<data_dir>/OpenIM_py_<user_id>.db
Tables:
conversation_seq(conversation_id, last_seq)messages(...)
Metadata
Release files for openim-sdk-core 0.1.11
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| openim_sdk_core-0.1.11.tar.gz | 75.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| openim_sdk_core-0.1.11-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 149.7 kB
Release files / openim_sdk_core-0.1.11.tar.gz
| Download URL | openim_sdk_core-0.1.11.tar.gz |
|---|---|
| Size | 75.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7c57f96963780a080069b4177406edac23f9f0bc34ab10fcea208dfe07a8bb4d
|
|
BLAKE2b-256 checksum How to use checksums |
0f7addd85eef439e826cafe59a593c41d050d626136f91d5091c9c37069fa9c9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Release files / openim_sdk_core-0.1.11-py3-none-any.whl
| Download URL | openim_sdk_core-0.1.11-py3-none-any.whl |
|---|---|
| Size | 74.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4ae1dcdd6096b79e6e117186c82eb2e7d3efcc539e373d1acd52b0c979de62d9
|
|
BLAKE2b-256 checksum How to use checksums |
f67d053b8a5cb206ffaba9a6423b75ebaaf7cc79a5a4073b5b1651eb509aefb4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|