diff --git a/action/action.go b/action/action.go new file mode 100644 index 0000000..e2338b9 --- /dev/null +++ b/action/action.go @@ -0,0 +1,53 @@ +package action + +import ( + "encoding/json" + "fmt" + + "git.lxtend.com/qqbot/model" + "github.com/gorilla/websocket" +) + +func init() { +} + +var ActionManager = actionManager{} + +type actionManager struct { + botConn *websocket.Conn +} + +func (am *actionManager) SetConn(conn *websocket.Conn) { + am.botConn = conn +} + +func (am *actionManager) SendAction(action string) error { + return am.botConn.WriteMessage(websocket.TextMessage, []byte(action)) +} + +func (am *actionManager) SendMsg(reply model.Reply) error { + if reply.ReferOriginMsg { + reply.ReplyMsg = fmt.Sprintf("%s%s", GenReply(reply.FromMsg.OriginMsgId, "", 0, 0, 0), reply.ReplyMsg) + } + sendPkg := model.GenSendPkg(reply.FromMsg.UserId, reply.FromMsg.GroupInfo.GroupId, reply.ReplyMsg, false) + sendPkgJson, err := json.Marshal(sendPkg) + if err != nil { + return err + } + if err = am.botConn.WriteMessage(websocket.TextMessage, sendPkgJson); err != nil { + return err + } + return nil +} + +func (am *actionManager) DrawbackMsg(msgId int32) error { + withDrawPkg := model.GenDrawbackPkg(msgId) + withDrawPkgJson, err := json.Marshal(withDrawPkg) + if err != nil { + return err + } + if err = am.botConn.WriteMessage(websocket.TextMessage, withDrawPkgJson); err != nil { + return err + } + return nil +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..b3a21f9 --- /dev/null +++ b/config/config.go @@ -0,0 +1,37 @@ +package config + +import ( + "os" + + "gopkg.in/yaml.v3" +) + +var ConfigManager = &configManager{} + +func init() { + err := ConfigManager.LoadConfig("config.yml") + if err != nil { + panic(err) + } +} + +type configManager struct { + propertys map[string]string +} + +func (cm *configManager) LoadConfig(path string) error { + data, err := os.ReadFile(path) + if err != nil { + return err + } + + err = yaml.Unmarshal(data, &cm.propertys) + if err != nil { + return err + } + return nil +} + +func (cm *configManager) GetProperty(key string) string { + return cm.propertys[key] +} diff --git a/go.mod b/go.mod index b83444a..00c8468 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/sashabaranov/go-openai v1.30.3 golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c golang.org/x/net v0.30.0 + gopkg.in/yaml.v3 v3.0.1 ) require ( @@ -73,6 +74,5 @@ require ( golang.org/x/text v0.19.0 // indirect golang.org/x/time v0.7.0 // indirect google.golang.org/protobuf v1.35.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect ) diff --git a/handler/drawback/drawback.go b/handler/drawback/drawback.go new file mode 100644 index 0000000..a59722e --- /dev/null +++ b/handler/drawback/drawback.go @@ -0,0 +1,32 @@ +package drawback + +import ( + "log" + + "git.lxtend.com/qqbot/action" + "git.lxtend.com/qqbot/constants" + "git.lxtend.com/qqbot/handler" + "git.lxtend.com/qqbot/model" +) + +func init() { + handler.RegisterRegexHandler(`撤回`, drawback, constants.LEVEL_USER) +} + +func drawback(msg model.Message) model.Reply { + msgIdToDrawback, err := model.ParseReplyData(msg.RawMsg) + log.Printf("Drawback message %d", msgIdToDrawback.Data.ID) + if err != nil { + return model.Reply{ + ReplyMsg: "", + ReferOriginMsg: false, + FromMsg: msg, + } + } + action.ActionManager.DrawbackMsg(int32(msgIdToDrawback.Data.ID)) + return model.Reply{ + ReplyMsg: "", + ReferOriginMsg: false, + FromMsg: msg, + } +} diff --git a/handler/handler.go b/handler/handler.go index 1ea4d9d..c69bdc3 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -2,6 +2,7 @@ package handler import ( "log" + "regexp" "strings" "git.lxtend.com/qqbot/auth" @@ -12,6 +13,7 @@ import ( 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 regexHandlers = make(map[string]model.HandlerInfo[model.Handler]) var liveHandlers = make(map[int64]map[int64]model.TryCatchHandler) var livePrivateHandlers = make(map[int64]model.TryCatchHandler) var HelpInforms = make(map[string]string) @@ -65,6 +67,14 @@ func UnRegisterGroupHandler(groupID int64, trigger string) { } } +func RegisterRegexHandler(trigger string, handler model.Handler, level constants.PermissionLevel) { + regexHandlers[trigger] = model.HandlerInfo[model.Handler]{ + Trigger: trigger, + Handler: handler, + Level: level, + } +} + func MsgInHandler(msg model.Message) (reply model.Reply) { defer func() { if r := recover(); r != nil { @@ -111,6 +121,12 @@ func MsgInHandler(msg model.Message) (reply model.Reply) { return auth.TryExecHandler(msg, handler.Level, handler.Handler) } } + for trigger, handler := range regexHandlers { + exp := regexp.MustCompile(trigger) + if exp.MatchString(msg.RawMsg) { + return auth.TryExecHandler(msg, handler.Level, handler.Handler) + } + } if !msg.GroupInfo.IsGroupMsg && privateAllHandler != nil { return privateAllHandler(msg) } diff --git a/handler/restart/restart.go b/handler/restart/restart.go index 50bb531..50b90cc 100644 --- a/handler/restart/restart.go +++ b/handler/restart/restart.go @@ -20,6 +20,7 @@ func init() { handler.RegisterHandler("/构建bot", build, constants.LEVEL_ADMIN) handler.RegisterHandler("/构建重启", buildAndRestart, constants.LEVEL_ADMIN) handler.RegisterHandler("/gitpull", pullCode, constants.LEVEL_ADMIN) + handler.RegisterHandler("/shutdown", shutdown, constants.LEVEL_ADMIN) } func restart(msg model.Message) model.Reply { @@ -38,6 +39,15 @@ func restart(msg model.Message) model.Reply { } } +func shutdown(msg model.Message) model.Reply { + go shutdownProgram() + return model.Reply{ + ReplyMsg: "关闭中...", + ReferOriginMsg: true, + FromMsg: msg, + } +} + func build(msg model.Message) model.Reply { err := buildBot() if err != nil { @@ -117,6 +127,14 @@ func restartProgram() error { return nil } +func shutdownProgram() error { + log.Println("关闭程序...") + docker.DockerContainer.RemoveContainer() + time.Sleep(500 * time.Millisecond) + os.Exit(0) + return nil +} + func buildBot() error { hasVaildBuild = false workDir, err := os.Getwd() diff --git a/model/action.go b/model/action.go new file mode 100644 index 0000000..3e7544c --- /dev/null +++ b/model/action.go @@ -0,0 +1,15 @@ +package model + +type Action struct { + Action string `json:"action"` + Params map[string]interface{} `json:"params"` +} + +func GenDrawbackPkg(msgId int32) Action { + return Action{ + Action: "delete_msg", + Params: map[string]interface{}{ + "message_id": msgId, + }, + } +} diff --git a/model/cq_message.go b/model/cq_message.go index 940803f..32473bd 100644 --- a/model/cq_message.go +++ b/model/cq_message.go @@ -48,7 +48,26 @@ type ReplyMessage struct { // 回复消息数据结构体 type ReplyData struct { - ID string `json:"id"` + ID int `json:"id"` +} + +func ParseReplyData(data string) (*ReplyMessage, error) { + // 使用正则表达式提取ID + re := regexp.MustCompile(`\[CQ:reply,id=(\d+)\]`) + matches := re.FindStringSubmatch(data) + if len(matches) < 2 { + return nil, fmt.Errorf("数据格式不正确") + } + + id, _ := strconv.Atoi(matches[1]) + + // 返回解析后的结构体 + return &ReplyMessage{ + Type: "reply", + Data: ReplyData{ + ID: id, + }, + }, nil } type ImageMessage struct { diff --git a/register.go b/register.go index 1bd24f5..da5bb30 100644 --- a/register.go +++ b/register.go @@ -3,6 +3,7 @@ package main import ( _ "git.lxtend.com/qqbot/handler/auth" _ "git.lxtend.com/qqbot/handler/beatleader" + _ "git.lxtend.com/qqbot/handler/drawback" _ "git.lxtend.com/qqbot/handler/echo" _ "git.lxtend.com/qqbot/handler/exec" _ "git.lxtend.com/qqbot/handler/getweb" diff --git a/ws_client/client.go b/ws_client/client.go index e34b37c..876428d 100644 --- a/ws_client/client.go +++ b/ws_client/client.go @@ -2,7 +2,6 @@ package wsclient import ( "encoding/json" - "fmt" "log" "net/url" @@ -38,6 +37,8 @@ func NewWebSocketClient(scheme, host, path string) (*WebSocketClient, error) { } }() + action.ActionManager.SetConn(conn) + go client.receiveMessages() return client, nil @@ -78,19 +79,7 @@ func (c *WebSocketClient) receiveMessages() { go func() { reply := handler.MsgInHandler(msg) if reply.ReplyMsg != "" { - if reply.ReferOriginMsg { - reply.ReplyMsg = fmt.Sprintf("%s%s", action.GenReply(reply.FromMsg.OriginMsgId, "", 0, 0, 0), reply.ReplyMsg) - } - sendPkg := model.GenSendPkg(reply.FromMsg.UserId, reply.FromMsg.GroupInfo.GroupId, reply.ReplyMsg, false) - sendPkgJson, err := json.Marshal(sendPkg) - if err != nil { - log.Println("Error marshalling sendPkg:", err) - return - } - if err = c.SendMessage(websocket.TextMessage, sendPkgJson); err != nil { - log.Println("Error sending message:", err) - return - } + action.ActionManager.SendMsg(reply) } }() }