diff --git a/Processor/ProcessC2CMessage.go b/Processor/ProcessC2CMessage.go index 917eaf3f..6f78fd5e 100644 --- a/Processor/ProcessC2CMessage.go +++ b/Processor/ProcessC2CMessage.go @@ -51,7 +51,7 @@ func (p *Processors) ProcessC2CMessage(data *dto.WSC2CMessageData) error { } messageID := int(messageID64) //转换at - messageText := handlers.RevertTransformedText(data) + messageText := handlers.RevertTransformedText(data, "group_private", p.Api, p.Apiv2) if messageText == "" { mylog.Printf("信息被自定义黑白名单拦截") return nil @@ -107,7 +107,7 @@ func (p *Processors) ProcessC2CMessage(data *dto.WSC2CMessageData) error { //将私聊信息转化为群信息(特殊需求情况下) //转换at - messageText := handlers.RevertTransformedText(data) + messageText := handlers.RevertTransformedText(data, "group_private", p.Api, p.Apiv2) if messageText == "" { mylog.Printf("信息被自定义黑白名单拦截") return nil diff --git a/Processor/ProcessChannelDirectMessage.go b/Processor/ProcessChannelDirectMessage.go index 95bf8063..024f36f7 100644 --- a/Processor/ProcessChannelDirectMessage.go +++ b/Processor/ProcessChannelDirectMessage.go @@ -67,7 +67,7 @@ func (p *Processors) ProcessChannelDirectMessage(data *dto.WSDirectMessageData) } messageID := int(messageID64) //转换at - messageText := handlers.RevertTransformedText(data) + messageText := handlers.RevertTransformedText(data, "guild_private", p.Api, p.Apiv2) if messageText == "" { mylog.Printf("信息被自定义黑白名单拦截") return nil @@ -127,7 +127,7 @@ func (p *Processors) ProcessChannelDirectMessage(data *dto.WSDirectMessageData) //获取s s := client.GetGlobalS() //转换at - messageText := handlers.RevertTransformedText(data) + messageText := handlers.RevertTransformedText(data, "guild_private", p.Api, p.Apiv2) if messageText == "" { mylog.Printf("信息被自定义黑白名单拦截") return nil @@ -220,7 +220,7 @@ func (p *Processors) ProcessChannelDirectMessage(data *dto.WSDirectMessageData) //直接储存 适用于私信场景私聊 idmap.WriteConfigv2(data.ChannelID, "guild_id", data.GuildID) //转换at - messageText := handlers.RevertTransformedText(data) + messageText := handlers.RevertTransformedText(data, "guild_private", p.Api, p.Apiv2) if messageText == "" { mylog.Printf("信息被自定义黑白名单拦截") return nil diff --git a/Processor/ProcessGroupMessage.go b/Processor/ProcessGroupMessage.go index 60856be2..0360055d 100644 --- a/Processor/ProcessGroupMessage.go +++ b/Processor/ProcessGroupMessage.go @@ -22,7 +22,7 @@ func (p *Processors) ProcessGroupMessage(data *dto.WSGroupATMessageData) error { s := client.GetGlobalS() // 转换at - messageText := handlers.RevertTransformedText(data) + messageText := handlers.RevertTransformedText(data, "group", p.Api, p.Apiv2) if messageText == "" { mylog.Printf("信息被自定义黑白名单拦截") return nil diff --git a/Processor/ProcessGuildATMessage.go b/Processor/ProcessGuildATMessage.go index 788e6f35..f88af083 100644 --- a/Processor/ProcessGuildATMessage.go +++ b/Processor/ProcessGuildATMessage.go @@ -27,7 +27,7 @@ func (p *Processors) ProcessGuildATMessage(data *dto.WSATMessageData) error { //获取s s := client.GetGlobalS() //转换at - messageText := handlers.RevertTransformedText(data) + messageText := handlers.RevertTransformedText(data, "guild", p.Api, p.Apiv2) if messageText == "" { mylog.Printf("信息被自定义黑白名单拦截") return nil @@ -123,7 +123,7 @@ func (p *Processors) ProcessGuildATMessage(data *dto.WSATMessageData) error { //转成int再互转 idmap.WriteConfigv2(fmt.Sprint(ChannelID64), "guild_id", data.GuildID) //转换at和图片 - messageText := handlers.RevertTransformedText(data) + messageText := handlers.RevertTransformedText(data, "guild", p.Api, p.Apiv2) if messageText == "" { mylog.Printf("信息被自定义黑白名单拦截") return nil diff --git a/Processor/ProcessGuildNormalMessage.go b/Processor/ProcessGuildNormalMessage.go index 8db0fae3..f68786cf 100644 --- a/Processor/ProcessGuildNormalMessage.go +++ b/Processor/ProcessGuildNormalMessage.go @@ -26,7 +26,7 @@ func (p *Processors) ProcessGuildNormalMessage(data *dto.WSMessageData) error { //获取s s := client.GetGlobalS() //转换at - messageText := handlers.RevertTransformedText(data) + messageText := handlers.RevertTransformedText(data, "guild", p.Api, p.Apiv2) if messageText == "" { mylog.Printf("信息被自定义黑白名单拦截") return nil @@ -125,7 +125,7 @@ func (p *Processors) ProcessGuildNormalMessage(data *dto.WSMessageData) error { //转成int再互转 idmap.WriteConfigv2(fmt.Sprint(ChannelID64), "guild_id", data.GuildID) //转换at - messageText := handlers.RevertTransformedText(data) + messageText := handlers.RevertTransformedText(data, "guild", p.Api, p.Apiv2) if messageText == "" { mylog.Printf("信息被自定义黑白名单拦截") return nil diff --git a/config/config.go b/config/config.go index aa4751a3..84c44908 100644 --- a/config/config.go +++ b/config/config.go @@ -76,6 +76,7 @@ type Settings struct { ImageLimitB int `yaml:"image_limit"` RecordSampleRate int `yaml:"record_sampleRate"` RecordBitRate int `yaml:"record_bitRate"` + NoWhiteResponse string `yaml:"No_White_Response"` } // LoadConfig 从文件中加载配置并初始化单例配置 @@ -898,3 +899,15 @@ func GetRecordBitRate() int { return instance.Settings.RecordBitRate } + +// 获取NoWhiteResponse的值 +func GetNoWhiteResponse() string { + mu.Lock() + defer mu.Unlock() + + if instance == nil { + mylog.Println("Warning: instance is nil when trying to NoWhiteResponse value.") + return "" + } + return instance.Settings.NoWhiteResponse +} diff --git a/handlers/message_parser.go b/handlers/message_parser.go index e3c300f7..8637047a 100644 --- a/handlers/message_parser.go +++ b/handlers/message_parser.go @@ -1,6 +1,8 @@ package handlers import ( + "context" + "errors" "fmt" "net" "path/filepath" @@ -8,13 +10,16 @@ import ( "runtime" "strconv" "strings" + "time" "github.com/hoshinonyaruko/gensokyo/callapi" "github.com/hoshinonyaruko/gensokyo/config" + "github.com/hoshinonyaruko/gensokyo/echo" "github.com/hoshinonyaruko/gensokyo/idmap" "github.com/hoshinonyaruko/gensokyo/mylog" "github.com/hoshinonyaruko/gensokyo/url" "github.com/tencent-connect/botgo/dto" + "github.com/tencent-connect/botgo/openapi" "mvdan.cc/xurls" //xurls是一个从文本提取url的库 适用于多种场景 ) @@ -239,7 +244,7 @@ func transformMessageText(messageText string) string { } // 处理at和其他定形文到onebotv11格式(cq码) -func RevertTransformedText(data interface{}) string { +func RevertTransformedText(data interface{}, msgtype string, api openapi.OpenAPI, apiv2 openapi.OpenAPI) string { var msg *dto.Message switch v := data.(type) { case *dto.WSGroupATMessageData: @@ -322,9 +327,10 @@ func RevertTransformedText(data interface{}) string { } } - // 如果没有匹配项,则将 messageText 置为空 + // 如果没有匹配项,则将 messageText 置为兜底回复 兜底回复可空 if !matched { messageText = "" + SendMessage(config.GetNoWhiteResponse(), data, msgtype, api, apiv2) } } //检查是否启用黑名单模式 @@ -529,3 +535,78 @@ func sortMessageSegments(segments []map[string]interface{}) []map[string]interfa // 按照指定的顺序合并这些切片 return append(append(atSegments, textSegments...), imageSegments...) } + +// SendMessage 发送消息根据不同的类型 +func SendMessage(messageText string, data interface{}, messageType string, api openapi.OpenAPI, apiv2 openapi.OpenAPI) error { + // 强制类型转换,获取Message结构 + var msg *dto.Message + switch v := data.(type) { + case *dto.WSGroupATMessageData: + msg = (*dto.Message)(v) + case *dto.WSATMessageData: + msg = (*dto.Message)(v) + case *dto.WSMessageData: + msg = (*dto.Message)(v) + case *dto.WSDirectMessageData: + msg = (*dto.Message)(v) + case *dto.WSC2CMessageData: + msg = (*dto.Message)(v) + default: + return nil + } + switch messageType { + case "guild": + // 处理公会消息 + msgseq := echo.GetMappingSeq(msg.ID) + echo.AddMappingSeq(msg.ID, msgseq+1) + textMsg, _ := GenerateReplyMessage(msg.ID, nil, messageText, msgseq+1) + if _, err := api.PostMessage(context.TODO(), msg.ChannelID, textMsg); err != nil { + mylog.Printf("发送文本信息失败: %v", err) + return err + } + + case "group": + // 处理群组消息 + msgseq := echo.GetMappingSeq(msg.ID) + echo.AddMappingSeq(msg.ID, msgseq+1) + textMsg, _ := GenerateReplyMessage(msg.ID, nil, messageText, msgseq+1) + _, err := apiv2.PostGroupMessage(context.TODO(), msg.GroupID, textMsg) + if err != nil { + mylog.Printf("发送文本群组信息失败: %v", err) + return err + } + + case "guild_private": + // 处理私信 + timestamp := time.Now().Unix() + timestampStr := fmt.Sprintf("%d", timestamp) + dm := &dto.DirectMessage{ + GuildID: msg.GuildID, + ChannelID: msg.ChannelID, + CreateTime: timestampStr, + } + msgseq := echo.GetMappingSeq(msg.ID) + echo.AddMappingSeq(msg.ID, msgseq+1) + textMsg, _ := GenerateReplyMessage(msg.ID, nil, messageText, msgseq+1) + if _, err := apiv2.PostDirectMessage(context.TODO(), dm, textMsg); err != nil { + mylog.Printf("发送文本信息失败: %v", err) + return err + } + + case "group_private": + // 处理群组私聊消息 + msgseq := echo.GetMappingSeq(msg.ID) + echo.AddMappingSeq(msg.ID, msgseq+1) + textMsg, _ := GenerateReplyMessage(msg.ID, nil, messageText, msgseq+1) + _, err := apiv2.PostC2CMessage(context.TODO(), msg.Author.ID, textMsg) + if err != nil { + mylog.Printf("发送文本私聊信息失败: %v", err) + return err + } + + default: + return errors.New("未知的消息类型") + } + + return nil +} diff --git a/handlers/send_private_msg.go b/handlers/send_private_msg.go index 47807b7c..5f83eba2 100644 --- a/handlers/send_private_msg.go +++ b/handlers/send_private_msg.go @@ -184,16 +184,30 @@ func handleSendGuildChannelPrivateMsg(client callapi.Client, api openapi.OpenAPI var guildID, channelID string var err error + GroupID := message.Params.GroupID.(string) if optionalGuildID != nil && optionalChannelID != nil { guildID = *optionalGuildID channelID = *optionalChannelID } else { - //默认私信场景 通过仅有的userid来还原频道私信需要的guildid - guildID, channelID, err = getGuildIDFromMessage(message) - if err != nil { - mylog.Printf("获取 guild_id 和 channel_id 出错: %v", err) - return + //频道私信,虚拟成群 通过仅有的group来还原频道私信需要的guildid channelID + if GroupID != "" { + guildID, err = idmap.ReadConfigv2(GroupID, "guild_id") + if err != nil { + mylog.Printf("根据GroupID获取guild_id失败: %v", err) + return + } + channelID, err = idmap.RetrieveRowByIDv2(GroupID) + if err != nil { + mylog.Printf("根据GroupID获取channelID失败: %v", err) + return + } + } else { //默认私信场景 通过仅有的userid来还原频道私信需要的guildid channelID + guildID, channelID, err = getGuildIDFromMessage(message) + if err != nil { + mylog.Printf("获取 guild_id 和 channel_id 出错: %v", err) + return + } } } RawUserID := message.Params.UserID.(string) diff --git a/main.go b/main.go index 43c17861..15771aa4 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "net/http" "os" "os/signal" + "runtime" "strings" "syscall" "time" @@ -51,11 +52,18 @@ func main() { sys.InitBase() // 如果不是faststart模式,则执行初始化 } if _, err := os.Stat("config.yml"); os.IsNotExist(err) { - // 获取内网IP地址 - ip, err := sys.GetLocalIP() - if err != nil { - log.Println("Error retrieving the local IP address:", err) - return + var ip string + var err error + // 检查操作系统是否为Android + if runtime.GOOS == "android" { + ip = "127.0.0.1" + } else { + // 获取内网IP地址 + ip, err = sys.GetLocalIP() + if err != nil { + log.Println("Error retrieving the local IP address:", err) + ip = "127.0.0.1" + } } // 将 替换成实际的内网IP地址 确保初始状态webui能够被访问 configData := strings.Replace(template.ConfigTemplate, "", ip, -1) diff --git a/mylog/mylog.go b/mylog/mylog.go index d3abdb85..748c8120 100644 --- a/mylog/mylog.go +++ b/mylog/mylog.go @@ -48,16 +48,30 @@ func GetLogLevelFromConfig(logLevel int) LogLevel { } } -// 接收新参数,并设置文件日志路径 -func NewMyLogAdapter(level LogLevel, enableFileLog bool) *MyLogAdapter { +var logPath string + +func init() { exePath, err := os.Executable() if err != nil { - panic(err) // 或者处理错误 + panic(err) } + exeDir := filepath.Dir(exePath) - logPath := filepath.Join(exeDir, "log") + logPath = filepath.Join(exeDir, "log") +} + +// 全局变量,用于存储日志启用状态 +var enableFileLogGlobal bool + +// SetEnableFileLog 设置 enableFileLogGlobal 的值 +func SetEnableFileLog(value bool) { + enableFileLogGlobal = value +} +// 接收新参数,并设置文件日志路径 +func NewMyLogAdapter(level LogLevel, enableFileLog bool) *MyLogAdapter { if enableFileLog { + SetEnableFileLog(true) if _, err := os.Stat(logPath); os.IsNotExist(err) { err := os.Mkdir(logPath, 0755) if err != nil { @@ -94,12 +108,34 @@ func (adapter *MyLogAdapter) logToFile(level, message string) { } } +// 独立的文件日志记录函数 +func LogToFile(level, message string) { + if !enableFileLogGlobal { + return + } + filename := time.Now().Format("2006-01-02") + ".log" + filepath := logPath + "/" + filename + + file, err := os.OpenFile(filepath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + fmt.Println("Error opening log file:", err) + return + } + defer file.Close() + + logEntry := fmt.Sprintf("[%s] %s: %s\n", time.Now().Format("2006-01-02T15:04:05"), level, message) + if _, err := file.WriteString(logEntry); err != nil { + fmt.Println("Error writing to log file:", err) + } +} + // Debug logs a message at the debug level. func (adapter *MyLogAdapter) Debug(v ...interface{}) { if adapter.Level <= LogLevelDebug { message := fmt.Sprint(v...) Println(v...) adapter.logToFile("DEBUG", message) + emitLog("DEBUG", message) } } @@ -109,6 +145,7 @@ func (adapter *MyLogAdapter) Info(v ...interface{}) { message := fmt.Sprint(v...) Println(v...) adapter.logToFile("INFO", message) + emitLog("INFO", message) } } @@ -118,6 +155,7 @@ func (adapter *MyLogAdapter) Warn(v ...interface{}) { message := fmt.Sprint(v...) Printf("WARN: %v\n", v...) adapter.logToFile("WARN", message) + emitLog("WARN", message) } } @@ -127,6 +165,7 @@ func (adapter *MyLogAdapter) Error(v ...interface{}) { message := fmt.Sprint(v...) Printf("ERROR: %v\n", v...) adapter.logToFile("ERROR", message) + emitLog("ERROR", message) } } @@ -136,6 +175,7 @@ func (adapter *MyLogAdapter) Debugf(format string, v ...interface{}) { message := fmt.Sprintf(format, v...) Printf("DEBUG: "+format, v...) adapter.logToFile("DEBUG", message) + emitLog("DEBUG", message) } } @@ -145,6 +185,7 @@ func (adapter *MyLogAdapter) Infof(format string, v ...interface{}) { message := fmt.Sprintf(format, v...) Printf("INFO: "+format, v...) adapter.logToFile("INFO", message) + emitLog("INFO", message) } } @@ -154,6 +195,7 @@ func (adapter *MyLogAdapter) Warnf(format string, v ...interface{}) { message := fmt.Sprintf(format, v...) Printf("WARN: "+format, v...) adapter.logToFile("WARN", message) + emitLog("WARN", message) } } @@ -163,6 +205,7 @@ func (adapter *MyLogAdapter) Errorf(format string, v ...interface{}) { message := fmt.Sprintf(format, v...) Printf("ERROR: "+format, v...) adapter.logToFile("ERROR", message) + emitLog("ERROR", message) } } @@ -184,8 +227,6 @@ type EnhancedLogEntry struct { Message string `json:"message"` } -//todo 下面的不会存入文件,上头的,不会进入ws,改一改 - // 日志频道,所有的 WebSocket 客户端都会在此监听日志事件 var logChannel = make(chan EnhancedLogEntry, 1000) @@ -193,24 +234,28 @@ func Println(v ...interface{}) { log.Println(v...) message := fmt.Sprint(v...) emitLog("INFO", message) + LogToFile("INFO", message) } func Printf(format string, v ...interface{}) { log.Printf(format, v...) message := fmt.Sprintf(format, v...) emitLog("INFO", message) + LogToFile("INFO", message) } func Errorf(format string, v ...interface{}) { log.Printf(format, v...) message := fmt.Sprintf(format, v...) emitLog("ERROR", message) + LogToFile("ERROR", message) } func Fatalf(format string, v ...interface{}) { log.Printf(format, v...) message := fmt.Sprintf(format, v...) emitLog("Fatal", message) + LogToFile("Fatal", message) } func emitLog(level, message string) { diff --git a/template/config_template.go b/template/config_template.go index 05b8ff09..4879eddc 100644 --- a/template/config_template.go +++ b/template/config_template.go @@ -76,6 +76,7 @@ settings: white_prefix_mode : false #公域 过审用 指令白名单模式开关 如果审核严格 请开启并设置白名单指令 以白名单开头的指令会被通过,反之被拦截 white_prefixs : [""] #可设置多个 比如设置 机器人 测试 则只有信息以机器人 测试开头会相应 remove_prefix remove_at 需为true时生效 + No_White_Response : "" #默认不兜底,强烈建议设置一个友善的兜底回复,告知审核机器人已无隐藏指令,如:你输入的指令不对哦,@机器人来获取可用指令 black_prefix_mode : false #公私域 过审用 指令黑名单模式开关 过滤被审核打回的指令不响应 无需改机器人后端 black_prefixs : [""] #可设置多个 比如设置 查询 则查询开头的信息均被拦截 防止审核失败 diff --git a/template/config_template.yml b/template/config_template.yml index d957f98f..7561155e 100644 --- a/template/config_template.yml +++ b/template/config_template.yml @@ -67,4 +67,5 @@ settings: remove_bot_at_group : true #因为群聊机器人不支持发at,开启本开关会自动隐藏群机器人发出的at(不影响频道场景) image_limit : 100 #每分钟上传的最大图片数量,可自行增加 record_sampleRate : 24000 #语音文件的采样率 最高48000 默认24000 单位Khz - record_bitRate : 24000 #语音文件的比特率 默认24000 代表 24 kbps 最高无限 请根据带宽 您发送的实际码率调整 \ No newline at end of file + record_bitRate : 24000 #语音文件的比特率 默认24000 代表 24 kbps 最高无限 请根据带宽 您发送的实际码率调整 + No_White_Response : "" #默认不兜底,强烈建议设置一个友善的兜底回复,告知审核机器人已无隐藏指令,如:你输入的指令不对哦,@机器人来获取可用指令 \ No newline at end of file