From 4546c2cb9f9e12e085712a4fc242c076ae6bcfb4 Mon Sep 17 00:00:00 2001 From: fumiama Date: Wed, 12 Jan 2022 11:28:58 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=9A=20=20move=20zbpctrl=20in?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- control/README.md | 2 + control/cd.go | 94 ++++++++ control/cd_test.go | 19 ++ control/register.go | 31 +++ control/rule.go | 502 +++++++++++++++++++++++++++++++++++++++ control/tables.go | 19 ++ control/web/gui.go | 561 ++++++++++++++++++++++++++++++++++++++++++++ go.mod | 16 ++ go.sum | 74 +++--- 9 files changed, 1288 insertions(+), 30 deletions(-) create mode 100644 control/README.md create mode 100644 control/cd.go create mode 100644 control/cd_test.go create mode 100644 control/register.go create mode 100644 control/rule.go create mode 100644 control/tables.go create mode 100644 control/web/gui.go diff --git a/control/README.md b/control/README.md new file mode 100644 index 0000000..16b864f --- /dev/null +++ b/control/README.md @@ -0,0 +1,2 @@ +# zbpctrl +ZeroBot-Plugin 的控制库 diff --git a/control/cd.go b/control/cd.go new file mode 100644 index 0000000..f53ff24 --- /dev/null +++ b/control/cd.go @@ -0,0 +1,94 @@ +package control + +import ( + "encoding/binary" + "strings" + "time" + + b14 "github.com/fumiama/go-base16384" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" + "github.com/wdvxdr1123/ZeroBot/utils/helper" + + "github.com/FloatTech/zbputils/math" + "github.com/FloatTech/zbputils/process" +) + +var startTime int64 + +func init() { + // 插件冲突检测 会在本群发送一条消息并在约 1s 后撤回 + zero.OnFullMatch("插件冲突检测", zero.OnlyGroup, zero.AdminPermission, zero.OnlyToMe).SetBlock(true).FirstPriority(). + Handle(func(ctx *zero.Ctx) { + tok, err := genToken() + if err != nil { + return + } + t := message.Text("●cd" + tok) + startTime = time.Now().Unix() + id := ctx.SendChain(t) + process.SleepAbout1sTo2s() + ctx.DeleteMessage(id) + }) + + zero.OnRegex("^●cd([\u4e00-\u8e00]{4})$", zero.OnlyGroup).SetBlock(true).FirstPriority(). + Handle(func(ctx *zero.Ctx) { + if isValidToken(ctx.State["regex_matched"].([]string)[1]) { + msg := "" + gid := ctx.Event.GroupID + ForEach(func(key string, manager *Control) bool { + if manager.IsEnabledIn(gid) { + msg += "\xfe\xff" + key + } + return true + }) + if len(msg) > 2 { + my, err := b14.UTF16be2utf8(b14.EncodeString(msg[2:])) + mys := "●cd●" + helper.BytesToString(my) + if err == nil { + id := ctx.SendChain(message.Text(mys)) + process.SleepAbout1sTo2s() + ctx.DeleteMessage(id) + } + } + } + }) + + zero.OnRegex("^●cd●(([\u4e00-\u8e00]*[\u3d01-\u3d06]?))", zero.OnlyGroup).SetBlock(true).FirstPriority(). + Handle(func(ctx *zero.Ctx) { + if time.Now().Unix()-startTime < 10 { + msg, err := b14.UTF82utf16be(helper.StringToBytes(ctx.State["regex_matched"].([]string)[1])) + if err == nil { + gid := ctx.Event.GroupID + for _, s := range strings.Split(b14.DecodeString(msg), "\xfe\xff") { + mu.RLock() + c, ok := managers[s] + mu.RUnlock() + if ok && c.IsEnabledIn(gid) { + c.Disable(gid) + } + } + } + } + }) +} + +func genToken() (tok string, err error) { + timebytes := make([]byte, 8) + binary.BigEndian.PutUint64(timebytes, uint64(time.Now().Unix())) + timebytes, err = b14.UTF16be2utf8(b14.Encode(timebytes[1:])) + if err == nil { + tok = helper.BytesToString(timebytes) + } + return +} + +func isValidToken(tok string) (yes bool) { + s, err := b14.UTF82utf16be(helper.StringToBytes(tok)) + if err == nil { + timebytes := make([]byte, 1, 8) + timebytes = append(timebytes, b14.Decode(s)...) + yes = math.Abs64(time.Now().Unix()-int64(binary.BigEndian.Uint64(timebytes))) < 10 + } + return +} diff --git a/control/cd_test.go b/control/cd_test.go new file mode 100644 index 0000000..6a238d4 --- /dev/null +++ b/control/cd_test.go @@ -0,0 +1,19 @@ +package control + +import "testing" + +func TestGenToken(t *testing.T) { + tok, err := genToken() + if err == nil { + t.Log(tok) + t.Log(isValidToken(tok)) + t.Fail() + } else { + t.Fatal(err) + } +} + +func TestMaru(t *testing.T) { + t.Log(len("\xff")) + t.Fail() +} diff --git a/control/register.go b/control/register.go new file mode 100644 index 0000000..1aafad2 --- /dev/null +++ b/control/register.go @@ -0,0 +1,31 @@ +package control + +import ( + zero "github.com/wdvxdr1123/ZeroBot" +) + +var enmap = make(map[string]*zero.Engine) + +// Register 注册插件控制器 +func Register(service string, o *Options) *zero.Engine { + engine := zero.New() + engine.UsePreHandler(newctrl(service, o).Handler) + enmap[service] = engine + return engine +} + +// Delete 删除插件控制器,不会删除数据 +func Delete(service string) { + engine, ok := enmap[service] + if ok { + engine.Delete() + mu.RLock() + _, ok = managers[service] + mu.RUnlock() + if ok { + mu.Lock() + delete(managers, service) + mu.Unlock() + } + } +} diff --git a/control/rule.go b/control/rule.go new file mode 100644 index 0000000..450911b --- /dev/null +++ b/control/rule.go @@ -0,0 +1,502 @@ +// Package control 控制插件的启用与优先级等 +package control + +import ( + "crypto/md5" + "encoding/binary" + "fmt" + "os" + "strconv" + "strings" + "sync" + + log "github.com/sirupsen/logrus" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/extension" + "github.com/wdvxdr1123/ZeroBot/message" + "github.com/wdvxdr1123/ZeroBot/utils/helper" + + "github.com/FloatTech/zbputils/sql" + "github.com/FloatTech/zbputils/txt2img" +) + +var ( + db = &sql.Sqlite{DBPath: "data/control/plugins.db"} + // managers 每个插件对应的管理 + managers = map[string]*Control{} + mu = sync.RWMutex{} + hasinit bool +) + +// Control is to control the plugins. +type Control struct { + sync.RWMutex + service string + options Options +} + +// newctrl returns Manager with settings. +func newctrl(service string, o *Options) *Control { + m := &Control{service: service, + options: func() Options { + if o == nil { + return Options{} + } + return *o + }(), + } + mu.Lock() + managers[service] = m + mu.Unlock() + err := db.Create(service, &grpcfg{}) + if err != nil { + panic(err) + } + err = db.Create(service+"ban", &ban{}) + if err != nil { + panic(err) + } + return m +} + +// Enable enables a group to pass the Manager. +// groupID == 0 (ALL) will operate on all grps. +func (m *Control) Enable(groupID int64) { + var c grpcfg + m.RLock() + err := db.Find(m.service, &c, "WHERE gid = "+strconv.FormatInt(groupID, 10)) + m.RUnlock() + if err != nil { + c.GroupID = groupID + } + c.Disable = int64(uint64(c.Disable) & 0xffffffff_fffffffe) + m.Lock() + err = db.Insert(m.service, &c) + m.Unlock() + if err != nil { + log.Errorf("[control] %v", err) + } +} + +// Disable disables a group to pass the Manager. +// groupID == 0 (ALL) will operate on all grps. +func (m *Control) Disable(groupID int64) { + var c grpcfg + m.RLock() + err := db.Find(m.service, &c, "WHERE gid = "+strconv.FormatInt(groupID, 10)) + m.RUnlock() + if err != nil { + c.GroupID = groupID + } + c.Disable |= 1 + m.Lock() + err = db.Insert(m.service, &c) + m.Unlock() + if err != nil { + log.Errorf("[control] %v", err) + } +} + +// Reset resets the default config of a group. +// groupID == 0 (ALL) is not allowed. +func (m *Control) Reset(groupID int64) { + if groupID != 0 { + m.Lock() + err := db.Del(m.service, "WHERE gid = "+strconv.FormatInt(groupID, 10)) + m.Unlock() + if err != nil { + log.Errorf("[control] %v", err) + } + } +} + +// IsEnabledIn 开启群 +func (m *Control) IsEnabledIn(gid int64) bool { + var c grpcfg + var err error + log.Debugln("[control] IsEnabledIn recv gid =", gid) + if gid != 0 { + m.RLock() + err = db.Find(m.service, &c, "WHERE gid = "+strconv.FormatInt(gid, 10)) + m.RUnlock() + if err == nil && gid == c.GroupID { + log.Debugf("[control] plugin %s of grp %d : %d", m.service, c.GroupID, c.Disable&1) + return c.Disable&1 == 0 + } + } + m.RLock() + err = db.Find(m.service, &c, "WHERE gid = 0") + m.RUnlock() + if err == nil && c.GroupID == 0 { + log.Debugf("[control] plugin %s of all : %d", m.service, c.Disable&1) + return c.Disable&1 == 0 + } + return !m.options.DisableOnDefault +} + +// Ban 禁止某人在某群使用本插件 +func (m *Control) Ban(uid, gid int64) { + var err error + var digest [16]byte + log.Debugln("[control] Ban recv gid =", gid, "uid =", uid) + if gid != 0 { // 特定群 + digest = md5.Sum(helper.StringToBytes(fmt.Sprintf("%d_%d", uid, gid))) + m.RLock() + err = db.Insert(m.service+"ban", &ban{ID: int64(binary.LittleEndian.Uint64(digest[:8])), UserID: uid, GroupID: gid}) + m.RUnlock() + if err == nil { + log.Debugf("[control] plugin %s is banned in grp %d for usr %d.", m.service, gid, uid) + return + } + } + // 所有群 + digest = md5.Sum(helper.StringToBytes(fmt.Sprintf("%d_all", uid))) + m.RLock() + err = db.Insert(m.service+"ban", &ban{ID: int64(binary.LittleEndian.Uint64(digest[:8])), UserID: uid, GroupID: 0}) + m.RUnlock() + if err == nil { + log.Debugf("[control] plugin %s is banned in all grp for usr %d.", m.service, uid) + } +} + +// Permit 允许某人在某群使用本插件 +func (m *Control) Permit(uid, gid int64) { + var digest [16]byte + log.Debugln("[control] Permit recv gid =", gid, "uid =", uid) + if gid != 0 { // 特定群 + digest = md5.Sum(helper.StringToBytes(fmt.Sprintf("%d_%d", uid, gid))) + m.RLock() + _ = db.Del(m.service+"ban", "WHERE id = "+strconv.FormatInt(int64(binary.LittleEndian.Uint64(digest[:8])), 10)) + m.RUnlock() + log.Debugf("[control] plugin %s is permitted in grp %d for usr %d.", m.service, gid, uid) + return + } + // 所有群 + digest = md5.Sum(helper.StringToBytes(fmt.Sprintf("%d_all", uid))) + m.RLock() + _ = db.Del(m.service+"ban", "WHERE id = "+strconv.FormatInt(int64(binary.LittleEndian.Uint64(digest[:8])), 10)) + m.RUnlock() + log.Debugf("[control] plugin %s is permitted in all grp for usr %d.", m.service, uid) +} + +// IsBannedIn 某人是否在某群被 ban +func (m *Control) IsBannedIn(uid, gid int64) bool { + var b ban + var err error + var digest [16]byte + log.Debugln("[control] IsBannedIn recv gid =", gid, "uid =", uid) + if gid != 0 { + digest = md5.Sum(helper.StringToBytes(fmt.Sprintf("%d_%d", uid, gid))) + m.RLock() + err = db.Find(m.service+"ban", &b, "WHERE id = "+strconv.FormatInt(int64(binary.LittleEndian.Uint64(digest[:8])), 10)) + m.RUnlock() + if err == nil && gid == b.GroupID && uid == b.UserID { + log.Debugf("[control] plugin %s is banned in grp %d for usr %d.", m.service, b.GroupID, b.UserID) + return true + } + } + digest = md5.Sum(helper.StringToBytes(fmt.Sprintf("%d_all", uid))) + m.RLock() + err = db.Find(m.service+"ban", &b, "WHERE id = "+strconv.FormatInt(int64(binary.LittleEndian.Uint64(digest[:8])), 10)) + m.RUnlock() + if err == nil && b.GroupID == 0 && uid == b.UserID { + log.Debugf("[control] plugin %s is banned in all grp for usr %d.", m.service, b.UserID) + return true + } + return false +} + +// GetData 获取某个群的 63 字节配置信息 +func (m *Control) GetData(gid int64) int64 { + var c grpcfg + var err error + log.Debugln("[control] IsEnabledIn recv gid =", gid) + m.RLock() + err = db.Find(m.service, &c, "WHERE gid = "+strconv.FormatInt(gid, 10)) + m.RUnlock() + if err == nil && gid == c.GroupID { + log.Debugf("[control] plugin %s of grp %d : 0x%x", m.service, c.GroupID, c.Disable>>1) + return c.Disable >> 1 + } + return 0 +} + +// SetData 为某个群设置低 63 位配置数据 +func (m *Control) SetData(groupID int64, data int64) error { + var c grpcfg + m.RLock() + err := db.Find(m.service, &c, "WHERE gid = "+strconv.FormatInt(groupID, 10)) + m.RUnlock() + if err != nil { + c.GroupID = groupID + if m.options.DisableOnDefault { + c.Disable = 1 + } + } + c.Disable &= 1 + c.Disable |= data << 1 + log.Debugf("[control] set plugin %s of grp %d : 0x%x", m.service, c.GroupID, data) + m.Lock() + err = db.Insert(m.service, &c) + m.Unlock() + if err != nil { + log.Errorf("[control] %v", err) + } + return err +} + +// Handler 返回 预处理器 +func (m *Control) Handler(ctx *zero.Ctx) bool { + ctx.State["manager"] = m + grp := ctx.Event.GroupID + if grp == 0 { + // 个人用户 + return m.IsEnabledIn(-ctx.Event.UserID) + } + log.Debugln("[control] handler get gid =", grp) + return m.IsEnabledIn(grp) && !m.IsBannedIn(ctx.Event.UserID, grp) +} + +// Lookup returns a Manager by the service name, if +// not exist, it will return nil. +func Lookup(service string) (*Control, bool) { + mu.RLock() + m, ok := managers[service] + mu.RUnlock() + return m, ok +} + +// ForEach iterates through managers. +func ForEach(iterator func(key string, manager *Control) bool) { + mu.RLock() + m := copyMap(managers) + mu.RUnlock() + for k, v := range m { + if !iterator(k, v) { + return + } + } +} + +func copyMap(m map[string]*Control) map[string]*Control { + ret := make(map[string]*Control, len(m)) + for k, v := range m { + ret[k] = v + } + return ret +} + +func userOrGrpAdmin(ctx *zero.Ctx) bool { + if zero.OnlyGroup(ctx) { + return zero.AdminPermission(ctx) + } + return zero.OnlyToMe(ctx) +} + +func init() { + if !hasinit { + mu.Lock() + if !hasinit { + err := os.MkdirAll("data/control", 0755) + if err != nil { + panic(err) + } else { + hasinit = true + zero.OnCommandGroup([]string{ + "启用", "enable", "禁用", "disable", + }, userOrGrpAdmin).SetBlock(true).FirstPriority().Handle(func(ctx *zero.Ctx) { + model := extension.CommandModel{} + _ = ctx.Parse(&model) + service, ok := Lookup(model.Args) + if !ok { + ctx.SendChain(message.Text("没有找到指定服务!")) + return + } + grp := ctx.Event.GroupID + if grp == 0 { + // 个人用户 + grp = -ctx.Event.UserID + } + if strings.Contains(model.Command, "启用") || strings.Contains(model.Command, "enable") { + service.Enable(grp) + ctx.SendChain(message.Text("已启用服务: " + model.Args)) + } else { + service.Disable(grp) + ctx.SendChain(message.Text("已禁用服务: " + model.Args)) + } + }) + + zero.OnCommandGroup([]string{ + "全局启用", "enableall", "全局禁用", "disableall", + }, zero.OnlyToMe, zero.SuperUserPermission).SetBlock(true).FirstPriority().Handle(func(ctx *zero.Ctx) { + model := extension.CommandModel{} + _ = ctx.Parse(&model) + service, ok := Lookup(model.Args) + if !ok { + ctx.SendChain(message.Text("没有找到指定服务!")) + return + } + if strings.Contains(model.Command, "启用") || strings.Contains(model.Command, "enable") { + service.Enable(0) + ctx.SendChain(message.Text("已全局启用服务: " + model.Args)) + } else { + service.Disable(0) + ctx.SendChain(message.Text("已全局禁用服务: " + model.Args)) + } + }) + + zero.OnCommandGroup([]string{"还原", "reset"}, userOrGrpAdmin).SetBlock(true).FirstPriority().Handle(func(ctx *zero.Ctx) { + model := extension.CommandModel{} + _ = ctx.Parse(&model) + service, ok := Lookup(model.Args) + if !ok { + ctx.SendChain(message.Text("没有找到指定服务!")) + return + } + grp := ctx.Event.GroupID + if grp == 0 { + // 个人用户 + grp = -ctx.Event.UserID + } + service.Reset(grp) + ctx.SendChain(message.Text("已还原服务的默认启用状态: " + model.Args)) + }) + + zero.OnCommandGroup([]string{ + "禁止", "ban", "允许", "permit", + }, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).FirstPriority().Handle(func(ctx *zero.Ctx) { + model := extension.CommandModel{} + _ = ctx.Parse(&model) + args := strings.Split(model.Args, " ") + if len(args) >= 2 { + service, ok := Lookup(args[0]) + if !ok { + ctx.SendChain(message.Text("没有找到指定服务!")) + return + } + grp := ctx.Event.GroupID + msg := "**" + args[0] + "报告**" + if strings.Contains(model.Command, "允许") || strings.Contains(model.Command, "permit") { + for _, usr := range args[1:] { + uid, err := strconv.ParseInt(usr, 10, 64) + if err == nil { + service.Permit(uid, grp) + msg += "\n+ 已允许" + usr + } + } + } else { + for _, usr := range args[1:] { + uid, err := strconv.ParseInt(usr, 10, 64) + if err == nil { + service.Ban(uid, grp) + msg += "\n- 已禁止" + usr + } + } + } + ctx.SendChain(message.Text(msg)) + return + } + ctx.SendChain(message.Text("参数错误!")) + }) + + zero.OnCommandGroup([]string{ + "全局禁止", "banall", "全局允许", "permitall", + }, zero.OnlyGroup, zero.SuperUserPermission).SetBlock(true).FirstPriority().Handle(func(ctx *zero.Ctx) { + model := extension.CommandModel{} + _ = ctx.Parse(&model) + args := strings.Split(model.Args, " ") + if len(args) >= 2 { + service, ok := Lookup(args[0]) + if !ok { + ctx.SendChain(message.Text("没有找到指定服务!")) + return + } + msg := "**" + args[0] + "全局报告**" + if strings.Contains(model.Command, "允许") || strings.Contains(model.Command, "permit") { + for _, usr := range args[1:] { + uid, err := strconv.ParseInt(usr, 10, 64) + if err == nil { + service.Permit(uid, 0) + msg += "\n+ 已允许" + usr + } + } + } else { + for _, usr := range args[1:] { + uid, err := strconv.ParseInt(usr, 10, 64) + if err == nil { + service.Ban(uid, 0) + msg += "\n- 已禁止" + usr + } + } + } + ctx.SendChain(message.Text(msg)) + return + } + ctx.SendChain(message.Text("参数错误!")) + }) + + zero.OnCommandGroup([]string{"用法", "usage"}, userOrGrpAdmin).SetBlock(true).FirstPriority(). + Handle(func(ctx *zero.Ctx) { + model := extension.CommandModel{} + _ = ctx.Parse(&model) + service, ok := Lookup(model.Args) + if !ok { + ctx.SendChain(message.Text("没有找到指定服务!")) + return + } + if service.options.Help != "" { + ctx.SendChain(message.Text(service.options.Help)) + } else { + ctx.SendChain(message.Text("该服务无帮助!")) + } + }) + + zero.OnCommandGroup([]string{"服务列表", "service_list"}, userOrGrpAdmin).SetBlock(true).FirstPriority(). + Handle(func(ctx *zero.Ctx) { + msg := "--------服务列表--------\n发送\"/用法 name\"查看详情" + i := 0 + gid := ctx.Event.GroupID + ForEach(func(key string, manager *Control) bool { + i++ + msg += "\n" + strconv.Itoa(i) + `: ` + if manager.IsEnabledIn(gid) { + msg += "●" + key + } else { + msg += "○" + key + } + return true + }) + ctx.SendChain(message.Text(msg)) + }) + + zero.OnCommandGroup([]string{"服务详情", "service_detail"}, userOrGrpAdmin).SetBlock(true).FirstPriority(). + Handle(func(ctx *zero.Ctx) { + text := "---服务详情---\n" + i := 0 + ForEach(func(key string, manager *Control) bool { + service, _ := Lookup(key) + help := service.options.Help + i++ + msg := strconv.Itoa(i) + `: ` + if manager.IsEnabledIn(ctx.Event.GroupID) { + msg += "●" + key + } else { + msg += "○" + key + } + msg += "\n" + help + text += msg + "\n\n" + return true + }) + data, err := txt2img.RenderToBase64(text, 40, 20) + if err != nil { + log.Errorf("[control] %v", err) + } + if id := ctx.SendChain(message.Image("base64://" + helper.BytesToString(data))); id == 0 { + ctx.SendChain(message.Text("ERROR: 可能被风控了")) + } + }) + } + } + mu.Unlock() + } +} diff --git a/control/tables.go b/control/tables.go new file mode 100644 index 0000000..6914b34 --- /dev/null +++ b/control/tables.go @@ -0,0 +1,19 @@ +package control + +// grpcfg holds the group config for the Manager. +type grpcfg struct { + GroupID int64 `db:"gid"` // GroupID 群号 + Disable int64 `db:"disable"` // Disable 默认启用该插件 +} + +type ban struct { + ID int64 `db:"id"` + UserID int64 `db:"uid"` + GroupID int64 `db:"gid"` +} + +// Options holds the optional parameters for the Manager. +type Options struct { + DisableOnDefault bool + Help string // 帮助文本信息 +} diff --git a/control/web/gui.go b/control/web/gui.go new file mode 100644 index 0000000..607fc7d --- /dev/null +++ b/control/web/gui.go @@ -0,0 +1,561 @@ +// Package webctrl 包含 webui 所需的所有内容 +package webctrl + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "strconv" + "sync" + + manager "github.com/FloatTech/bot-manager" + // 依赖gin监听server + "github.com/gin-gonic/gin" + "github.com/gorilla/websocket" + + // 前端静态文件 + log "github.com/sirupsen/logrus" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" + + ctrl "github.com/FloatTech/zbputils/control" +) + +var ( + // 向前端推送消息的ws链接 + conn *websocket.Conn + // 向前端推送日志的ws链接 + logConn *websocket.Conn + + l logWriter + // 存储请求事件,flag作为键,一个request对象作为值 + requestData sync.Map +) + +// logWriter +// @Description: +// +type logWriter struct { +} + +// request +// @Description: 一个请求事件的结构体 +// +type request struct { + RequestType string `json:"request_type"` + SubType string `json:"sub_type"` + Type string `json:"type"` + Comment string `json:"comment"` + GroupID int64 `json:"group_id"` + UserID int64 `json:"user_id"` + Flag string `json:"flag"` + SelfID int64 `json:"self_id"` +} + +// InitGui 初始化gui +func InitGui(addr string) { + // 将日志重定向到前端hook + writer := io.MultiWriter(l, os.Stdout) + log.SetOutput(writer) + // 监听后端 + go controller(addr) + // 注册消息handle + messageHandle() +} + +// websocket的协议升级 +var upGrader = websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { + return true + }, +} + +func controller(addr string) { + defer func() { + err := recover() + if err != nil { + log.Errorln("[gui]" + "bot-manager出现不可恢复的错误") + log.Errorln("[gui]", err) + } + }() + + engine := gin.New() + // 支持跨域 + engine.Use(cors()) + // 注册静态文件 + engine.StaticFS("/dist", http.FS(manager.Dist)) + engine.POST("/get_bots", getBots) + engine.POST("/get_group_list", getGroupList) + engine.POST("/get_friend_list", getFriendList) + // 注册主路径路由,使其跳转到主页面 + engine.GET("/", func(context *gin.Context) { + context.Redirect(http.StatusMovedPermanently, "/dist/dist/default.html") + }) + // 更改某个插件状态 + engine.POST("/update_plugin_status", updatePluginStatus) + // 更改某一个插件在所有群的状态 + engine.POST("/update_plugin_all_group_status", updatePluginAllGroupStatus) + // 更改所有插件状态 + engine.POST("/update_all_plugin_status", updateAllPluginStatus) + // 获取所有插件状态 + engine.POST("/get_plugins_status", getPluginsStatus) + // 获取一个插件状态 + engine.POST("/get_plugin_status", getPluginStatus) + // 获取插件列表 + engine.POST("/get_plugins", func(context *gin.Context) { + var datas []map[string]interface{} + ctrl.ForEach(func(key string, manager *ctrl.Control) bool { + datas = append(datas, map[string]interface{}{"id": 1, "handle_type": "", "name": key, "enable": manager.IsEnabledIn(0)}) + return true + }) + context.JSON(200, datas) + }) + // 获取所有请求 + engine.POST("/get_requests", getRequests) + // 执行一个请求事件 + engine.POST("handle_request", handelRequest) + // 链接日志 + engine.GET("/get_log", getLogs) + // 获取前端标签 + engine.GET("/get_label", func(context *gin.Context) { + context.JSON(200, "ZeroBot-Plugin") + }) + + // 发送信息 + engine.POST("/send_msg", sendMsg) + engine.GET("/data", upgrade) + log.Infoln("[gui] the webui is running on", addr) + log.Infoln("[gui] ", "you input the `ZeroBot-Plugin.exe -g` can disable the gui") + if err := engine.Run(addr); err != nil { + log.Debugln("[gui] ", err.Error()) + } +} + +// handelRequest +/** + * @Description: 处理一个请求 + * @param context + */ +func handelRequest(context *gin.Context) { + var data map[string]interface{} + err := context.BindJSON(&data) + if err != nil { + context.JSON(404, nil) + return + } + r, ok := requestData.LoadAndDelete(data["flag"].(string)) + if !ok { + context.JSON(404, "flag not found") + } + r2 := r.(*request) + r2.handle(data["approve"].(bool), data["reason"].(string)) + context.JSON(200, "操作成功") +} + +// getRequests +/** + * @Description: 获取所有的请求 + * @param context + */ +func getRequests(context *gin.Context) { + var data []interface{} + requestData.Range(func(key, value interface{}) bool { + data = append(data, value) + return true + }) + context.JSON(200, data) +} + +// updateAllPluginStatus +/** + * @Description: 改变所有插件的状态 + * @param context + * example + */ +func updateAllPluginStatus(context *gin.Context) { + enable, err := strconv.ParseBool(context.PostForm("enable")) + if err != nil { + var parse map[string]interface{} + err := context.BindJSON(&parse) + if err != nil { + log.Errorln("[gui] " + err.Error()) + return + } + enable = parse["enable"].(bool) + } + ctrl.ForEach(func(key string, manager *ctrl.Control) bool { + if enable { + manager.Enable(0) + } else { + manager.Disable(0) + } + return true + }) + context.JSON(200, nil) +} + +// updatePluginAllGroupStatus +/** + * @Description: 改变插件在所有群的状态 + * @param context + * example + */ +func updatePluginAllGroupStatus(context *gin.Context) { + name := context.PostForm("name") + enable, err := strconv.ParseBool(context.PostForm("enable")) + if err != nil { + var parse map[string]interface{} + err := context.BindJSON(&parse) + if err != nil { + log.Errorln("[gui]" + err.Error()) + return + } + name = parse["name"].(string) + enable = parse["enable"].(bool) + } + control, b := ctrl.Lookup(name) + if !b { + context.JSON(404, nil) + return + } + if enable { + control.Enable(0) + } else { + control.Disable(0) + } + context.JSON(200, nil) +} + +// updatePluginStatus +/** + * @Description: 更改某一个插件状态 + * @param context + * example + */ +func updatePluginStatus(context *gin.Context) { + var parse map[string]interface{} + err := context.BindJSON(&parse) + if err != nil { + log.Errorln("[gui] ", err) + return + } + groupID := int64(parse["group_id"].(float64)) + name := parse["name"].(string) + enable := parse["enable"].(bool) + fmt.Println(name) + control, b := ctrl.Lookup(name) + if !b { + context.JSON(404, "服务不存在") + return + } + if enable { + control.Enable(groupID) + } else { + control.Disable(groupID) + } + context.JSON(200, nil) +} + +// getPluginStatus +/** + * @Description: 获取一个插件的状态 + * @param context + * example + */ +func getPluginStatus(context *gin.Context) { + groupID, err := strconv.ParseInt(context.PostForm("group_id"), 10, 64) + name := context.PostForm("name") + if err != nil { + var parse map[string]interface{} + err := context.BindJSON(&parse) + if err != nil { + log.Errorln("[gui]" + err.Error()) + return + } + groupID = int64(parse["group_id"].(float64)) + name = parse["name"].(string) + } + control, b := ctrl.Lookup(name) + if !b { + context.JSON(404, "服务不存在") + return + } + context.JSON(200, gin.H{"enable": control.IsEnabledIn(groupID)}) +} + +// getPluginsStatus +/** + * @Description: 获取所有插件的状态 + * @param context + * example + */ +func getPluginsStatus(context *gin.Context) { + groupID, err := strconv.ParseInt(context.PostForm("group_id"), 10, 64) + if err != nil { + var parse map[string]interface{} + err := context.BindJSON(&parse) + if err != nil { + log.Errorln("[gui]" + err.Error()) + return + } + groupID = int64(parse["group_id"].(float64)) + } + var datas []map[string]interface{} + ctrl.ForEach(func(key string, manager *ctrl.Control) bool { + enable := manager.IsEnabledIn(groupID) + datas = append(datas, map[string]interface{}{"name": key, "enable": enable}) + return true + }) + context.JSON(200, datas) +} + +// getLogs +/** + * @Description: 连接日志 + * @param context + * example + */ +func getLogs(context *gin.Context) { + con1, err := upGrader.Upgrade(context.Writer, context.Request, nil) + if err != nil { + return + } + logConn = con1 +} + +// getFriendList +/** + * @Description: 获取好友列表 + * @param context + * example + */ +func getFriendList(context *gin.Context) { + selfID, err := strconv.Atoi(context.PostForm("self_id")) + if err != nil { + log.Errorln("[gui]" + err.Error()) + var data map[string]interface{} + err := context.BindJSON(&data) + if err != nil { + log.Errorln("[gui]" + err.Error()) + log.Errorln("[gui]" + "绑定错误") + return + } + selfID = int(data["self_id"].(float64)) + } + bot := zero.GetBot(int64(selfID)) + var resp []interface{} + list := bot.GetFriendList().String() + err = json.Unmarshal([]byte(list), &resp) + if err != nil { + log.Errorln("[gui]" + err.Error()) + log.Errorln("[gui]" + "解析json错误") + } + context.JSON(200, resp) +} + +// getGroupList +/** + * @Description: 获取群列表 + * @param context + * example + */ +func getGroupList(context *gin.Context) { + selfID, err := strconv.Atoi(context.PostForm("self_id")) + if err != nil { + var data map[string]interface{} + err := context.BindJSON(&data) + if err != nil { + log.Errorln("[gui]" + err.Error()) + return + } + selfID = int(data["self_id"].(float64)) + } + + bot := zero.GetBot(int64(selfID)) + var resp []interface{} + list := bot.GetGroupList().String() + err = json.Unmarshal([]byte(list), &resp) + if err != nil { + log.Errorln("[gui]" + err.Error()) + } + context.JSON(200, resp) +} + +// getBots +/** + * @Description: 获取机器人qq号 + * @param context + * example + */ +func getBots(context *gin.Context) { + var bots []int64 + + zero.RangeBot(func(id int64, ctx *zero.Ctx) bool { + bots = append(bots, id) + return true + }) + context.JSON(200, bots) +} + +// MessageHandle +/** + * @Description: 定义一个向前端发送信息的handle + * example + */ +func messageHandle() { + defer func() { + err := recover() + if err != nil { + log.Errorln("[gui]" + "bot-manager出现不可恢复的错误") + log.Errorln("[gui] ", err) + } + }() + + matcher := zero.OnMessage().SetBlock(false).SetPriority(1) + + matcher.Handle(func(ctx *zero.Ctx) { + if conn != nil { + err := conn.WriteJSON(ctx.Event) + if err != nil { + log.Debugln("[gui] " + "向发送错误") + return + } + } + }) + // 直接注册一个request请求监听器,优先级设置为最高,设置不阻断事件传播 + zero.OnRequest(func(ctx *zero.Ctx) bool { + if ctx.Event.RequestType == "friend" { + ctx.State["type_name"] = "好友添加" + } else { + if ctx.Event.SubType == "add" { + ctx.State["type_name"] = "加群请求" + } else { + ctx.State["type_name"] = "群邀请" + } + } + return true + }).SetBlock(false).FirstPriority().Handle(func(ctx *zero.Ctx) { + r := &request{ + RequestType: ctx.Event.RequestType, + SubType: ctx.Event.SubType, + Type: ctx.State["type_name"].(string), + GroupID: ctx.Event.GroupID, + UserID: ctx.Event.UserID, + Flag: ctx.Event.Flag, + Comment: ctx.Event.Comment, + SelfID: ctx.Event.SelfID, + } + requestData.Store(ctx.Event.Flag, r) + }) +} + +// upgrade +/** + * @Description: 连接ws,向前端推送message + * @param context + * example + */ +func upgrade(context *gin.Context) { + con, err := upGrader.Upgrade(context.Writer, context.Request, nil) + if err != nil { + return + } + conn = con +} + +// sendMsg +/** + * @Description: 前端调用发送信息 + * @param context + * example + */ +func sendMsg(context *gin.Context) { + var data map[string]interface{} + err := context.BindJSON(&data) + if err != nil { + context.JSON(404, nil) + return + } + selfID := int64(data["self_id"].(float64)) + id := int64(data["id"].(float64)) + message1 := data["message"].(string) + messageType := data["message_type"].(string) + + bot := zero.GetBot(selfID) + var msgID int64 + if messageType == "group" { + msgID = bot.SendGroupMessage(id, message.ParseMessageFromString(message1)) + } else { + msgID = bot.SendPrivateMessage(id, message.ParseMessageFromString(message1)) + } + context.JSON(200, msgID) +} + +// cors +/** + * @Description: 支持跨域访问 + * @return gin.HandlerFunc + * example + */ +func cors() gin.HandlerFunc { + return func(c *gin.Context) { + method := c.Request.Method + origin := c.Request.Header.Get("Origin") // 请求头部 + if origin != "" { + // 接收客户端发送的origin (重要!) + c.Writer.Header().Set("Access-Control-Allow-Origin", origin) + // 服务器支持的所有跨域请求的方法 + c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE") + // 允许跨域设置可以返回其他子段,可以自定义字段 + c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session, Content-Type") + // 允许浏览器(客户端)可以解析的头部 (重要) + c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers") + // 设置缓存时间 + c.Header("Access-Control-Max-Age", "172800") + // 允许客户端传递校验信息比如 cookie (重要) + c.Header("Access-Control-Allow-Credentials", "true") + } + + // 允许类型校验 + if method == "OPTIONS" { + c.JSON(http.StatusOK, "ok!") + } + + defer func() { + if err := recover(); err != nil { + log.Printf("Panic info is: %v", err) + } + }() + + c.Next() + } +} + +// handle +/** + * @Description: 提交一个请求 + * @receiver r + * @param approve 是否通过 + * @param reason 拒绝的理由 + */ +func (r *request) handle(approve bool, reason string) { + bot := zero.GetBot(r.SelfID) + if r.RequestType == "friend" { + bot.SetFriendAddRequest(r.Flag, approve, "") + } else { + bot.SetGroupAddRequest(r.Flag, r.SubType, approve, reason) + } + log.Debugln("[gui] ", "已处理", r.UserID, "的"+r.Type) +} + +func (l logWriter) Write(p []byte) (n int, err error) { + if logConn != nil { + err := logConn.WriteMessage(websocket.TextMessage, p) + if err != nil { + return len(p), nil + } + } + return len(p), nil +} diff --git a/go.mod b/go.mod index 5e2fe65..56e962c 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,14 @@ module github.com/FloatTech/zbputils go 1.17 require ( + github.com/FloatTech/bot-manager v1.0.0 github.com/disintegration/imaging v1.6.2 github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 github.com/fogleman/gg v1.3.0 + github.com/fumiama/go-base16384 v1.2.1 github.com/fumiama/go-registry v0.0.2 + github.com/gin-gonic/gin v1.7.7 + github.com/gorilla/websocket v1.4.2 github.com/logoove/sqlite v1.13.0 github.com/mattn/go-runewidth v0.0.13 github.com/sirupsen/logrus v1.8.1 @@ -16,21 +20,33 @@ require ( require ( github.com/fumiama/gofastTEA v0.0.6 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.13.0 // indirect + github.com/go-playground/universal-translator v0.17.0 // indirect + github.com/go-playground/validator/v10 v10.4.1 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/golang/protobuf v1.3.3 // indirect github.com/google/go-cmp v0.5.6 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/json-iterator/go v1.1.9 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/leodido/go-urn v1.2.0 // indirect github.com/mattn/go-isatty v0.0.14 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/tidwall/gjson v1.12.1 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect + github.com/ugorji/go/codec v1.1.7 // indirect + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect golang.org/x/mod v0.5.1 // indirect golang.org/x/sys v0.0.0-20220111092808-5a964db01320 // indirect golang.org/x/tools v0.1.8 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + gopkg.in/yaml.v2 v2.2.8 // indirect lukechampine.com/uint128 v1.1.1 // indirect modernc.org/cc/v3 v3.35.22 // indirect modernc.org/ccgo/v3 v3.14.0 // indirect diff --git a/go.sum b/go.sum index 70542d8..496568f 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,6 @@ +github.com/FloatTech/bot-manager v1.0.0 h1:d63J5htLhVBc2ITG09WBJI+qAB0ubPjYhfXl6hljBNk= +github.com/FloatTech/bot-manager v1.0.0/go.mod h1:8YYRJ16oroGHQGD2En0oVnmcKJkxR9O/jd5BPSfWfOQ= github.com/Mrs4s/MiraiGo v0.0.0-20211120033824-43b23f4e6fcb h1:Rkj28fqIwGx/EgBzRYtpmJRfH6wqVn7cNdc7aJ0QE4M= -github.com/Mrs4s/MiraiGo v0.0.0-20211120033824-43b23f4e6fcb/go.mod h1:imVKbfKqqeit+C/eaWGb4MKQ3z3gN6pRpBU5RMtp5so= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -12,43 +13,62 @@ github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4/go.mod h1:H github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fumiama/go-base16384 v1.2.1 h1:6OGprW8g/95m2ocmryHi8mipZ7bx9StFMZDKEqLvMiA= +github.com/fumiama/go-base16384 v1.2.1/go.mod h1:1HTC0QFL7BjS0DuO5Qm+fBYKQkHqmAapLbRpCxrhPXQ= github.com/fumiama/go-registry v0.0.2 h1:2EoZwZpqI7YhkQ1FnuAPvALYPpvUtbsCqk879+r7ehs= github.com/fumiama/go-registry v0.0.2/go.mod h1:QkcmmHuw1y6y/w7/HiH1c9yjBw5Zt+6EER6YJKl9xh8= github.com/fumiama/gofastTEA v0.0.6 h1:Yni3MXDbJVa/c4CecgdZDgCJK+fLdvGph+OBqY2mtiI= github.com/fumiama/gofastTEA v0.0.6/go.mod h1:+sBZ05nCA2skZkursHNvyr8kULlEetrYTM2y5kA4rQc= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= +github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/logoove/sqlite v1.13.0 h1:XM7QKK9R3tm8o7bI75R3zmwYBFQ5S3Jqg+XCaqsAMQQ= github.com/logoove/sqlite v1.13.0/go.mod h1:MRpE/o3qQhT7AgfIdnBue5c63+//xT+KXV0gHeVAUAg= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= @@ -62,30 +82,35 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816/go.mod h1:tzym/CEb5jnFI+Q0k4Qq3+LvRF4gO3E2pxS8fHP8jcA= -github.com/tidwall/gjson v1.11.0 h1:C16pk7tQNiH6VlCrtIXL1w8GaOsi1X3W8KDkE1BuYd4= +github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= github.com/tidwall/gjson v1.11.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo= github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/wdvxdr1123/ZeroBot v1.3.2/go.mod h1:i2DIqQjtjE+3gvVi9r9sc+QpNaUuyTXx/HNXXayIpwI= github.com/wdvxdr1123/ZeroBot v1.4.1 h1:fk/8RH2D1gB3YeC1eI/SZi/kG31Rh7Z8lAiDc60VZFM= github.com/wdvxdr1123/ZeroBot v1.4.1/go.mod h1:7t9m4vDZPwWAmzKlhP6IvUoisOIiqNdm/3AJgiY3+ew= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs= -golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ= golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= @@ -94,11 +119,9 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -106,24 +129,20 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210902050250-f475640dd07b h1:S7hKs0Flbq0bbc9xgYt4stIEG1zNDFqyrPwAX2Wj/sE= golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78 h1:M8tBwCtWD/cZV9DZpFYRUgaymAYAr+aIUTWzDaM3uPs= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= @@ -132,12 +151,14 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU= @@ -145,7 +166,6 @@ lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= modernc.org/cc/v3 v3.33.9/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= modernc.org/cc/v3 v3.33.11/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.34.0 h1:dFhZc/HKR3qp92sYQxKRRaDMz+sr1bwcFD+m7LSCrAs= modernc.org/cc/v3 v3.34.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= modernc.org/cc/v3 v3.35.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= modernc.org/cc/v3 v3.35.4/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= @@ -164,8 +184,6 @@ modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60 modernc.org/ccgo/v3 v3.10.0/go.mod h1:c0yBmkRFi7uW4J7fwx/JiijwOjeAeR2NoSaRVFPmjMw= modernc.org/ccgo/v3 v3.11.0/go.mod h1:dGNposbDp9TOZ/1KBxghxtUp/bzErD0/0QW4hhSaBMI= modernc.org/ccgo/v3 v3.11.1/go.mod h1:lWHxfsn13L3f7hgGsGlU28D9eUOf6y3ZYHKoPaKU0ag= -modernc.org/ccgo/v3 v3.11.2 h1:gqa8PQ2v7SjrhHCgxUO5dzoAJWSLAveJqZTNkPCN0kc= -modernc.org/ccgo/v3 v3.11.2/go.mod h1:6kii3AptTDI+nUrM9RFBoIEUEisSWCbdczD9ZwQH2FE= modernc.org/ccgo/v3 v3.11.3/go.mod h1:0oHunRBMBiXOKdaglfMlRPBALQqsfrCKXgw9okQ3GEw= modernc.org/ccgo/v3 v3.12.4/go.mod h1:Bk+m6m2tsooJchP/Yk5ji56cClmN6R1cqc9o/YtbgBQ= modernc.org/ccgo/v3 v3.12.6/go.mod h1:0Ji3ruvpFPpz+yu+1m0wk68pdr/LENABhTrDkMDWH6c= @@ -202,14 +220,14 @@ modernc.org/ccgo/v3 v3.12.92/go.mod h1:5yDdN7ti9KWPi5bRVWPl8UNhpEAtCjuEE7ayQnzzq modernc.org/ccgo/v3 v3.13.1/go.mod h1:aBYVOUfIlcSnrsRVU8VRS35y2DIfpgkmVkYZ0tpIXi4= modernc.org/ccgo/v3 v3.14.0 h1:Zr1Ny9+7r5yAiXpBdgp8XiXqkNA4ARrRphHGHVXeAp0= modernc.org/ccgo/v3 v3.14.0/go.mod h1:hBrkiBlUwvr5vV/ZH9YzXIp982jKE8Ek8tR1ytoAL6Q= +modernc.org/ccorpus v1.11.1 h1:K0qPfpVG1MJh5BYazccnmhywH4zHuOgJXgbjzyp6dWA= modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q= modernc.org/libc v1.11.0/go.mod h1:2lOfPmj7cz+g1MrPNmX65QCzVxgNq2C5o0jdLY2gAYg= modernc.org/libc v1.11.2/go.mod h1:ioIyrl3ETkugDO3SGZ+6EOKvlP3zSOycUETe4XM4n8M= -modernc.org/libc v1.11.3 h1:q//spBhqp23lC/if8/o8hlyET57P8mCZqrqftzT2WmY= -modernc.org/libc v1.11.3/go.mod h1:k3HDCP95A6U111Q5TmG3nAyUcp3kR5YFZTeDS9v8vSU= modernc.org/libc v1.11.5/go.mod h1:k3HDCP95A6U111Q5TmG3nAyUcp3kR5YFZTeDS9v8vSU= modernc.org/libc v1.11.6/go.mod h1:ddqmzR6p5i4jIGK1d/EiSw97LBcE3dK24QEwCFvgNgE= modernc.org/libc v1.11.11/go.mod h1:lXEp9QOOk4qAYOtL3BmMve99S5Owz7Qyowzvg6LiZso= @@ -257,15 +275,11 @@ modernc.org/memory v1.0.5 h1:XRch8trV7GgvTec2i7jc33YlUI0RKVDBvZ5eZ5m8y14= modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM= modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.13.0 h1:cwhUj0jTBgPjk/demWheV+T6xi6ifTfsGIFKFq0g3Ck= -modernc.org/sqlite v1.13.0/go.mod h1:2qO/6jZJrcQaxFUHxOwa6Q6WfiGSsiVj6GXX0Ker+Jg= modernc.org/sqlite v1.14.4 h1:F3DRiVZKnCLqIQ0LhEGqBLnw9LcdADciCwCIHQ8bD5g= modernc.org/sqlite v1.14.4/go.mod h1:LWtcO8JtBrt29KKmTqNNXDjAn36vHa/3nHvOYoVIAjc= modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= -modernc.org/tcl v1.5.9/go.mod h1:bcwjvBJ2u0exY6K35eAmxXBBij5kXb1dHlAWmfhqThE= modernc.org/tcl v1.10.0/go.mod h1:WzWapmP/7dHVhFoyPpEaNSVTL8xtewhouN/cqSJ5A2s= modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.1.2/go.mod h1:sj9T1AGBG0dm6SCVzldPOHWrif6XBpooJtbttMn1+Js= modernc.org/z v1.2.21/go.mod h1:uXrObx4pGqXWIMliC5MiKuwAyMrltzwpteOFUP1PWCc=