From 87036e2c9479f2c817f3a1b16d3a5a1160c24704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=9A=E5=90=83=E7=82=B9=E8=8B=B9=E6=9E=9C?= <73388495+eatmoreapple@users.noreply.github.com> Date: Tue, 10 Jan 2023 15:41:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AE=9A=E6=97=B6=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E6=95=B0=E6=8D=AE=E5=88=B0=E7=83=AD=E5=AD=98=E5=82=A8?= =?UTF-8?q?=E5=AE=B9=E5=99=A8=E5=8A=9F=E8=83=BD=20(#191)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot.go | 7 ++++++- bot_login.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++------ stroage.go | 28 +++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 7 deletions(-) diff --git a/bot.go b/bot.go index 5adfec6..0940540 100644 --- a/bot.go +++ b/bot.go @@ -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") diff --git a/bot_login.go b/bot_login.go index 5020e13..8dff482 100644 --- a/bot_login.go +++ b/bot_login.go @@ -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, diff --git a/stroage.go b/stroage.go index 1c7df10..0e82cee 100644 --- a/stroage.go +++ b/stroage.go @@ -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} +}