跳转至

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 ~/.weilink/token.json.

None
base_path str | Path | None

Base directory for multi-session storage. Named sessions are stored under <base_path>/<name>/. Defaults to ~/.weilink/. Ignored if token_path is given (the base path is derived from it).

None
message_store bool | str | Path | None

Enable SQLite message persistence. None (default) disables it. True uses <base_path>/messages.db. A path string or Path specifies a custom database location.

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 "default" for the default session).

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 logs out the default session.

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 uses the default session. A new named session stores credentials at <base_path>/<name>/token.json.

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 recv() with a short timeout before sending to refresh context tokens. Useful when the caller may not have called recv() recently.

False

Returns:

Type Description
SendResult

A SendResult with success flag, any messages

SendResult

received during auto-recv, and remaining quota count.

SendResult

Evaluates to True/False for backward compatibility.

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 "image", "voice", "file", "video".

required
file_name str

Original file name (required for "file" type).

''

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.