clawbot

package module
v0.0.0-...-49a6a8d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 1, 2026 License: MIT Imports: 16 Imported by: 0

README

wechat-clawbot-client-go

Go Reference

English

微信 iLink Bot API 的 Go SDK。将微信 bot 能力集成到任意 Go 项目中 —— 后端服务、CLI 工具、聊天客服系统。

特性

  • 泛型 Client[T] — 携带自定义业务上下文(数据库连接、用户信息等)
  • QR 码登录Login() 返回含 QR URL 的 LoginSessionWait() 阻塞直到扫码完成
  • 凭证自动管理 — 登录后自动保存到 Store;Start() 自动从 Store 恢复
  • 可插拔存储 — 实现 Store 接口即可对接 Redis、MySQL 等。内置 MemoryStoreFileStoreRedisStoreMySQLStoreSQLiteStore
  • 事件回调 — 所有回调携带 *Client[T],直接访问客户端方法和自定义状态
  • 状态机 — 随时查询 client.State()new → logging_in → ready → running ⇄ session_expired → stopped
  • 多媒体支持 — 收发图片、视频、文件、语音,CDN 加密自动处理
  • 输入状态SendTyping() / CancelTyping(),自动缓存 typing ticket

安装

go get github.com/importcjj/wechat-clawbot-client-go

快速开始

package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "os/signal"

    clawbot "github.com/importcjj/wechat-clawbot-client-go"
    "github.com/importcjj/wechat-clawbot-client-go/store"
)

func main() {
    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
    defer stop()

    client := clawbot.NewDefault("my-bot", store.NewFileStore("./data"),
        clawbot.WithEventHooks(clawbot.EventHooks[struct{}]{
            OnMessage: func(c *clawbot.DefaultClient, msg *clawbot.Message) {
                fmt.Printf("%s: %s\n", msg.From, msg.Text)
                c.SendText(ctx, msg.From, "Echo: "+msg.Text)
            },
            OnConnected: func(c *clawbot.DefaultClient) { fmt.Println("Connected!") },
        }),
    )

    // Start 自动从 Store 加载凭证
    // 首次运行: 无凭证 → ErrNotLoggedIn → 扫码登录
    // 后续运行: 有凭证 → 直接长轮询
    err := client.Start(ctx)
    if err == clawbot.ErrNotLoggedIn {
        session, _ := client.Login(ctx)
        fmt.Println("Scan QR:", session.QRCodeURL())
        session.Wait(ctx)
        client.Start(ctx)
    }
}

API

Client
// 创建(泛型,携带自定义状态)
func New[T any](clientID string, state T, s store.Store, opts ...Option[T]) *Client[T]

// 创建(无自定义状态的简写)
func NewDefault(clientID string, s store.Store, opts ...DefaultOption) *DefaultClient

// 登录
func (c *Client[T]) Login(ctx context.Context) (*LoginSession, error)

// 生命周期
func (c *Client[T]) Start(ctx context.Context) error  // 阻塞直到 ctx 取消
func (c *Client[T]) Stop()
func (c *Client[T]) State() ClientState
func (c *Client[T]) ClientID() string
func (c *Client[T]) UserState() T
func (c *Client[T]) HasCredentials() bool

// 发送
func (c *Client[T]) SendText(ctx context.Context, to, text string) error
func (c *Client[T]) SendImage(ctx context.Context, to string, data []byte, caption string) error
func (c *Client[T]) SendVideo(ctx context.Context, to string, data []byte, caption string) error
func (c *Client[T]) SendFile(ctx context.Context, to string, data []byte, filename, caption string) error
func (c *Client[T]) SendTyping(ctx context.Context, to string) error
func (c *Client[T]) CancelTyping(ctx context.Context, to string) error
Store
type Store interface {
    CredentialStore   // SaveCredentials / LoadCredentials / DeleteCredentials
    SyncStore         // SaveSyncBuf / LoadSyncBuf
    ContextTokenStore // SaveContextToken / LoadContextToken
}
实现 构造函数 适用场景
MemoryStore store.NewMemoryStore() 开发测试
FileStore store.NewFileStore(dir) CLI / 单机
RedisStore store.NewRedisStore(client) 分布式部署
SQLiteStore store.NewSQLiteStore(db) 嵌入式持久化
MySQLStore store.NewMySQLStore(db) 生产服务端
EventHooks

回调的第一个参数是 *Client[T],可以直接调用客户端方法和访问自定义状态:

type EventHooks[T any] struct {
    OnMessage        func(client *Client[T], msg *Message)
    OnQRCode         func(client *Client[T], qrCodeURL string)
    OnQRScanned      func(client *Client[T])
    OnQRExpired      func(client *Client[T], refreshCount int)
    OnConnected      func(client *Client[T])
    OnSessionExpired func(client *Client[T])
    OnDisconnected   func(client *Client[T], err error)
    OnError          func(client *Client[T], err error)
}

