2023-02-02 10:24:18 +08:00

354 lines
8.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Bot对象
`Bot`对象负责处理网络请求和消息回调以及登录登出的用户行为,一个`Bot`对应一个登录的微信号。
### 创建Bot对象
在登录微信之前需要创建一个`Bot`对象。
```go
bot := openwechat.DefaultBot()
```
使用默认的构造方法`DefaultBot`来创建一个`Bot`对象。
### 登陆二维码回调
但仅仅是这样我们依然无法登录, 我们平常登录微信都需要用手机扫描二维码登录,所以我们得知道需要扫描哪张二维码,最后还需要为它绑定一个登录二维码的回调函数。
```go
// 注册登陆二维码回调
bot.UUIDCallback = openwechat.PrintlnQrcodeUrl
```
`PrintlnQrcodeUrl`这个函数做的事情很简单,就是将我们需要扫码登录的二维码链接打印打控制台上,这样我们就知道去扫描哪张二维码登录了。
可以自定义`UUIDCallback`来实现自己的逻辑。
如:将登录的二维码打印到控制台。
```go
package main
import (
"fmt"
"github.com/skip2/go-qrcode"
"github.com/eatMoreApple/openwechat"
)
func ConsoleQrCode(uuid string) {
q, _ := qrcode.New("https://login.weixin.qq.com/l/"+uuid, qrcode.Low)
fmt.Println(q.ToString(true))
}
func main() {
bot := openwechat.DefaultBot()
bot.UUIDCallback = ConsoleQrCode
bot.Login()
}
```
虽然最终打印的结果肉眼看上去有点不尽人意,但手机也还能够识别...
### 登录
#### 扫码登录
上面的准备工作做完了,下面就可以登录,直接调用`Bot.Login`即可。
```go
bot.Login()
```
`Login`方法会阻塞当前 goroutine直到登录成功或者失败。
登录会返回一个`error`,即登录失败的原因。
#### 热登录
每次执行普通登录都需要扫码,在调试一些功能的时候需要反复编译,这样会很麻烦。
热登录可以只用扫码一次,后面在单位时间内重启程序也不会再要求扫码
```go
// 创建热存储容器对象
reloadStorage := openwechat.NewJsonFileHotReloadStorage("storage.json")
defer reloadStorage.Close()
// 执行热登录
bot.HotLogin(reloadStorage)
```
`HotLogin`需要接受一个`热存储容器对象`来调用。`热存储容器`用来保存登录的会话信息,本质是一个接口类型
我们第一次进行热登录的时候,因为我们的`热存储容器`是空的,所以这时候会发生错误。
我们只需要在`HotLogin`增加一个参数,让它在失败后执行扫码登录即可
```go
bot.HotLogin(reloadStorage, openwechat.NewRetryLoginOption())
```
当扫码登录成功后,会将会话信息写入到`热存储容器`中,下次再执行热登录的时候就会从`热存储容器`中读取会话信息,直接登录成功。
```go
// 热登陆存储接口
type HotReloadStorage io.ReadWriter
```
`NewJsonFileHotReloadStorage`简单实现了该接口,它采用`JSON`的方式存储会话信息。
实现这个接口,实现你自己的存储方式。
#### 免扫码登录
目前热登录有一点缺点就是它的有效期很短(具体多久我也不知道)。
我们平常在pc上登录微信的时候通常只需要登录一次第二次就会在微信上有一个确认登录的按钮点击确认就会往手机上发送一个确认登录的请求这样就可以免扫码登录了。
openwechat也提供了这样的功能。
```go
bot.PushLogin(storage HotReloadStorage, opts ...openwechat.BotLoginOption) error
```
`PushLogin`需要传入一个`热存储容器`,和一些可选参数。
`HotReloadStorage` 跟上面一样,用来保存会话信息,必要参数。
`openwechat.BotLoginOption`是一个可选参数,用来设置一些额外的行为。
目前有下面几个可选参数:
```go
// NewSyncReloadDataLoginOption 登录成功后定时同步热存储容器数据
func NewSyncReloadDataLoginOption(duration time.Duration) BotLoginOption
// NewRetryLoginOption 登录失败后进行扫码登录
func NewRetryLoginOption() BotLoginOption
```
注意:如果是第一次登录,``PushLogin`` 一定会失败的,因为我们的`HotReloadStorage`里面没有会话信息,你需要设置失败会进行扫码登录。
```go
bot := openwechat.DefaultBot()
reloadStorage := openwechat.NewJsonFileHotReloadStorage("storage.json")
defer reloadStorage.Close()
err = bot.PushLogin(reloadStorage, openwechat.NewRetryLoginOption())
```
这样当第一次登录失败的时候,会自动执行扫码登录。
扫码登录成功后,会自动保存会话信息到`HotReloadStorage`,下次登录就可以直接使用`PushLogin`了,就会往手机上发送确认登录的请求。
### 扫码回调
在pc端微信上我们打开手机扫码进行登录的时候只扫描二维码但不点击确认微信上也能够显示当前扫码用户的头像并提示用户登录确认。
通过对`bot`对象绑定扫码回调即可实现对应的功能。
```go
bot.ScanCallBack = func(body openwechat.CheckLoginResponse) { fmt.Println(string(body)) }
```
用户扫码后body里面会携带用户的头像信息。
**注**:绑定扫码回调须在登录前执行。
`CheckLoginResponse` 是一个`[]byte`包装类型, 扫码成功后可以通过该类型获取用户的头像信息。
```go
type CheckLoginResponse []byte
func (c CheckLoginResponse) Avatar() (string, error)
```
### 登录回调
对`bot`对象绑定登录
```go
bot.LoginCallBack = func(body openwechat.CheckLoginResponse) {
fmt.Println(string(body))
// to do your business
}
```
登录回调的参数就是当前客户端需要跳转的链接,用户可以不用关心它。(其实可以拿来做一些骚操作😈)
登录回调函数可以当做一个信号处理,表示当前扫码登录的用户已经确认登录。
### 桌面模式
`DefaultBot`默认是与网页版微信进行交互部分用户的网页版wx可能已经被限制登录了。
这时候可以尝试使用`桌面模式`进行登录。
```go
bot := openwechat.DefaultBot(openwechat.Desktop)
```
别的逻辑不用改直接在创建bot的时候加一个参数就行了。
如果桌面模式还登录不上,请检查你的微信号是不是刚刚申请。
### 消息处理
在用户登录后需要实时接受微信发送过来的消息。
很简单,给`BOT`对象绑定一个消息回调函数就行了。
```go
// 注册消息处理函数
bot.MessageHandler = func(msg *openwechat.Message) {
if msg.IsText() && msg.Content == "ping" {
msg.ReplyText("pong")
}
}
```
所有接受的消息都通过`Bot.MessageHandler`来处理。
基于这个回调函数,可以对消息进行多样化处理
```go
dispatcher := openwechat.NewMessageMatchDispatcher()
// 只处理消息类型为文本类型的消息
dispatcher.OnText(func(ctx *openwechat.MessageContext){
msg := ctx.Message
fmt.Println("Text: ", msg.Content)
msg.ReplyText("hello")
})
// 注册消息回调函数
bot.MessageHandler = dispatcher.AsMessageHandler()
```
`openwechat.DispatchMessage`会将消息转发给`dispatcher`对象处理
#### MessageMatchDispatcher
##### 构造方法
```go
openwechat.NewMessageMatchDispatcher()
```
##### 注册消息处理函数
```go
// 注册消息处理函数
func (m *MessageMatchDispatcher) RegisterHandler(matchFunc matchFunc, handlers ...MessageContextHandler)
// 消息匹配函数
type matchFunc func(*Message) bool
// 消息处理函数
type MessageContextHandler func(ctx *MessageContext)
```
`matchFunc`:接受当前收到的消息对象,并返回`bool`值,返回`true`则表示处理当前的消息
`RegisterHandler`:接受一个`matchFunc`和不定长的消息处理函数,如果`matchFunc`返回为`true`,则表示运行对应的处理函数组。
##### OnText
注册处理消息类型为文本类型的消息
```go
func (m *MessageMatchDispatcher) OnText(handlers ...MessageContextHandler)
```
##### OnImage
注册处理消息类型为图片类型的消息
```golang
func (m *MessageMatchDispatcher) OnImage(handlers ...MessageContextHandler)
```
##### OnVoice
注册处理消息类型为语言类型的消息
```go
func (m *MessageMatchDispatcher) OnVoice(handlers ...MessageContextHandler)
```
##### [更多请点击查看源码](https://github.com/eatMoreApple/openwechat/blob/main/message_handle.go)
### 获取登录后的用户
```go
self, err := bot.GetCurrentUser()
```
**注**:该方法在登录成功后调用
[详见`Self`对象](./user.md)
### 阻塞主程序
```go
bot.Block()
```
该方法会一直阻塞,直到用户主动退出或者网络请求发生错误。
### 控制Bot存活
判断当前的`Bot`是否存活。
```go
func (b *Bot) Alive() bool
```
当返回为`true`则表示`Bot`存活。
如何控制`Bot`存活呢?
```go
ctx, cancel := context.WithCancel(context.Background())
bot := openwechat.DefaultBot(openwechat.WithContext(ctx))
```
`WithContext`接受一个`context.Context`对象,当`context`对象被取消时,`Bot`也会被取消。
当前我们也可以调用`bot.Logout`来主动退出当前的`Bot`,当`Bot`退出后,`bot.Alive()`会返回`false`。