Python SDK and CLI for OpenIM-style login, messaging, and websocket sync.
Project description
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(...)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file openim_sdk_core-0.1.10.tar.gz.
File metadata
- Download URL: openim_sdk_core-0.1.10.tar.gz
- Upload date:
- Size: 72.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c2f5050d64a9334f93b21517eafbb89aa385bee4e1af0f336edf8b190bd4ada3
|
|
| MD5 |
5385455b123acf37c4e789c4648d11f0
|
|
| BLAKE2b-256 |
a773b649f742d5693bd53aee21f8ffdc5efe34c6617ab1cdf3b00e5945d9f0f8
|
File details
Details for the file openim_sdk_core-0.1.10-py3-none-any.whl.
File metadata
- Download URL: openim_sdk_core-0.1.10-py3-none-any.whl
- Upload date:
- Size: 71.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb7cfd7d7f3d228f2445edd27639fb472d430deedffbc1b43961f057518c670a
|
|
| MD5 |
5f8546ee125c7b9fcf59c84d86c6c8e4
|
|
| BLAKE2b-256 |
f163d773ce08ef4180afd2ebaad9b19ecc3c8fa94c00e7732f63ba5be54156d1
|