不需要自定义状态时,可用 DefaultEventHooks(签名不含 *Client,保持简洁):

type DefaultEventHooks struct {
    OnMessage        func(clientID string, msg *Message)
    OnConnected      func(clientID string)
    // ...
}

示例

Terminal Echo Chat

终端 echo bot,适合快速体验和调试。

cd examples/terminal-echo-chat && go run .
  • 终端渲染二维码,扫码即用
  • 文本 echo、图片/视频/文件下载保存、语音转文字
  • 凭证自动持久化,重启免登录
Stateful Bot

展示 Client[T] 泛型用法,在回调中直接访问自定义状态。

cd examples/stateful-bot && go run .
  • 自定义 BotState 携带 per-user 消息计数器
  • EventHooks[*BotState] 回调直接拿到 *Client[*BotState]
  • 通过 c.UserState() 访问状态,c.SendText() 回复
Multi-Account Server

多账号管理后台(Go + React + Ant Design),适合服务端集成参考。

# 后端
cd examples/multi-account-server/server && go run .
# 前端
cd examples/multi-account-server/ui && pnpm install && pnpm dev
  • Bot 列表管理(添加/激活/停用/状态查询)
  • QR 码扫码登录弹窗,重启自动恢复所有 bot
  • 聊天界面:消息历史、发送文本/图片/文件、typing 状态
  • 消息持久化,服务重启不丢失

许可证

MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrNotLoggedIn = errors.New("wechat: not logged in, call Login() first")

ErrNotLoggedIn is returned by Start when no credentials are available.

Functions

This section is empty.

Types

type APIError

type APIError struct {
	Ret     int
	ErrCode int
	ErrMsg  string
}

APIError represents a non-zero ret/errcode from the server.

func (*APIError) Error

func (e *APIError) Error() string

type CDNError

type CDNError struct {
	StatusCode int
	Message    string
	Retryable  bool
}

CDNError represents a CDN upload or download failure.

func (*CDNError) Error

func (e *CDNError) Error() string

type Client

type Client[T any] struct {
	// contains filtered or unexported fields
}

Client[T] is the main entry point for the WeChat iLink Bot SDK. T is a user-defined state type for carrying business context.

func New

func New[T any](clientID string, state T, s store.Store, opts ...Option[T]) *Client[T]

New creates a new Client.

  • clientID: business identifier (e.g. "user-123"), used as Store key and in EventHook callbacks
  • state: user-defined state accessible via UserState()
  • s: storage backend, nil uses in-memory store

func (*Client[T]) CancelTyping

func (c *Client[T]) CancelTyping(ctx context.Context, to string) error

CancelTyping cancels the typing indicator for a user.

func (*Client[T]) ClientID

func (c *Client[T]) ClientID() string

ClientID returns the business identifier passed at creation.

func (*Client[T]) HasCredentials

func (c *Client[T]) HasCredentials() bool

HasCredentials checks if the Store has credentials for this clientID.

func (*Client[T]) Login

func (c *Client[T]) Login(ctx context.Context) (*LoginSession, error)

Login initiates a QR code login. Returns a LoginSession whose QRCodeURL() can be displayed immediately. Call session.Wait() to block until completion.

func (*Client[T]) SendFile

func (c *Client[T]) SendFile(ctx context.Context, to string, data []byte, filename, caption string) error

SendFile uploads and sends a file attachment.

func (*Client[T]) SendImage

func (c *Client[T]) SendImage(ctx context.Context, to string, data []byte, caption string) error

SendImage uploads and sends an image.

func (*Client[T]) SendText

func (c *Client[T]) SendText(ctx context.Context, to, text string) error

SendText sends a plain text message to a user.

func (*Client[T]) SendTyping

func (c *Client[T]) SendTyping(ctx context.Context, to string) error

SendTyping sends a typing indicator to a user.

func (*Client[T]) SendVideo

func (c *Client[T]) SendVideo(ctx context.Context, to string, data []byte, caption string) error

SendVideo uploads and sends a video.

func (*Client[T]) Start

func (c *Client[T]) Start(ctx context.Context) error

Start begins the long-poll monitor loop. Blocks until ctx is cancelled. If Login() was not called, Start tries to load credentials from Store. Returns ErrNotLoggedIn if no credentials are available.

func (*Client[T]) State

func (c *Client[T]) State() ClientState

State returns the current lifecycle state.

func (*Client[T]) Stop

func (c *Client[T]) Stop()

Stop stops the long-poll monitor loop.

func (*Client[T]) UserState

func (c *Client[T]) UserState() T

UserState returns the user-defined state.

type ClientState

type ClientState int

ClientState represents the lifecycle state of a Client.

