From 21fa847c4ee46a4de1ebc10d2c3665c7be0770b0 Mon Sep 17 00:00:00 2001 From: yqchilde Date: Sat, 31 Dec 2022 01:49:23 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E5=BC=80=E5=90=AF=E5=85=B3=E9=97=AD=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- engine/control/control.go | 68 +++++++++++++++++++++++++++++++++------ engine/control/rule.go | 67 +++++++++++++++++++++++++++++++++++--- 2 files changed, 122 insertions(+), 13 deletions(-) diff --git a/engine/control/control.go b/engine/control/control.go index 64bdaf86..1f4677df 100644 --- a/engine/control/control.go +++ b/engine/control/control.go @@ -1,6 +1,8 @@ package control import ( + "errors" + "github.com/yqchilde/wxbot/engine/pkg/log" ) @@ -15,7 +17,7 @@ type Control[CTX any] struct { func (manager *Manager[CTX]) NewControl(service string, o *Options[CTX]) *Control[CTX] { m := &Control[CTX]{ Service: service, - Cache: make(map[string]bool, 16), + Cache: make(map[string]bool), Options: func() Options[CTX] { if o == nil { return Options[CTX]{} @@ -56,17 +58,26 @@ func (m *Control[CTX]) Handler(gid, uid string) bool { // Enable 使插件在某个群中启用 func (m *Control[CTX]) Enable(groupID string) error { + if groupID != "all" { + if isEnable, ok := m.IsEnabledAll(true); ok { + if isEnable { + return errors.New("该插件已在全局启用") + } + return errors.New("该插件已全局禁用,如需启用请先在关闭全局禁用") + } + } + c := PluginConfig{GroupID: groupID, Enable: true} tx := m.Manager.D.Begin() - if err := tx.Table(m.Service).Where("gid = ?", groupID).Delete(&PluginConfig{}).Error; err != nil { + if err := tx.Table(m.Service).Delete(&PluginConfig{}, "gid = ?", groupID).Error; err != nil { log.Errorf("(plugin) %s enable in %s failed: %v", m.Service, groupID, err) tx.Rollback() - return err + return errors.New("启用失败") } if err := tx.Table(m.Service).Create(&c).Error; err != nil { log.Errorf("(plugin) %s enable in %s failed: %v", m.Service, groupID, err) tx.Rollback() - return err + return errors.New("启用失败") } tx.Commit() m.Manager.Lock() @@ -77,17 +88,26 @@ func (m *Control[CTX]) Enable(groupID string) error { // Disable 使插件在某个群中禁用 func (m *Control[CTX]) Disable(groupID string) error { + if groupID != "all" { + if isEnable, ok := m.IsEnabledAll(false); ok { + if isEnable { + return errors.New("该插件已在全局禁用") + } + return errors.New("该插件已全局启用,如需启用请先在关闭全局启用") + } + } + c := PluginConfig{GroupID: groupID, Enable: false} tx := m.Manager.D.Begin() - if err := tx.Table(m.Service).Where("gid = ?", groupID).Delete(&PluginConfig{}).Error; err != nil { + if err := tx.Table(m.Service).Delete(&PluginConfig{}, "gid = ?", groupID).Error; err != nil { log.Errorf("(plugin) %s disable in %s failed: %v", m.Service, groupID, err) tx.Rollback() - return err + return errors.New("禁用失败") } if err := tx.Table(m.Service).Create(&c).Error; err != nil { log.Errorf("(plugin) %s disable in %s failed: %v", m.Service, groupID, err) tx.Rollback() - return err + return errors.New("禁用失败") } tx.Commit() m.Manager.Lock() @@ -96,6 +116,18 @@ func (m *Control[CTX]) Disable(groupID string) error { return nil } +// CloseGlobalMode 关闭全局模式 +func (m *Control[CTX]) CloseGlobalMode() error { + if err := m.Manager.D.Table(m.Service).Delete(&PluginConfig{}, "gid = ?", "all").Error; err != nil { + log.Errorf("(plugin) %s close global failed: %v", m.Service, err) + return errors.New("关闭失败") + } + m.Manager.Lock() + delete(m.Cache, "all") + m.Manager.Unlock() + return nil +} + // IsEnabledIn 查询开启群组 func (m *Control[CTX]) IsEnabledIn(gid string) bool { m.Manager.RLock() @@ -113,13 +145,31 @@ func (m *Control[CTX]) IsEnabledIn(gid string) bool { m.Manager.Lock() defer m.Manager.Unlock() var c PluginConfig - if m.Manager.D.Table(m.Service).Where("gid = ?", "all").First(&c).Error == nil { + if m.Manager.D.Table(m.Service).First(&c, "gid = ?", "all").Error == nil { m.Cache["all"] = c.Enable return c.Enable } - if m.Manager.D.Table(m.Service).Where("gid = ?", gid).First(&c).Error == nil { + if m.Manager.D.Table(m.Service).First(&c, "gid = ?", "all").Error == nil { m.Cache[gid] = c.Enable return c.Enable } return !m.Options.DisableOnDefault } + +// IsEnabledAll 查询是否全局开启 +func (m *Control[CTX]) IsEnabledAll(enable bool) (isEnable bool, ok bool) { + m.Manager.RLock() + isEnable, ok = m.Cache["all"] + m.Manager.RUnlock() + if ok { + return isEnable == enable, ok + } + m.Manager.Lock() + defer m.Manager.Unlock() + var c PluginConfig + if m.Manager.D.Table(m.Service).First(&c, "gid = ?", "all").Error == nil { + m.Cache["all"] = c.Enable + return c.Enable == enable, ok + } + return false, ok +} diff --git a/engine/control/rule.go b/engine/control/rule.go index b4909716..ef35dca2 100644 --- a/engine/control/rule.go +++ b/engine/control/rule.go @@ -21,6 +21,7 @@ func newControl(service string, o *Options[*robot.Ctx]) robot.Rule { func init() { once.Do(func() { + // 启用、禁用某个插件在某个群或某个私聊 robot.OnCommandGroup([]string{"启用", "禁用"}, robot.UserOrGroupAdmin).SetBlock(true).FirstPriority().Handle(func(ctx *robot.Ctx) { args := ctx.State["args"].(string) if args == "" { @@ -34,8 +35,8 @@ func init() { grp := ctx.Event.FromUniqueID switch ctx.State["command"].(string) { case "启用": - if service.Enable(grp) != nil { - ctx.ReplyText("启用失败") + if err := service.Enable(grp); err != nil { + ctx.ReplyText(err.Error()) return } if service.Options.OnEnable != nil { @@ -44,8 +45,8 @@ func init() { ctx.ReplyText("启用成功") } case "禁用": - if service.Disable(grp) != nil { - ctx.ReplyText("禁用失败") + if err := service.Disable(grp); err != nil { + ctx.ReplyText(err.Error()) return } if service.Options.OnDisable != nil { @@ -55,5 +56,63 @@ func init() { } } }) + + // todo 启用、禁用全部插件在某个群或某个私聊 + robot.OnCommandGroup([]string{"启用全部", "禁用全部"}, robot.UserOrGroupAdmin).SetBlock(true).FirstPriority().Handle(func(ctx *robot.Ctx) { + }) + + // 启用、禁用某个插件在所有群和所有私聊 + robot.OnCommandGroup([]string{"全局启用", "全局禁用"}, robot.UserOrGroupAdmin).SetBlock(true).FirstPriority().Handle(func(ctx *robot.Ctx) { + args := ctx.State["args"].(string) + if args == "" { + return + } + service, ok := managers.Lookup(args) + if !ok { + ctx.ReplyTextAndAt("没有找到对应插件服务") + return + } + switch ctx.State["command"].(string) { + case "全局启用": + if service.Enable("all") != nil { + ctx.ReplyText("全局启用失败") + return + } + if service.Options.OnEnable != nil { + service.Options.OnEnable(ctx) + } else { + ctx.ReplyText("全局启用成功") + } + case "全局禁用": + if service.Disable("all") != nil { + ctx.ReplyText("全局禁用失败") + return + } + if service.Options.OnDisable != nil { + service.Options.OnDisable(ctx) + } else { + ctx.ReplyText("全局禁用成功") + } + } + }) + + // 开启、关闭某个插件的全局模式 + robot.OnCommand("关闭全局模式", robot.UserOrGroupAdmin).SetBlock(true).FirstPriority().Handle(func(ctx *robot.Ctx) { + args := ctx.State["args"].(string) + if args == "" { + return + } + service, ok := managers.Lookup(args) + if !ok { + ctx.ReplyTextAndAt("没有找到对应插件服务") + return + } + if err := service.CloseGlobalMode(); err != nil { + ctx.ReplyText(err.Error()) + return + } else { + ctx.ReplyText("关闭全局模式成功") + } + }) }) }