添加定时同步数据到热存储容器功能 (#191)

This commit is contained in:
多吃点苹果 2023-01-10 15:41:04 +08:00 committed by GitHub
parent 102af677ff
commit 87036e2c94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 7 deletions

7
bot.go
View File

@ -248,7 +248,7 @@ func (b *Bot) Block() error {
if b.self == nil {
return errors.New("`Block` must be called after user login")
}
<-b.context.Done()
<-b.Context().Done()
return nil
}
@ -298,6 +298,11 @@ func (b *Bot) UUID() string {
return b.uuid
}
// Context returns current context of bot
func (b *Bot) Context() context.Context {
return b.context
}
func (b *Bot) reload() error {
if b.hotReloadStorage == nil {
return errors.New("hotReloadStorage is nil")

View File

@ -1,5 +1,9 @@
package openwechat
import (
"time"
)
// BotLogin 定义了一个Login的接口
type BotLogin interface {
Login(bot *Bot) error
@ -28,8 +32,9 @@ func (s *SacnLogin) checkLogin(bot *Bot, uuid string) error {
}
type hotLoginOption struct {
withRetry bool
_ struct{}
withRetry bool
syncDuration time.Duration
_ struct{}
}
type HotLoginOptionFunc func(o *hotLoginOption)
@ -40,6 +45,13 @@ func HotLoginWithRetry(flag bool) HotLoginOptionFunc {
}
}
// HotLoginWithSyncReloadData 定时同步 HotLogin 的数据
func HotLoginWithSyncReloadData(duration time.Duration) HotLoginOptionFunc {
return func(o *hotLoginOption) {
o.syncDuration = duration
}
}
// HotLogin 热登录模式
type HotLogin struct {
storage HotReloadStorage
@ -48,6 +60,17 @@ type HotLogin struct {
// Login 实现了 BotLogin 接口
func (h *HotLogin) Login(bot *Bot) error {
if err := h.loginWrapper(bot); err != nil {
return err
}
if h.opt.syncDuration > 0 {
syncer := NewHotReloadStorageSyncer(bot, h.opt.syncDuration)
go func() { _ = syncer.Sync() }()
}
return nil
}
func (h *HotLogin) loginWrapper(bot *Bot) error {
err := h.login(bot)
if err != nil && h.opt.withRetry {
scanLogin := SacnLogin{}
@ -73,6 +96,7 @@ type pushLoginOption struct {
withoutScanCallback bool
withoutLoginCallback bool
withRetry bool
syncDuration time.Duration
}
type PushLoginOptionFunc func(o *pushLoginOption)
@ -105,6 +129,13 @@ func PushLoginWithRetry(flag bool) PushLoginOptionFunc {
}
}
// PushLoginWithSyncReloadData 定时同步 PushLogin 的数据
func PushLoginWithSyncReloadData(duration time.Duration) PushLoginOptionFunc {
return func(o *pushLoginOption) {
o.syncDuration = duration
}
}
// defaultPushLoginOpts 默认的 PushLogin
var defaultPushLoginOpts = [...]PushLoginOptionFunc{
PushLoginWithoutUUIDCallback(true),
@ -118,7 +149,18 @@ type PushLogin struct {
}
// Login 实现了 BotLogin 接口
func (p PushLogin) Login(bot *Bot) error {
func (p *PushLogin) Login(bot *Bot) error {
if err := p.loginWrapper(bot); err != nil {
return err
}
if p.opt.syncDuration > 0 {
syncer := NewHotReloadStorageSyncer(bot, p.opt.syncDuration)
go func() { _ = syncer.Sync() }()
}
return nil
}
func (p *PushLogin) loginWrapper(bot *Bot) error {
err := p.login(bot)
if err != nil && p.opt.withRetry {
scanLogin := SacnLogin{}
@ -127,7 +169,7 @@ func (p PushLogin) Login(bot *Bot) error {
return err
}
func (p PushLogin) login(bot *Bot) error {
func (p *PushLogin) login(bot *Bot) error {
if err := p.pushLoginInit(bot); err != nil {
return err
}
@ -141,13 +183,13 @@ func (p PushLogin) login(bot *Bot) error {
return p.checkLogin(bot, resp.UUID)
}
func (p PushLogin) pushLoginInit(bot *Bot) error {
func (p *PushLogin) pushLoginInit(bot *Bot) error {
bot.hotReloadStorage = p.storage
return bot.reload()
}
// checkLogin 登录检查
func (p PushLogin) checkLogin(bot *Bot, uuid string) error {
func (p *PushLogin) checkLogin(bot *Bot, uuid string) error {
bot.uuid = uuid
loginChecker := &LoginChecker{
Bot: bot,

View File

@ -3,6 +3,7 @@ package openwechat
import (
"io"
"os"
"time"
)
// Storage 身份信息, 维持整个登陆的Session会话
@ -75,3 +76,30 @@ func NewJsonFileHotReloadStorage(filename string) io.ReadWriteCloser {
}
var _ HotReloadStorage = (*jsonFileHotReloadStorage)(nil)
type HotReloadStorageSyncer struct {
duration time.Duration
bot *Bot
}
// Sync 定时同步数据到登陆存储中
func (h *HotReloadStorageSyncer) Sync() error {
// 定时器
ticker := time.NewTicker(h.duration)
for {
select {
case <-ticker.C:
// 每隔一段时间, 将数据同步到storage中
if err := h.bot.DumpHotReloadStorage(); err != nil {
return err
}
case <-h.bot.Context().Done():
// 当Bot关闭的时候, 退出循环
return nil
}
}
}
func NewHotReloadStorageSyncer(bot *Bot, duration time.Duration) *HotReloadStorageSyncer {
return &HotReloadStorageSyncer{duration: duration, bot: bot}
}