const (
	StateNew            ClientState = iota // Just created
	StateLoggingIn                         // Login() in progress
	StateReady                             // Has credentials, can Start
	StateRunning                           // Start() running, long-polling
	StateSessionExpired                    // Server returned errcode -14
	StateStopped                           // Start() ended
)

func (ClientState) String

func (s ClientState) String() string

type DefaultClient

type DefaultClient = Client[struct{}]

DefaultClient is a Client without custom state, for the common case.

func NewDefault

func NewDefault(clientID string, s store.Store, opts ...DefaultOption) *DefaultClient

NewDefault creates a Client without custom state.

client := wechat.NewDefault("my-bot", nil)
client := wechat.NewDefault("my-bot", store.NewFileStore("./data"),
    wechat.WithDefaultEventHooks(wechat.DefaultEventHooks{
        OnMessage:   func(id string, msg *wechat.Message) { ... },
        OnConnected: func(id string) { ... },
    }),
)

type DefaultEventHooks

type DefaultEventHooks struct {
	OnMessage        func(clientID string, msg *Message)
	OnQRCode         func(clientID string, qrCodeURL string)
	OnQRScanned      func(clientID string)
	OnQRExpired      func(clientID string, refreshCount int)
	OnConnected      func(clientID string)
	OnSessionExpired func(clientID string)
	OnDisconnected   func(clientID string, err error)
	OnError          func(clientID string, err error)
}

DefaultEventHooks provides event callbacks without the state parameter, for use with DefaultClient.

type DefaultOption

type DefaultOption = Option[struct{}]

DefaultOption is an Option without custom state.

func WithDefaultEventHooks

func WithDefaultEventHooks(h DefaultEventHooks) DefaultOption

WithDefaultEventHooks sets event hooks for a DefaultClient. It wraps each callback to match the EventHooks[struct{}] signature.

type EventHooks

type EventHooks[T any] struct {
	OnMessage        func(client *Client[T], msg *Message)
	OnQRCode         func(client *Client[T], qrCodeURL string)
	OnQRScanned      func(client *Client[T])
	OnQRExpired      func(client *Client[T], refreshCount int)
	OnConnected      func(client *Client[T])
	OnSessionExpired func(client *Client[T])
	OnDisconnected   func(client *Client[T], err error)
	OnError          func(client *Client[T], err error)
}

EventHooks receives lifecycle events. All callbacks receive *Client[T] as the first parameter, giving access to the client, its ID, and user state.

type LoginSession

type LoginSession struct {
	// contains filtered or unexported fields
}

LoginSession represents an in-progress QR login.

func (*LoginSession) QRCodeURL

func (s *LoginSession) QRCodeURL() string

QRCodeURL returns the URL for displaying the QR code.

func (*LoginSession) Wait

func (s *LoginSession) Wait(ctx context.Context) error

Wait blocks until the QR login completes, times out, or ctx is cancelled.

type MediaAttachment

type MediaAttachment = monitor.MediaAttachment

MediaAttachment holds decoded media data.

type Message

type Message = monitor.Message

Message represents a decoded inbound message from a WeChat user.

type Option

type Option[T any] func(*clientConfig[T])

Option configures a Client. Use With* functions to create options.

func WithBaseURL

func WithBaseURL[T any](url string) Option[T]

WithBaseURL overrides the default API base URL.

func WithCDNBaseURL

func WithCDNBaseURL[T any](url string) Option[T]

WithCDNBaseURL overrides the default CDN base URL.

func WithEventHooks

func WithEventHooks[T any](h EventHooks[T]) Option[T]

WithEventHooks sets lifecycle event callbacks.

func WithHTTPClient

func WithHTTPClient[T any](hc *http.Client) Option[T]

WithHTTPClient sets a custom http.Client for all requests.

func WithLogger

func WithLogger[T any](l *slog.Logger) Option[T]

WithLogger sets a structured logger.

func WithMessageBufferSize

func WithMessageBufferSize[T any](n int) Option[T]

WithMessageBufferSize sets the OnMessage internal buffer size.

func WithRouteTag

func WithRouteTag[T any](tag string) Option[T]

WithRouteTag sets the SKRouteTag header value.

func WithVersion

func WithVersion[T any](version string) Option[T]

WithVersion sets the channel version string.

type RefMessage

type RefMessage = monitor.RefMessage

RefMessage holds quoted message info.

type SessionExpiredError

type SessionExpiredError struct {
	AccountID string
}

SessionExpiredError indicates the server returned errcode -14.

func (*SessionExpiredError) Error

func (e *SessionExpiredError) Error() string

type VoiceAttachment

type VoiceAttachment = monitor.VoiceAttachment

VoiceAttachment holds decoded voice data.

Directories

Path Synopsis
internal
api
cdn

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL