WeiLink¶
weilink.WeiLink
¶
Lightweight WeChat iLink Bot client.
Supports multiple named sessions for registering one bot with multiple
WeChat accounts. When name is not provided, a default session is
used and behaviour is identical to single-session usage.
Example::
wl = WeiLink()
wl.login()
# Receive messages
messages = wl.recv()
for msg in messages:
print(f"{msg.from_user}: {msg.text}")
# Reply
wl.send(msg.from_user, "Got it!")
wl.close()
is_connected
property
¶
Whether any session has valid credentials.
bot_id
property
¶
Default session's bot identifier, or None if not logged in.
bot_ids
property
¶
Map of session name to bot_id for all connected sessions.
sessions
property
¶
All sessions as a name -> Session mapping.
Iterating yields session names (strings)::
for name in wl.sessions: ...
list(wl.sessions) # ["default", "zb"]
Dict-like access for Session objects::
wl.sessions["zb"].rename("new_name")
wl.sessions["zb"].set_default()
__init__(token_path=None, *, base_path=None, message_store=None, fallback_window=_FALLBACK_WINDOW, queue_maxsize=_DEFAULT_QUEUE_MAXSIZE)
¶
Initialize the WeiLink client.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token_path
|
str | Path | None
|
Path to persist bot credentials for the default
session. Defaults to |
None
|
base_path
|
str | Path | None
|
Base directory for multi-session storage. Named
sessions are stored under |
None
|
message_store
|
bool | str | Path | None
|
Enable SQLite message persistence.
|
None
|
fallback_window
|
float
|
Time window in seconds for Route C degraded SQLite reads when the poll lock is held by another process. Defaults to 60. |
_FALLBACK_WINDOW
|
queue_maxsize
|
int
|
Maximum number of messages buffered in the dispatcher queue. When full, the oldest message is dropped. Defaults to 1000. |
_DEFAULT_QUEUE_MAXSIZE
|
rename_session(old_name, new_name)
¶
Rename a session, moving its persisted files.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
old_name
|
str
|
Current session name (use |
required |
new_name
|
str
|
New session name. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If old_name does not exist or new_name is already taken. |
logout(name=None)
¶
Log out a session, removing its persisted credentials.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str | None
|
Session name. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the session does not exist. |
set_default(name)
¶
Set a named session as the default session.
The default session is used when API methods are called without
a session name (e.g. login(), send()).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Session name to set as default. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the session does not exist. |
login(name=None, force=False)
¶
Login a session via QR code scan.
If valid credentials exist on disk and force is False, reuses them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str | None
|
Session name. |
None
|
force
|
bool
|
Force a new QR code login even if credentials exist. |
False
|
Returns:
| Type | Description |
|---|---|
BotInfo
|
BotInfo with bot_id, base_url, and token. |
recv(timeout=35.0)
¶
Receive pending messages via long-polling.
When the dispatcher is running (via :meth:run_forever or
:meth:run_background), messages are read from an internal queue
instead of polling iLink directly. This avoids cursor conflicts.
When multiple sessions are active, polls all sessions concurrently
and merges results. Each returned Message has bot_id
populated so the caller knows which session received it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float
|
Maximum wait time in seconds. |
35.0
|
Returns:
| Type | Description |
|---|---|
list[Message]
|
List of received messages (may be empty on timeout). |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If not logged in (only when dispatcher is not running). |
SessionExpiredError
|
If session has expired (re-login needed). |
send(to, text=None, *, image=None, voice=None, file=None, file_name='', video=None, auto_recv=False)
¶
Send a message to a user.
Automatically routes to the session that has a context_token for the target user. If multiple sessions have a token, the one with the most recent timestamp is used.
Each context_token allows at most 10 outbound messages (text
or media). The returned SendResult.remaining shows how many
sends are left on the current token.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
to
|
str
|
Target user ID (xxx@im.wechat). |
required |
text
|
str | None
|
Text message content. Must be <= 16 KiB UTF-8. |
None
|
image
|
MediaContent | None
|
Image bytes/UploadedMedia, or list thereof. |
None
|
voice
|
MediaContent | None
|
Voice bytes/UploadedMedia, or list thereof. |
None
|
file
|
MediaContent | None
|
File bytes/UploadedMedia, or list thereof. |
None
|
file_name
|
str | list[str]
|
File name(s). Required when sending file(s) as raw bytes. Ignored for UploadedMedia. |
''
|
video
|
MediaContent | None
|
Video bytes/UploadedMedia, or list thereof. |
None
|
auto_recv
|
bool
|
If True, call |
False
|
Returns:
| Type | Description |
|---|---|
SendResult
|
A SendResult with |
SendResult
|
received during auto-recv, and |
SendResult
|
Evaluates to |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If not logged in. |
ValueError
|
If file bytes are provided without file_name, or if file and file_name list lengths don't match. |
QuotaExhaustedError
|
If the 10-message quota for the current context_token is exhausted. |
TextTooLongError
|
If text exceeds 16 KiB UTF-8 bytes. |
send_typing(to)
¶
Show "typing" indicator to a user.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
to
|
str
|
Target user ID. |
required |
stop_typing(to)
¶
Cancel "typing" indicator for a user.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
to
|
str
|
Target user ID. |
required |
download(msg)
¶
Download media from a received message.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
msg
|
Message
|
A received Message with media content. |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
Decrypted file bytes. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the message has no downloadable media. |
upload(to, data, media_type, file_name='')
¶
Pre-upload media to CDN without sending.
Returns an UploadedMedia reference that can be passed to
send() one or more times, avoiding repeated uploads of the
same file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
to
|
str
|
Target user ID (xxx@im.wechat). CDN uploads are user-bound. |
required |
data
|
bytes
|
Raw file bytes. |
required |
media_type
|
str
|
One of |
required |
file_name
|
str
|
Original file name (required for |
''
|
Returns:
| Type | Description |
|---|---|
UploadedMedia
|
UploadedMedia with CDN reference info. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If not logged in. |
ValueError
|
If media_type is invalid or file_name missing for file uploads. |
on_message(handler)
¶
Register a message handler.
Can be used as a decorator or called directly::
@wl.on_message
def handle(msg):
print(msg.text)
# or
wl.on_message(some_function)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
handler
|
Callable[[Message], None]
|
Callable that accepts a Message. |
required |
Returns:
| Type | Description |
|---|---|
Callable[[Message], None]
|
The handler unchanged (for decorator usage). |
run_forever(poll_timeout=35.0)
¶
Start the dispatcher and block until :meth:stop is called.
Installs SIGINT/SIGTERM handlers so Ctrl+C triggers a
graceful shutdown. Calls :meth:close before returning.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
poll_timeout
|
float
|
Timeout per recv poll cycle in seconds. |
35.0
|
run_background(poll_timeout=35.0)
¶
Start the dispatcher in the background without blocking.
Messages are dispatched to registered handlers and buffered in
an internal queue. Call :meth:recv to read from the queue,
or use :meth:on_message to register handlers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
poll_timeout
|
float
|
Timeout per recv poll cycle in seconds. |
35.0
|
stop()
¶
Stop the dispatcher if running.
start_admin(host='127.0.0.1', port=8080)
¶
Start the admin panel HTTP server in a background thread.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
host
|
str
|
Host address to bind to. |
'127.0.0.1'
|
port
|
int
|
Port number. |
8080
|
Returns:
| Type | Description |
|---|---|
Any
|
AdminInfo with host, port, url. |
stop_admin()
¶
Stop the admin panel server.
close()
¶
Save state for all sessions and clean up.