weixin-bot SDK

repository·main·Indexed 19 days ago

https://github.com/epiral/weixin-bot

An SDK for integrating AI Agents with WeChat messaging via the iLink Bot API. Available for Node.js (@pinixai/weixin-bot) and Python (weixin-bot-sdk), it provides features including QR code login, automatic session management, long-polling for messages, and 'typing' status simulation.

Tokens
14.5K
Snippets
49
Records
82
Agent score
62%

What's inside weixin-bot

  1. Authentication Credentials and Storage

    main

    When the QR code status reaches confirmed, the API returns the following credentials required for all subsequent business requests:

    • bot_token: The Bearer Token used in the Authorization header.
    • ilink_bot_id: The Bot account ID (e.g., ...@im.bot).
    • ilink_user_id: The authorized WeChat user ID (e.g., ...@im.wechat).
    • baseurl: The business API base URL. Use this instead of the default if it differs.

    Storage Recommendations:

    • Persist bot_token and baseurl together to avoid using stale base URLs after a restart.
    • Store credentials for each ilink_bot_id separately; do not share state files across multiple accounts.
    • Set file permissions to 0600 for security.
  2. How context_token works and its lifecycle

    main

    The context_token is the most critical field in the WeChat iLink protocol. It is not a User ID, but a session capability token for the current conversation context.

    Key Behaviors:

    • Inbound: Every incoming WeixinMessage includes a context_token.
    • Outbound: When calling sendmessage, you must include the context_token received from the inbound message. If it is missing, the server may reject the message or fail to associate it with the session.
    • Lifecycle: The token is tied to the active conversation. If your process restarts and you lose the cached token, you may lose the ability to send active messages until a new session is established.

    Implementation Best Practices:

    1. Cache tokens: Store the most recent context_token using a key like (accountId, userId).
    2. Isolation: Do not reuse tokens across different users or different bot accounts.
    3. Integrity: Never attempt to forge or guess tokens.
  3. Compare WeChat iLink Bot API with other platforms

    main

    The WeChat iLink Bot API has unique characteristics compared to Telegram and Slack, specifically regarding session management and media handling:

    • Message Reception: Primarily uses getupdates long polling (similar to Telegram's getUpdates).
    • Message Targeting: Requires both to_user_id and a context_token. Unlike Telegram where chat_id is sufficient, the context_token is the critical key for WeChat.
    • Session Context: The API uses a 'one-time reply context token' model. To send a message back to a user, you must use the context_token provided in the most recent inbound message.
    • Media Uploads: Follows a two-step process: first call getuploadurl, then perform an upload using AES-128-ECB encryption via an independent CDN.
    • Typing Indicators: Implemented by calling getconfig to retrieve a typing_ticket, then calling sendtyping.
    • Media Encryption: Unlike Telegram or Slack where the platform manages encryption, the caller is responsible for local encryption/decryption.
  4. Handle AES key encoding formats

    main

    When decoding aes_key from media messages, you must support two different encoding formats used by the protocol:

    1. Format A (Raw Bytes): The key is base64(raw 16 bytes). If the decoded length is exactly 16 bytes, use it directly.
    2. Format B (Hex String): The key is base64(hex string). This is common in official implementations. If the decoded length is 32 bytes and contains hexadecimal ASCII characters, you must hex-decode it into the 16-byte key.

    Decoding Logic:

    1. Base64 decode the aes_key string.
    2. If length == 16 bytes $\rightarrow$ Use as key.
    3. If length == 32 bytes and is hex $\rightarrow$ Hex decode to 16 bytes.
    4. If image_item.aeskey is present, it typically takes priority and is usually a 32-character hex string.
  5. How the weixin-bot-sdk works

    main

    The SDK follows this operational lifecycle:

    1. Login: login() fetches a QR code URL, waits for user confirmation via WeChat, and saves the bot token.
    2. Polling: run() performs long polling against the getupdates endpoint.
    3. Normalization: Inbound messages are converted into IncomingMessage objects and passed to registered callbacks.
    4. Context Management: reply() and send() use internally managed context_token values required by the protocol.
    5. Error Recovery: If an errcode = -14 is encountered, the SDK clears saved credentials, requests a new QR login, and resumes polling using exponential backoff.
  6. How weixin-bot works: Authentication and Message Loop

    main

    The SDK manages the complexity of the WeChat iLink Bot API through two main phases:

    1. Authentication

    When bot.login() is called, the SDK requests a QR code URL from the API. The user scans this code via WeChat. Upon successful confirmation, the SDK receives a bot_token and baseurl, which are saved locally for future sessions.

    2. Message Loop

    Once bot.run() is called, the SDK enters a long-polling loop (POST /getupdates) with a hold time of up to 35 seconds.

    • Receiving: When a user sends a message, the API returns the message along with a context_token. The SDK triggers the onMessage event.
    • Typing: Calling sendTyping(userId) triggers the "对方正在输入中" (User is typing) status.
    • Replying: When using reply(msg, text), the SDK automatically includes the required context_token in the POST /sendmessage request and cancels the typing status.
  7. Manage `get_updates_buf` Cursor

    main

    The get_updates_buf is an opaque blob used for long-polling. It is not a readable offset and should not be modified.

    Best Practices:

    • Initial Request: Pass an empty string "".
    • Persistence: Immediately save every new get_updates_buf received in the response. Store it on a per-bot basis.
    • Invalidation: Clear the cursor if the bot_token changes, if you perform a new QR code login, or if you receive a session expiration error (-14).
    • Do Not Decode: Do not attempt to Base64 decode or modify the content of the buffer.
  8. How the @pinixai/weixin-bot lifecycle works

    main

    The SDK operates through the following lifecycle:

    1. Authentication: login() fetches a QR login URL, waits for WeChat confirmation, and saves the returned bot token to the tokenPath.
    2. Polling: run() initiates long polling against the getupdates endpoint.
    3. Normalization: Inbound messages are normalized into the IncomingMessage format before being dispatched to your onMessage handlers.
    4. Context Management: reply() and send() methods manage the context_token internally, which is a requirement of the underlying protocol for message continuity.
  9. Understand the importance of `context_token` for replying

    main

    In the WeChat iLink Bot API, the context_token is a unique design element that binds a response to a specific conversation context.

    Key takeaway for developers: You cannot rely solely on the user_id to send messages. Every inbound message provides a context_token that must be cached and returned in your outgoing request to successfully associate the reply with the correct session. If you only store the user_id, your attempts to send messages will likely fail because the session context is lost.

  10. Install and use weixin-bot with Node.js

    main

    To use the SDK in a Node.js environment, install the @pinixai/weixin-bot package via npm. The typical workflow involves initializing a WeixinBot instance, calling login() to handle QR code authentication, registering a message handler with onMessage, and starting the long-polling loop with run().

    import { WeixinBot } from '@pinixai/weixin-bot'
    
    const bot = new WeixinBot()
    await bot.login()
    
    bot.onMessage(async (msg) => {
      await bot.sendTyping(msg.userId)
      await bot.reply(msg, `Echo: ${msg.text}`)
    })
    
    await bot.run()
  11. Upload and download media via CDN

    main

    Media handling involves three steps:

    1. Get Upload URL: Call POST /ilink/bot/getuploadurl with file metadata (size, MD5, type). It returns an upload_param.
    2. CDN Upload: Perform a POST to <cdn_base>/upload?encrypted_query_param=<upload_param>&filekey=<key>. The body must be the file bytes encrypted using AES-128-ECB.
    3. CDN Download: Call GET <cdn_base>/download?encrypted_query_param=<param>. The response contains AES-128-ECB encrypted bytes which must be decrypted using the aes_key provided in the CDNMedia object.
    # Upload
    POST https://novac2c.cdn.weixin.qq.com/c2c/upload?encrypted_query_param=<upload_param>&filekey=<key>
    Content-Type: application/octet-stream
    Body: [AES-128-ECB encrypted bytes]
    
    # Download
    GET https://novac2c.cdn.weixin.qq.com/c2c/download?encrypted_query_param=<param>