diff --git a/handler/handler.go b/handler/handler.go index b61e3e4..1ea4d9d 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -9,7 +9,8 @@ import ( "git.lxtend.com/qqbot/model" ) -var handlers = make(map[string]model.HandlerInfo[model.Handler]) +var allGroupHandlers = make(map[string]model.HandlerInfo[model.Handler]) +var GroupHandlers = make(map[int64]map[string]model.HandlerInfo[model.Handler]) var frontMatchHandlers = make(map[string]model.HandlerInfo[model.Handler]) var liveHandlers = make(map[int64]map[int64]model.TryCatchHandler) var livePrivateHandlers = make(map[int64]model.TryCatchHandler) @@ -21,7 +22,7 @@ func RegisterPrivateHandler(handler model.Handler) { } func RegisterHandler(trigger string, handler model.Handler, level constants.PermissionLevel) { - handlers[trigger] = model.HandlerInfo[model.Handler]{ + allGroupHandlers[trigger] = model.HandlerInfo[model.Handler]{ Trigger: trigger, Handler: handler, Level: level, @@ -47,6 +48,23 @@ func RegisterLiveHandler(groupID int64, userID int64, handler model.TryCatchHand liveHandlers[groupID][userID] = handler } +func RegisterGroupHandler(groupID int64, trigger string, handler model.Handler, level constants.PermissionLevel) { + if _, ok := GroupHandlers[groupID]; !ok { + GroupHandlers[groupID] = make(map[string]model.HandlerInfo[model.Handler]) + } + GroupHandlers[groupID][trigger] = model.HandlerInfo[model.Handler]{ + Trigger: trigger, + Handler: handler, + Level: level, + } +} + +func UnRegisterGroupHandler(groupID int64, trigger string) { + if _, ok := GroupHandlers[groupID]; ok { + delete(GroupHandlers[groupID], trigger) + } +} + func MsgInHandler(msg model.Message) (reply model.Reply) { defer func() { if r := recover(); r != nil { @@ -85,9 +103,14 @@ func MsgInHandler(msg model.Message) (reply model.Reply) { } } msgArray := strings.Split(msg.RawMsg, " ") - if handler, ok := handlers[msgArray[0]]; ok { + if handler, ok := allGroupHandlers[msgArray[0]]; ok { return auth.TryExecHandler(msg, handler.Level, handler.Handler) } + if groupHandler, ok := GroupHandlers[msg.GroupInfo.GroupId]; ok { + if handler, ok := groupHandler[msgArray[0]]; ok { + return auth.TryExecHandler(msg, handler.Level, handler.Handler) + } + } if !msg.GroupInfo.IsGroupMsg && privateAllHandler != nil { return privateAllHandler(msg) } diff --git a/handler/kw/kw.go b/handler/kw/kw.go new file mode 100644 index 0000000..8a1750b --- /dev/null +++ b/handler/kw/kw.go @@ -0,0 +1,155 @@ +package say + +import ( + "math/rand/v2" + "strconv" + + "git.lxtend.com/qqbot/constants" + "git.lxtend.com/qqbot/handler" + "git.lxtend.com/qqbot/model" + "git.lxtend.com/qqbot/service/kw" + "git.lxtend.com/qqbot/util" +) + +func init() { + handler.RegisterHandler("kw", setKw, constants.LEVEL_TRUSTED) + handler.RegisterHelpInform("kw", "kw [关键词] [回复内容] 添加关键词回复,kw [关键词] 删除全部关键词回复") + handler.RegisterHandler("kwd", deleteKw, constants.LEVEL_TRUSTED) + + handler.RegisterHandler("kwall", getGroupAllKW, constants.LEVEL_TRUSTED) + handler.RegisterHelpInform("kwall", "kwall 查看所有关键词回复") + initKw() +} + +func initKw() { + kwList, err := kw.GetAllKW() + if err != nil { + return + } + for _, v := range kwList { + group, _ := strconv.Atoi(v.GroupID) + regKw(v.Kw, int64(group)) + } +} + +func setKw(msg model.Message) (reply model.Reply) { + tokens := util.SplitN(msg.RawMsg, 3) + if len(tokens) < 2 { + return model.Reply{ + ReplyMsg: "参数不足, 请使用\"kw [关键词] [回复内容]\"添加关键词回复", + ReferOriginMsg: true, + FromMsg: msg, + } + } + + if _, err := kw.AddKW(tokens[1], tokens[2], strconv.Itoa(int(msg.GroupInfo.GroupId)), strconv.Itoa(int(msg.UserId))); err != nil { + return model.Reply{ + ReplyMsg: "添加失败", + ReferOriginMsg: true, + FromMsg: msg, + } + } + regKw(tokens[1], msg.GroupInfo.GroupId) + return model.Reply{ + ReplyMsg: "记下了", + ReferOriginMsg: true, + FromMsg: msg, + } +} + +func deleteKw(msg model.Message) (reply model.Reply) { + tokens := util.SplitN(msg.RawMsg, 3) + if len(tokens) == 2 { + if err := kw.DeleteKW(tokens[1], strconv.Itoa(int(msg.GroupInfo.GroupId))); err != nil { + return model.Reply{ + ReplyMsg: "删除失败", + ReferOriginMsg: true, + FromMsg: msg, + } + } + unRegKw(tokens[1], msg.GroupInfo.GroupId) + return model.Reply{ + ReplyMsg: "清空了", + ReferOriginMsg: true, + FromMsg: msg, + } + } + if len(tokens) < 2 { + return model.Reply{ + ReplyMsg: "参数不足, 请使用\"kwd [关键词] [回复内容]\"删除对应的关键词回复", + ReferOriginMsg: true, + FromMsg: msg, + } + } + if err := kw.DeleteKWReply(tokens[1], tokens[2], strconv.Itoa(int(msg.GroupInfo.GroupId))); err != nil { + return model.Reply{ + ReplyMsg: "删除失败", + ReferOriginMsg: true, + FromMsg: msg, + } + } + return model.Reply{ + ReplyMsg: "删除了", + ReferOriginMsg: true, + FromMsg: msg, + } +} + +func getGroupAllKW(msg model.Message) (reply model.Reply) { + kwList, err := kw.GetGroupAllKW(strconv.Itoa(int(msg.GroupInfo.GroupId))) + if err != nil { + return model.Reply{ + ReplyMsg: "获取失败", + ReferOriginMsg: true, + FromMsg: msg, + } + } + kws := "" + for k, v := range kwList { + kws += v.Kw + " -> " + v.Reply + if k != len(kwList)-1 { + kws += "\n" + } + } + return model.Reply{ + ReplyMsg: kws, + ReferOriginMsg: true, + FromMsg: msg, + } +} + +func regKw(keyword string, groupId int64) { + handler.RegisterGroupHandler(groupId, keyword, kwReply, constants.LEVEL_USER) +} + +func unRegKw(keyword string, groupId int64) { + handler.UnRegisterGroupHandler(groupId, keyword) +} + +func kwReply(msg model.Message) (reply model.Reply) { + w, err := kw.GetKW(msg.RawMsg, strconv.Itoa(int(msg.GroupInfo.GroupId))) + if err != nil { + return model.Reply{ + ReplyMsg: "", + ReferOriginMsg: false, + FromMsg: msg, + } + } + wlist := []string{} + for _, v := range w { + wlist = append(wlist, v.Reply) + } + pick := rand.IntN(len(wlist)) + if util.Fail(0.1) { + return model.Reply{ + ReplyMsg: "", + ReferOriginMsg: false, + FromMsg: msg, + } + } + return model.Reply{ + ReplyMsg: wlist[pick], + ReferOriginMsg: false, + FromMsg: msg, + } +} diff --git a/handler/say/say.go b/handler/say/say.go deleted file mode 100644 index b9a1d4b..0000000 --- a/handler/say/say.go +++ /dev/null @@ -1,22 +0,0 @@ -package say - -import ( - "git.lxtend.com/qqbot/constants" - "git.lxtend.com/qqbot/handler" - "git.lxtend.com/qqbot/model" -) - -func init() { - handler.RegisterHandler("kw", say, constants.LEVEL_TRUSTED) -} - -func say(msg model.Message) (reply model.Reply) { - if len(msg.RawMsg) <= len("kw ") { - return model.Reply{} - } - return model.Reply{ - ReplyMsg: "记下了", - ReferOriginMsg: true, - FromMsg: msg, - } -} diff --git a/handler/wordle/wordle.go b/handler/wordle/wordle.go new file mode 100644 index 0000000..101d3e3 --- /dev/null +++ b/handler/wordle/wordle.go @@ -0,0 +1,28 @@ +package wordle + +import ( + "git.lxtend.com/qqbot/constants" + "git.lxtend.com/qqbot/handler" + "git.lxtend.com/qqbot/model" +) + +func init() { + handler.RegisterHandler("wordle", wordle, constants.LEVEL_USER) +} + +func wordle(msg model.Message) (reply model.Reply) { + handler.RegisterLiveHandler(msg.GroupInfo.GroupId, msg.UserId, tempTrigger) + return model.Reply{ + ReplyMsg: "", + ReferOriginMsg: true, + FromMsg: msg, + } +} + +func tempTrigger(msg model.Message) (reply model.Reply, isTrigger bool) { + return model.Reply{ + ReplyMsg: " ", + ReferOriginMsg: true, + FromMsg: msg, + }, true +} diff --git a/register.go b/register.go index d9c2620..8b62393 100644 --- a/register.go +++ b/register.go @@ -8,11 +8,11 @@ import ( _ "git.lxtend.com/qqbot/handler/headmaster" _ "git.lxtend.com/qqbot/handler/help" _ "git.lxtend.com/qqbot/handler/jrrp" + _ "git.lxtend.com/qqbot/handler/kw" _ "git.lxtend.com/qqbot/handler/restart" _ "git.lxtend.com/qqbot/handler/roll" _ "git.lxtend.com/qqbot/handler/scoresaber" _ "git.lxtend.com/qqbot/handler/ticket" _ "git.lxtend.com/qqbot/handler/urlparser" _ "git.lxtend.com/qqbot/handler/xibao" - // _ "git.lxtend.com/qqbot/handler/wordle" ) diff --git a/service/kw/kw.go b/service/kw/kw.go new file mode 100644 index 0000000..874ae08 --- /dev/null +++ b/service/kw/kw.go @@ -0,0 +1,111 @@ +package kw + +import "git.lxtend.com/qqbot/sqlite3" + +func init() { + kwTable := ` + CREATE TABLE IF NOT EXISTS kw ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + kw TEXT, + reply TEXT, + group_id TEXT, + created_by TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + ` + sqlite3.TryCreateTable(kwTable) +} + +func AddKW(kw string, reply string, groupID string, createdBy string) (int64, error) { + kwData := Kw{ + Kw: kw, + Reply: reply, + GroupID: groupID, + CreatedBy: createdBy, + } + tx, err := sqlite3.GetTran() + if err != nil { + return 0, err + } + defer tx.Rollback() + res, err := tx.Exec("INSERT INTO kw (kw, reply, group_id, created_by) VALUES (:kw, :reply, :group_id, :created_by)", kwData.Kw, kwData.Reply, kwData.GroupID, kwData.CreatedBy) + if err != nil { + return 0, err + } + id, _ := res.LastInsertId() + tx.Commit() + return id, nil +} + +func DeleteKW(kw string, groupID string) error { + tx, err := sqlite3.GetTran() + if err != nil { + return err + } + defer tx.Rollback() + _, err = tx.Exec("DELETE FROM kw WHERE kw = ? AND group_id = ?", kw, groupID) + if err != nil { + return err + } + tx.Commit() + return nil +} + +func DeleteKWReply(kw string, reply string, groupID string) error { + tx, err := sqlite3.GetTran() + if err != nil { + return err + } + defer tx.Rollback() + _, err = tx.Exec("DELETE FROM kw WHERE kw = ? AND reply = ? AND group_id = ?", kw, reply, groupID) + if err != nil { + return err + } + tx.Commit() + return nil +} + +func GetKW(kw string, groupId string) ([]Kw, error) { + var kws []Kw + tx, err := sqlite3.GetTran() + if err != nil { + return nil, err + } + defer tx.Rollback() + err = tx.Select(&kws, "SELECT * FROM kw WHERE kw = ? AND group_id = ?", kw, groupId) + if err != nil { + return nil, err + } + tx.Commit() + return kws, nil +} + +func GetGroupAllKW(groupID string) ([]Kw, error) { + var kws []Kw + tx, err := sqlite3.GetTran() + if err != nil { + return nil, err + } + defer tx.Rollback() + err = tx.Select(&kws, "SELECT * FROM kw WHERE group_id = ?", groupID) + if err != nil { + return nil, err + } + tx.Commit() + return kws, nil +} + +func GetAllKW() ([]Kw, error) { + var kws []Kw + tx, err := sqlite3.GetTran() + if err != nil { + return nil, err + } + defer tx.Rollback() + err = tx.Select(&kws, "SELECT * FROM kw") + if err != nil { + return nil, err + } + tx.Commit() + return kws, nil +} diff --git a/service/kw/model.go b/service/kw/model.go new file mode 100644 index 0000000..c0beb41 --- /dev/null +++ b/service/kw/model.go @@ -0,0 +1,10 @@ +package kw + +type Kw struct { + ID int64 `json:"id" db:"id"` + Kw string `json:"kw" db:"kw"` + Reply string `json:"reply" db:"reply"` + GroupID string `json:"group_id" db:"group_id"` + CreatedBy string `json:"created_by" db:"created_by"` + CreatedAt string `json:"created_at" db:"created_at"` +} diff --git a/util/random_fail.go b/util/random_fail.go new file mode 100644 index 0000000..65e3107 --- /dev/null +++ b/util/random_fail.go @@ -0,0 +1,7 @@ +package util + +import "math/rand/v2" + +func Fail(chance float64) bool { + return rand.Float64() < chance +} diff --git a/util/split.go b/util/split.go index d231ea2..c5243d6 100644 --- a/util/split.go +++ b/util/split.go @@ -4,12 +4,8 @@ import ( "regexp" ) -func SplitN(text string, n int) ([]string, int) { - if n == 0 { - return []string{text}, 1 - } - +func SplitN(text string, n int) []string { re := regexp.MustCompile(`\s+`) tokens := re.Split(text, n) - return tokens, len(tokens) + return tokens }