From ca914e2f1047c5e06160a8a0b941fdccb2f82e80 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Mon, 4 Mar 2024 22:26:33 +0800
Subject: [PATCH 01/33] beta338
---
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index 90341e90..56be0d40 100644
--- a/readme.md
+++ b/readme.md
@@ -45,7 +45,7 @@ _✨ 基于 [OneBot](https://github.com/howmanybots/onebot/blob/master/README.md
## 引用
-- [`tencent-connect/botgo`](https://github.com/tencent-connect/botgo): 本项目引用了此项目,并做了一点改动.
+- [`tencent-connect/botgo`](https://github.com/tencent-connect/botgo): 本项目引用了此项目,并做了一些改动.
## 兼容性
gensokyo兼容 [OneBot-v11](https://github.com/botuniverse/onebot-11) ,并在其基础上做了一些扩展,详情请看 OneBot 的文档。
From 62e6985c471557d623d073dd66af0ad48b034510 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Tue, 5 Mar 2024 23:58:15 +0800
Subject: [PATCH 02/33] beta319
---
config/config.go | 13 +++++++++++++
main.go | 5 +++--
template/config_template.go | 3 ++-
3 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/config/config.go b/config/config.go
index 205fc97e..e602bb82 100644
--- a/config/config.go
+++ b/config/config.go
@@ -151,6 +151,7 @@ type Settings struct {
AutoPutInteraction bool `yaml:"auto_put_interaction"`
PutInteractionDelay int `yaml:"put_interaction_delay"`
ImgUpApiVtv2 bool `yaml:"img_up_api_ntv2"`
+ Fix11300 bool `yaml:"fix_11300"`
}
// LoadConfig 从文件中加载配置并初始化单例配置
@@ -1870,3 +1871,15 @@ func GetImgUpApiVtv2() bool {
}
return instance.Settings.ImgUpApiVtv2
}
+
+// 获取Fix11300开关
+func GetFix11300() bool {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to Fix11300 value.")
+ return false
+ }
+ return instance.Settings.Fix11300
+}
diff --git a/main.go b/main.go
index 1cbe9545..d3282d49 100644
--- a/main.go
+++ b/main.go
@@ -155,8 +155,9 @@ func main() {
}
configURL := config.GetDevelop_Acdir()
+ fix11300 := config.GetFix11300()
var me *dto.User
- if configURL == "" { // 执行API请求 显示机器人信息
+ if configURL == "" && !fix11300 { // 执行API请求 显示机器人信息
me, err = api.Me(ctx) // Adjusted to pass only the context
if err != nil {
log.Printf("Error fetching bot details: %v\n", err)
@@ -168,7 +169,7 @@ func main() {
log.Printf("自定义ac地址模式...请从日志手动获取bot的真实id并设置,不然at会不正常")
}
if !nologin {
- if configURL == "" { //初始化handlers
+ if configURL == "" && !fix11300 { //初始化handlers
handlers.BotID = me.ID
} else { //初始化handlers
handlers.BotID = config.GetDevBotid()
diff --git a/template/config_template.go b/template/config_template.go
index 103b418f..a73f3442 100644
--- a/template/config_template.go
+++ b/template/config_template.go
@@ -134,7 +134,8 @@ settings:
shard_id: 0 #当前分片id 默认从0开始,详细请看 https://bot.q.qq.com/wiki/develop/api/gateway/reference.html
auto_put_interaction : false #自动回应按钮回调的/interactions/{interaction_id} 注本api需要邮件申请,详细方法参考群公告:196173384
put_interaction_delay : 0 #单位毫秒 表示回应已收到回调类型的按钮的毫秒数 会按用户进行区分 非全局delay
- img_up_api_ntv2: false #gsk内建图片上传api 是否将图片转换为ntqq图床url(md发图用,自行调用)文档:
+ img_up_api_ntv2: false #gsk内建图片上传api 是否将图片转换为ntqq图床url(md发图用,自行调用)文档:https://www.yuque.com/km57bt/hlhnxg/ig2nk88fccykn6dm
+ fix_11300: false #修复11300报错,需要在develop_bot_id填入自己机器人的appid. 11300原因暂时未知,临时修复方案.
title : "Gensokyo © 2023 - Hoshinonyaruko" #程序的标题 如果多个机器人 可根据标题区分
custom_bot_name : "Gensokyo全域机器人" #自定义机器人名字,会在api调用中返回,默认Gensokyo全域机器人
From 8c8792c75b786d03672bf570e22b315d10dc37c1 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Thu, 7 Mar 2024 18:54:58 +0800
Subject: [PATCH 03/33] beta340
---
Processor/ProcessGroupDelBot.go | 3 +
config/config.go | 13 ++++
handlers/get_group_list.go | 12 +++-
handlers/send_group_msg.go | 39 ++++++++++--
handlers/send_guild_channel_forum.go | 37 ++++++++++--
handlers/send_guild_channel_msg.go | 36 +++++++++--
handlers/send_msg.go | 60 ++++++++++++++++---
handlers/send_private_msg.go | 40 ++++++++++---
idmap/service.go | 89 +++++++++++++++++++++++-----
server/getIDHandler.go | 17 +++++-
template/config_template.go | 1 +
11 files changed, 300 insertions(+), 47 deletions(-)
diff --git a/Processor/ProcessGroupDelBot.go b/Processor/ProcessGroupDelBot.go
index 34803c29..5dfe2e65 100644
--- a/Processor/ProcessGroupDelBot.go
+++ b/Processor/ProcessGroupDelBot.go
@@ -2,6 +2,7 @@
package Processor
import (
+ "fmt"
"strconv"
"github.com/hoshinonyaruko/gensokyo/config"
@@ -50,6 +51,8 @@ func (p *Processors) ProcessGroupDelBot(data *dto.GroupAddBotEvent) error {
return nil
}
mylog.Printf("Bot被[%v]从群[%v]移出", userid64, GroupID64)
+ //从数据库删除群数据(仅删除类型缓存,再次加入会刷新)
+ idmap.DeleteConfigv2(fmt.Sprint(GroupID64), "type")
Notice = GroupNoticeEvent{
GroupID: GroupID64,
NoticeType: "group_decrease",
diff --git a/config/config.go b/config/config.go
index e602bb82..4f03406e 100644
--- a/config/config.go
+++ b/config/config.go
@@ -152,6 +152,7 @@ type Settings struct {
PutInteractionDelay int `yaml:"put_interaction_delay"`
ImgUpApiVtv2 bool `yaml:"img_up_api_ntv2"`
Fix11300 bool `yaml:"fix_11300"`
+ LotusWithoutIdmaps bool `yaml:"lotus_without_idmaps"`
}
// LoadConfig 从文件中加载配置并初始化单例配置
@@ -1883,3 +1884,15 @@ func GetFix11300() bool {
}
return instance.Settings.Fix11300
}
+
+// 获取LotusWithoutIdmaps开关
+func GetLotusWithoutIdmaps() bool {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to LotusWithoutIdmaps value.")
+ return false
+ }
+ return instance.Settings.LotusWithoutIdmaps
+}
diff --git a/handlers/get_group_list.go b/handlers/get_group_list.go
index 0acc64c4..61294642 100644
--- a/handlers/get_group_list.go
+++ b/handlers/get_group_list.go
@@ -110,20 +110,28 @@ func GetGroupList(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.Open
}
// 将channel信息转换为Group对象并添加到groups
for _, channel := range channels {
- //转换ChannelID64
+ // 转换ChannelID64
ChannelID64, err := idmap.StoreIDv2(channel.ID)
if err != nil {
mylog.Printf("Error storing ID: %v", err)
}
+
+ // 根据channel.Type添加前缀
+ groupName := channel.Name
+ if channel.Type == dto.ChannelTypeText {
+ groupName = "&" + groupName
+ }
+
channelGroup := Group{
GroupCreateTime: 0, // 频道没有直接对应的创建时间字段
GroupID: ChannelID64,
GroupLevel: 0, // 频道没有直接对应的级别字段
GroupMemo: "", // 频道没有直接对应的描述字段
- GroupName: channel.Name,
+ GroupName: groupName,
MaxMemberCount: 0, // 频道没有直接对应的最大成员数字段
MemberCount: 0, // 频道没有直接对应的成员数字段
}
+
groupList.Data = append(groupList.Data, channelGroup)
}
}
diff --git a/handlers/send_group_msg.go b/handlers/send_group_msg.go
index 9329bcdc..3e4f0c6f 100644
--- a/handlers/send_group_msg.go
+++ b/handlers/send_group_msg.go
@@ -36,18 +36,47 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
// 当 message.Echo 是字符串类型时执行此块
msgType = echo.GetMsgTypeByKey(echoStr)
}
- if msgType == "" {
+ // 检查GroupID是否为0
+ checkZeroGroupID := func(id interface{}) bool {
+ switch v := id.(type) {
+ case int:
+ return v != 0
+ case int64:
+ return v != 0
+ case string:
+ return v != "0" // 检查字符串形式的0
+ default:
+ return true // 如果不是int、int64或string,假定它不为0
+ }
+ }
+
+ // 检查UserID是否为0
+ checkZeroUserID := func(id interface{}) bool {
+ switch v := id.(type) {
+ case int:
+ return v != 0
+ case int64:
+ return v != 0
+ case string:
+ return v != "0" // 同样检查字符串形式的0
+ default:
+ return true // 如果不是int、int64或string,假定它不为0
+ }
+ }
+
+ if msgType == "" && message.Params.GroupID != nil && checkZeroGroupID(message.Params.GroupID) {
msgType = GetMessageTypeByGroupid(config.GetAppIDStr(), message.Params.GroupID)
}
- if msgType == "" {
+ if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUserid(config.GetAppIDStr(), message.Params.UserID)
}
- if msgType == "" {
+ if msgType == "" && message.Params.GroupID != nil && checkZeroGroupID(message.Params.GroupID) {
msgType = GetMessageTypeByGroupidV2(message.Params.GroupID)
}
- if msgType == "" {
+ if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUseridV2(message.Params.UserID)
}
+
mylog.Printf("send_group_msg获取到信息类型:%v", msgType)
var idInt64 int64
var err error
@@ -493,7 +522,7 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
echo.AddMsgType(config.GetAppIDStr(), idInt64, tryMessageTypes[echo.GetMapping(idInt64)-1])
delay := config.GetSendDelay()
time.Sleep(time.Duration(delay) * time.Millisecond)
- HandleSendGroupMsg(client, api, apiv2, messageCopy)
+ retmsg, _ = HandleSendGroupMsg(client, api, apiv2, messageCopy)
}
return retmsg, nil
}
diff --git a/handlers/send_guild_channel_forum.go b/handlers/send_guild_channel_forum.go
index a812d869..7b1d5ee4 100644
--- a/handlers/send_guild_channel_forum.go
+++ b/handlers/send_guild_channel_forum.go
@@ -30,18 +30,47 @@ func HandleSendGuildChannelForum(client callapi.Client, api openapi.OpenAPI, api
// 当 message.Echo 是字符串类型时执行此块
msgType = echo.GetMsgTypeByKey(echoStr)
}
- if msgType == "" {
+ // 检查GroupID是否为0
+ checkZeroGroupID := func(id interface{}) bool {
+ switch v := id.(type) {
+ case int:
+ return v != 0
+ case int64:
+ return v != 0
+ case string:
+ return v != "0" // 检查字符串形式的0
+ default:
+ return true // 如果不是int、int64或string,假定它不为0
+ }
+ }
+
+ // 检查UserID是否为0
+ checkZeroUserID := func(id interface{}) bool {
+ switch v := id.(type) {
+ case int:
+ return v != 0
+ case int64:
+ return v != 0
+ case string:
+ return v != "0" // 同样检查字符串形式的0
+ default:
+ return true // 如果不是int、int64或string,假定它不为0
+ }
+ }
+
+ if msgType == "" && message.Params.GroupID != nil && checkZeroGroupID(message.Params.GroupID) {
msgType = GetMessageTypeByGroupid(config.GetAppIDStr(), message.Params.GroupID)
}
- if msgType == "" {
+ if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUserid(config.GetAppIDStr(), message.Params.UserID)
}
- if msgType == "" {
+ if msgType == "" && message.Params.GroupID != nil && checkZeroGroupID(message.Params.GroupID) {
msgType = GetMessageTypeByGroupidV2(message.Params.GroupID)
}
- if msgType == "" {
+ if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUseridV2(message.Params.UserID)
}
+
//当不转换频道信息时(不支持频道私聊)
if msgType == "" {
msgType = "forum"
diff --git a/handlers/send_guild_channel_msg.go b/handlers/send_guild_channel_msg.go
index 94bb86fc..a9e8a48b 100644
--- a/handlers/send_guild_channel_msg.go
+++ b/handlers/send_guild_channel_msg.go
@@ -34,16 +34,44 @@ func HandleSendGuildChannelMsg(client callapi.Client, api openapi.OpenAPI, apiv2
// 当 message.Echo 是字符串类型时执行此块
msgType = echo.GetMsgTypeByKey(echoStr)
}
- if msgType == "" {
+ // 检查GroupID是否为0
+ checkZeroGroupID := func(id interface{}) bool {
+ switch v := id.(type) {
+ case int:
+ return v != 0
+ case int64:
+ return v != 0
+ case string:
+ return v != "0" // 检查字符串形式的0
+ default:
+ return true // 如果不是int、int64或string,假定它不为0
+ }
+ }
+
+ // 检查UserID是否为0
+ checkZeroUserID := func(id interface{}) bool {
+ switch v := id.(type) {
+ case int:
+ return v != 0
+ case int64:
+ return v != 0
+ case string:
+ return v != "0" // 同样检查字符串形式的0
+ default:
+ return true // 如果不是int、int64或string,假定它不为0
+ }
+ }
+
+ if msgType == "" && message.Params.GroupID != nil && checkZeroGroupID(message.Params.GroupID) {
msgType = GetMessageTypeByGroupid(config.GetAppIDStr(), message.Params.GroupID)
}
- if msgType == "" {
+ if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUserid(config.GetAppIDStr(), message.Params.UserID)
}
- if msgType == "" {
+ if msgType == "" && message.Params.GroupID != nil && checkZeroGroupID(message.Params.GroupID) {
msgType = GetMessageTypeByGroupidV2(message.Params.GroupID)
}
- if msgType == "" {
+ if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUseridV2(message.Params.UserID)
}
//当不转换频道信息时(不支持频道私聊)
diff --git a/handlers/send_msg.go b/handlers/send_msg.go
index f95751f9..f9aca80a 100644
--- a/handlers/send_msg.go
+++ b/handlers/send_msg.go
@@ -25,28 +25,72 @@ func HandleSendMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.Ope
// 当 message.Echo 是字符串类型时执行此块
msgType = echo.GetMsgTypeByKey(echoStr)
}
- if msgType == "" {
+ // 检查GroupID是否为0
+ checkZeroGroupID := func(id interface{}) bool {
+ switch v := id.(type) {
+ case int:
+ return v != 0
+ case int64:
+ return v != 0
+ case string:
+ return v != "0" // 检查字符串形式的0
+ default:
+ return true // 如果不是int、int64或string,假定它不为0
+ }
+ }
+
+ // 检查UserID是否为0
+ checkZeroUserID := func(id interface{}) bool {
+ switch v := id.(type) {
+ case int:
+ return v != 0
+ case int64:
+ return v != 0
+ case string:
+ return v != "0" // 同样检查字符串形式的0
+ default:
+ return true // 如果不是int、int64或string,假定它不为0
+ }
+ }
+
+ if msgType == "" && message.Params.GroupID != nil && checkZeroGroupID(message.Params.GroupID) {
msgType = GetMessageTypeByGroupid(config.GetAppIDStr(), message.Params.GroupID)
}
- if msgType == "" {
+ if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUserid(config.GetAppIDStr(), message.Params.UserID)
}
- if msgType == "" {
+ if msgType == "" && message.Params.GroupID != nil && checkZeroGroupID(message.Params.GroupID) {
msgType = GetMessageTypeByGroupidV2(message.Params.GroupID)
}
- if msgType == "" {
+ if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUseridV2(message.Params.UserID)
}
var idInt64, idInt642 int64
var err error
+ var tempErr error
+
if message.Params.GroupID != "" {
- idInt64, err = ConvertToInt64(message.Params.GroupID)
- idInt642, err = ConvertToInt64(message.Params.UserID)
+ idInt64, tempErr = ConvertToInt64(message.Params.GroupID)
+ if tempErr != nil {
+ err = tempErr
+ }
+ idInt642, tempErr = ConvertToInt64(message.Params.UserID)
+ if tempErr != nil {
+ err = tempErr
+ }
+
} else if message.Params.UserID != "" {
- idInt64, err = ConvertToInt64(message.Params.UserID)
- idInt642, err = ConvertToInt64(message.Params.GroupID)
+ idInt64, tempErr = ConvertToInt64(message.Params.UserID)
+ if tempErr != nil {
+ err = tempErr
+ }
+ idInt642, tempErr = ConvertToInt64(message.Params.GroupID)
+ if tempErr != nil {
+ err = tempErr
+ }
+
}
//设置递归 对直接向gsk发送action时有效果
diff --git a/handlers/send_private_msg.go b/handlers/send_private_msg.go
index 573e588b..e71c493b 100644
--- a/handlers/send_private_msg.go
+++ b/handlers/send_private_msg.go
@@ -27,20 +27,44 @@ func HandleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open
// 当 message.Echo 是字符串类型时执行此块
msgType = echo.GetMsgTypeByKey(echoStr)
}
+ // 检查GroupID是否为0
+ checkZeroGroupID := func(id interface{}) bool {
+ switch v := id.(type) {
+ case int:
+ return v != 0
+ case int64:
+ return v != 0
+ case string:
+ return v != "0" // 检查字符串形式的0
+ default:
+ return true // 如果不是int、int64或string,假定它不为0
+ }
+ }
- //如果获取不到 就用user_id获取信息类型
- if msgType == "" {
+ // 检查UserID是否为0
+ checkZeroUserID := func(id interface{}) bool {
+ switch v := id.(type) {
+ case int:
+ return v != 0
+ case int64:
+ return v != 0
+ case string:
+ return v != "0" // 同样检查字符串形式的0
+ default:
+ return true // 如果不是int、int64或string,假定它不为0
+ }
+ }
+
+ if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUserid(config.GetAppIDStr(), message.Params.UserID)
}
- //顺序,私聊优先从UserID推断类型会更准确
- if msgType == "" {
+ if msgType == "" && message.Params.GroupID != nil && checkZeroGroupID(message.Params.GroupID) {
msgType = GetMessageTypeByGroupid(config.GetAppIDStr(), message.Params.GroupID)
}
- //新增 内存获取不到从数据库获取
- if msgType == "" {
+ if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUseridV2(message.Params.UserID)
}
- if msgType == "" {
+ if msgType == "" && message.Params.GroupID != nil && checkZeroGroupID(message.Params.GroupID) {
msgType = GetMessageTypeByGroupidV2(message.Params.GroupID)
}
var idInt64 int64
@@ -292,7 +316,7 @@ func HandleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open
echo.AddMsgType(config.GetAppIDStr(), idInt64, tryMessageTypes[echo.GetMapping(idInt64)-1])
delay := config.GetSendDelay()
time.Sleep(time.Duration(delay) * time.Millisecond)
- HandleSendPrivateMsg(client, api, apiv2, messageCopy)
+ retmsg, _ = HandleSendPrivateMsg(client, api, apiv2, messageCopy)
}
return retmsg, nil
}
diff --git a/idmap/service.go b/idmap/service.go
index 0fd44e65..844486d0 100644
--- a/idmap/service.go
+++ b/idmap/service.go
@@ -217,7 +217,7 @@ func SimplifiedStoreID(id string) (int64, error) {
// SimplifiedStoreID 根据a储存b 储存一半
func SimplifiedStoreIDv2(id string) (int64, error) {
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
// 使用网络请求方式
serverDir := config.GetServer_dir()
portValue := config.GetPortValue()
@@ -253,7 +253,7 @@ func SimplifiedStoreIDv2(id string) (int64, error) {
return int64(rowValue), nil
}
- // 如果lotus为假,就保持原来的store的方法
+ // 如果lotus为假,或不走idmaps是真,就保持原来的store的方法
return SimplifiedStoreID(id)
}
@@ -305,7 +305,7 @@ func StoreIDPro(id string, subid string) (int64, int64, error) {
// StoreIDv2 根据a储存b
func StoreIDv2(id string) (int64, error) {
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
// 使用网络请求方式
serverDir := config.GetServer_dir()
portValue := config.GetPortValue()
@@ -347,7 +347,7 @@ func StoreIDv2(id string) (int64, error) {
// 群号 然后 用户号
func StoreIDv2Pro(id string, subid string) (int64, int64, error) {
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
// 使用网络请求方式
serverDir := config.GetServer_dir()
portValue := config.GetPortValue()
@@ -413,7 +413,7 @@ func RetrieveRowByID(rowid string) (string, error) {
// 群号 然后 用户号
func RetrieveRowByIDv2Pro(newRowID string, newSubRowID string) (string, string, error) {
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
// 使用网络请求方式
serverDir := config.GetServer_dir()
portValue := config.GetPortValue()
@@ -495,7 +495,7 @@ func RetrieveRowByIDv2(rowid string) (string, error) {
protocol = "https"
}
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
// 使用网络请求方式
serverDir := config.GetServer_dir()
@@ -550,7 +550,7 @@ func WriteConfig(sectionName, keyName, value string) error {
// WriteConfigv2 根据a以b为类别储存c
func WriteConfigv2(sectionName, keyName, value string) error {
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
// 使用网络请求方式
serverDir := config.GetServer_dir()
portValue := config.GetPortValue()
@@ -610,6 +610,65 @@ func ReadConfig(sectionName, keyName string) (string, error) {
return result, err
}
+// DeleteConfig根据sectionName和keyName删除指定的键值对
+func DeleteConfig(sectionName, keyName string) error {
+ return db.Update(func(tx *bolt.Tx) error {
+ b := tx.Bucket([]byte(ConfigBucket))
+ if b == nil {
+ return fmt.Errorf("bucket %s does not exist", ConfigBucket)
+ }
+
+ key := joinSectionAndKey(sectionName, keyName)
+ err := b.Delete(key)
+ if err != nil {
+ return fmt.Errorf("failed to delete data with key %s: %w", key, err)
+ }
+
+ return nil
+ })
+}
+
+// DeleteConfigv2 根据sectionName和keyName远程删除配置
+func DeleteConfigv2(sectionName, keyName string) error {
+ // 根据portValue确定协议
+ protocol := "http"
+ portValue := config.GetPortValue()
+ if portValue == "443" {
+ protocol = "https"
+ }
+
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
+ // 使用网络请求方式
+ serverDir := config.GetServer_dir()
+
+ // 构建请求URL和参数
+ baseURL := fmt.Sprintf("%s://%s:%s/getid", protocol, serverDir, portValue)
+ params := url.Values{}
+ params.Add("type", "15") // type 15是用于删除操作的
+ params.Add("id", sectionName)
+ params.Add("subtype", keyName)
+ url := baseURL + "?" + params.Encode()
+
+ resp, err := http.Get(url)
+ if err != nil {
+ return fmt.Errorf("failed to send request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ // 如果HTTP状态码是200 OK,表示操作成功完成
+ if resp.StatusCode == http.StatusOK {
+ // 成功,可以返回nil或者根据需要返回具体的成功消息
+ return nil
+ } else {
+ // 如果状态码不是200 OK,返回错误信息
+ return fmt.Errorf("error response from server: %s", resp.Status)
+ }
+ }
+
+ // 如果lotus为假,则使用原始方法在本地删除配置
+ return DeleteConfig(sectionName, keyName) // 假设你已经有了一个本地删除的方法
+}
+
// ReadConfigv2 根据a和b取出c
func ReadConfigv2(sectionName, keyName string) (string, error) {
// 根据portValue确定协议
@@ -619,7 +678,7 @@ func ReadConfigv2(sectionName, keyName string) (string, error) {
protocol = "https"
}
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
// 使用网络请求方式
serverDir := config.GetServer_dir()
@@ -756,7 +815,7 @@ func RetrieveVirtualValue(realValue string) (string, string, error) {
// 更新真实值对应的虚拟值
func UpdateVirtualValuev2(oldRowValue, newRowValue int64) error {
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
// 构建请求URL
serverDir := config.GetServer_dir()
portValue := config.GetPortValue()
@@ -783,7 +842,7 @@ func UpdateVirtualValuev2(oldRowValue, newRowValue int64) error {
// RetrieveRealValuev2 根据虚拟值获取真实值
func RetrieveRealValuev2(virtualValue int64) (string, string, error) {
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
serverDir := config.GetServer_dir()
portValue := config.GetPortValue()
protocol := "http"
@@ -818,7 +877,7 @@ func RetrieveRealValuev2(virtualValue int64) (string, string, error) {
// RetrieveVirtualValuev2 根据真实值获取虚拟值
func RetrieveVirtualValuev2(realValue string) (string, string, error) {
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
// 使用网络请求方式
serverDir := config.GetServer_dir()
portValue := config.GetPortValue()
@@ -860,7 +919,7 @@ func RetrieveVirtualValuev2(realValue string) (string, string, error) {
// 根据2个真实值 获取2个虚拟值 群号 然后 用户号
func RetrieveVirtualValuev2Pro(realValue string, realValueSub string) (string, string, error) {
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
// 使用网络请求方式
serverDir := config.GetServer_dir()
portValue := config.GetPortValue()
@@ -974,7 +1033,7 @@ func RetrieveRealValuePro(virtualValue1, virtualValue2 int64) (string, string, e
// RetrieveRealValuesv2Pro 根据两个虚拟值获取两个真实值 群号 然后 用户号
func RetrieveRealValuesv2Pro(virtualValue int64, virtualValueSub int64) (string, string, error) {
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
// 使用网络请求方式
serverDir := config.GetServer_dir()
portValue := config.GetPortValue()
@@ -1057,7 +1116,7 @@ func UpdateVirtualValuePro(oldVirtualValue1, newVirtualValue1, oldVirtualValue2,
// UpdateVirtualValuev2Pro 根据配置更新两对虚拟值 旧群 新群 旧用户 新用户
func UpdateVirtualValuev2Pro(oldVirtualValue1, newVirtualValue1, oldVirtualValue2, newVirtualValue2 int64) error {
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
// 构建请求URL
serverDir := config.GetServer_dir()
portValue := config.GetPortValue()
@@ -1147,7 +1206,7 @@ func FindSubKeysById(id string) ([]string, error) {
// FindSubKeysByIdPro 根据1个值获取key中的k:v给出k获取所有v,通过网络调用
func FindSubKeysByIdPro(id string) ([]string, error) {
- if config.GetLotusValue() {
+ if config.GetLotusValue() && !config.GetLotusWithoutIdmaps() {
// 使用网络请求方式
serverDir := config.GetServer_dir()
portValue := config.GetPortValue()
diff --git a/server/getIDHandler.go b/server/getIDHandler.go
index 338052df..9c01cbff 100644
--- a/server/getIDHandler.go
+++ b/server/getIDHandler.go
@@ -221,8 +221,23 @@ func GetIDHandler(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
-
c.JSON(http.StatusOK, gin.H{"keys": keys})
+ case 15:
+ // 删除
+ // 从请求中获取参数
+ section := c.Query("id")
+ subtype := c.Query("subtype")
+
+ // 调用DeleteConfigv2来删除配置
+ err := idmap.DeleteConfigv2(section, subtype)
+ if err != nil {
+ // 如果有错误,记录并返回错误信息
+ c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
+ return
+ }
+
+ // 如果删除成功,返回成功响应
+ c.JSON(http.StatusOK, gin.H{"status": "success"})
}
}
diff --git a/template/config_template.go b/template/config_template.go
index a73f3442..a0a255e2 100644
--- a/template/config_template.go
+++ b/template/config_template.go
@@ -136,6 +136,7 @@ settings:
put_interaction_delay : 0 #单位毫秒 表示回应已收到回调类型的按钮的毫秒数 会按用户进行区分 非全局delay
img_up_api_ntv2: false #gsk内建图片上传api 是否将图片转换为ntqq图床url(md发图用,自行调用)文档:https://www.yuque.com/km57bt/hlhnxg/ig2nk88fccykn6dm
fix_11300: false #修复11300报错,需要在develop_bot_id填入自己机器人的appid. 11300原因暂时未知,临时修复方案.
+ lotus_without_idmaps: false #lotus只通过url,图片上传,语音,不通过id转换,在本地当前gsk维护idmaps转换.
title : "Gensokyo © 2023 - Hoshinonyaruko" #程序的标题 如果多个机器人 可根据标题区分
custom_bot_name : "Gensokyo全域机器人" #自定义机器人名字,会在api调用中返回,默认Gensokyo全域机器人
From 5fe4fae6acdecc551f3d844c87c92a0e241c40fc Mon Sep 17 00:00:00 2001
From: cosmo
Date: Sun, 17 Mar 2024 22:48:38 +0800
Subject: [PATCH 04/33] beta341
---
.github/workflows/cross_compile.yml | 14 ++++++++++++--
main.go | 4 ++--
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/cross_compile.yml b/.github/workflows/cross_compile.yml
index 6d600158..a712a2cc 100644
--- a/.github/workflows/cross_compile.yml
+++ b/.github/workflows/cross_compile.yml
@@ -95,11 +95,21 @@ jobs:
CGO_ENABLED: 0
run: |
if [ "$GOOS" = "windows" ]; then
- go build -o output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}.exe
+ go build -ldflags="-s -w" -o output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}.exe
else
- go build -o output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}
+ go build -ldflags="-s -w" -o output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}
fi
+ - name: Compress executable files with UPX
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y upx
+ if [ "$GOOS" = "windows" ]; then
+ upx --best --lzma output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}.exe
+ else
+ upx --best --lzma output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}
+ fi
+
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
diff --git a/main.go b/main.go
index d3282d49..66037a94 100644
--- a/main.go
+++ b/main.go
@@ -276,8 +276,8 @@ func main() {
// 所有客户端都成功初始化
p = Processor.NewProcessor(api, apiV2, &conf.Settings, wsClients)
}
- } else if conf.Settings.EnableWsServer {
- log.Println("只启动正向ws")
+ } else {
+ log.Println("提示,目前只启动了正向ws或httpapi")
p = Processor.NewProcessorV2(api, apiV2, &conf.Settings)
}
} else {
From bdb5874b4db45945ba528d3e0ec1a895c484b63d Mon Sep 17 00:00:00 2001
From: cosmo
Date: Sun, 17 Mar 2024 22:50:53 +0800
Subject: [PATCH 05/33] actionfix
---
.github/workflows/cross_compile.yml | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/cross_compile.yml b/.github/workflows/cross_compile.yml
index a712a2cc..bd429339 100644
--- a/.github/workflows/cross_compile.yml
+++ b/.github/workflows/cross_compile.yml
@@ -101,14 +101,14 @@ jobs:
fi
- name: Compress executable files with UPX
- run: |
- sudo apt-get update
- sudo apt-get install -y upx
- if [ "$GOOS" = "windows" ]; then
- upx --best --lzma output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}.exe
- else
- upx --best --lzma output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}
- fi
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y upx
+ if [ "$GOOS" = "windows" ]; then
+ upx --best --lzma output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}.exe
+ else
+ upx --best --lzma output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}
+ fi
- name: Upload artifacts
uses: actions/upload-artifact@v2
From b2f53f5a944b35060a72bf9b106028804ccfc869 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Sun, 17 Mar 2024 23:07:59 +0800
Subject: [PATCH 06/33] beta342
---
.github/workflows/cross_compile.yml | 2 +-
readme.md | 6 +++++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/cross_compile.yml b/.github/workflows/cross_compile.yml
index bd429339..62aac0ae 100644
--- a/.github/workflows/cross_compile.yml
+++ b/.github/workflows/cross_compile.yml
@@ -104,7 +104,7 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y upx
- if [ "$GOOS" = "windows" ]; then
+ if [[ "${{ matrix.os }}" == *"windows"* ]]; then
upx --best --lzma output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}.exe
else
upx --best --lzma output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}
diff --git a/readme.md b/readme.md
index 56be0d40..7578a14d 100644
--- a/readme.md
+++ b/readme.md
@@ -47,7 +47,7 @@ _✨ 基于 [OneBot](https://github.com/howmanybots/onebot/blob/master/README.md
## 引用
- [`tencent-connect/botgo`](https://github.com/tencent-connect/botgo): 本项目引用了此项目,并做了一些改动.
-## 兼容性
+## 介绍
gensokyo兼容 [OneBot-v11](https://github.com/botuniverse/onebot-11) ,并在其基础上做了一些扩展,详情请看 OneBot 的文档。
可将官方的websocket和api转换至onebotv11标准,
@@ -66,6 +66,10 @@ gensokyo兼容 [OneBot-v11](https://github.com/botuniverse/onebot-11) ,并在
欢迎测试,询问任何有关使用的问题,有问必答,有难必帮~
+[Gensokyo临时文档](https://www.yuque.com/km57bt/hlhnxg/mw7gm8dlpccd324e)展开左侧折叠栏,临时文档包含markdown定义、额外api文档等内容
+
+后续会将文档独立,因为语雀文档公开查看无需登录需要vip,故暂时放在我的机器人文档中。
+
## 特别鸣谢
- [`mnixry/nonebot-plugin-gocqhttp`](https://github.com/mnixry/nonebot-plugin-gocqhttp/): 本项目采用了mnixry编写的前端,并实现了与它对应的,基于qq官方api的后端api.
From 666ea3a81878b16769e80c6b1a191d946249746d Mon Sep 17 00:00:00 2001
From: cosmo
Date: Sun, 17 Mar 2024 23:09:05 +0800
Subject: [PATCH 07/33] beta342
---
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index 7578a14d..b77013a7 100644
--- a/readme.md
+++ b/readme.md
@@ -68,7 +68,7 @@ gensokyo兼容 [OneBot-v11](https://github.com/botuniverse/onebot-11) ,并在
[Gensokyo临时文档](https://www.yuque.com/km57bt/hlhnxg/mw7gm8dlpccd324e)展开左侧折叠栏,临时文档包含markdown定义、额外api文档等内容
-后续会将文档独立,因为语雀文档公开查看无需登录需要vip,故暂时放在我的机器人文档中。
+后续会将文档独立,因为语雀文档公开查看无需登录需要vip,故暂时放在我的机器人文档中。临时文档也包含了Gensokyo的完整编译教程。
## 特别鸣谢
From a5e3867f339acf7a55b4f61fce2fff82b096711c Mon Sep 17 00:00:00 2001
From: cosmo
Date: Sun, 17 Mar 2024 23:13:44 +0800
Subject: [PATCH 08/33] beta342
---
.github/workflows/cross_compile.yml | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/cross_compile.yml b/.github/workflows/cross_compile.yml
index 62aac0ae..eeb57fce 100644
--- a/.github/workflows/cross_compile.yml
+++ b/.github/workflows/cross_compile.yml
@@ -100,14 +100,19 @@ jobs:
go build -ldflags="-s -w" -o output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}
fi
- - name: Compress executable files with UPX
+ - name: Compress executable files with UPX (except for gensokyo-android-arm64)
run: |
sudo apt-get update
sudo apt-get install -y upx
if [[ "${{ matrix.os }}" == *"windows"* ]]; then
- upx --best --lzma output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}.exe
+ FILENAME="output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}.exe"
else
- upx --best --lzma output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}
+ FILENAME="output/gensokyo-${{ matrix.os }}-${{ matrix.goarch }}"
+ fi
+ if [[ "${{ matrix.os }}" == "android" && "${{ matrix.goarch }}" == "arm64" ]]; then
+ echo "Skipping UPX compression for $FILENAME"
+ else
+ upx --best --lzma "$FILENAME"
fi
- name: Upload artifacts
From a217d2f84cff319c212036c8bb9fcb7edb6396ea Mon Sep 17 00:00:00 2001
From: cosmo
Date: Mon, 18 Mar 2024 13:26:29 +0800
Subject: [PATCH 09/33] beta344
---
config/config.go | 65 ++++++++++++
handlers/get_group_list.go | 190 +++++++++++++++++++++++-------------
template/config_template.go | 6 ++
3 files changed, 193 insertions(+), 68 deletions(-)
diff --git a/config/config.go b/config/config.go
index 4f03406e..2f68ec44 100644
--- a/config/config.go
+++ b/config/config.go
@@ -153,6 +153,11 @@ type Settings struct {
ImgUpApiVtv2 bool `yaml:"img_up_api_ntv2"`
Fix11300 bool `yaml:"fix_11300"`
LotusWithoutIdmaps bool `yaml:"lotus_without_idmaps"`
+ GetGroupListAllGuilds bool `yaml:"get_g_list_all_guilds"`
+ GetGroupListGuilds string `yaml:"get_g_list_guilds"`
+ GetGroupListReturnGuilds bool `yaml:"get_g_list_return_guilds"`
+ GetGroupListGuidsType int `yaml:"get_g_list_guilds_type"`
+ GetGroupListDelay int `yaml:"get_g_list_delay"`
}
// LoadConfig 从文件中加载配置并初始化单例配置
@@ -1896,3 +1901,63 @@ func GetLotusWithoutIdmaps() bool {
}
return instance.Settings.LotusWithoutIdmaps
}
+
+// 获取GetGroupListAllGuilds开关
+func GetGroupListAllGuilds() bool {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to GetGroupListAllGuilds value.")
+ return false
+ }
+ return instance.Settings.GetGroupListAllGuilds
+}
+
+// 获取 GetGroupListGuilds 数量
+func GetGetGroupListGuilds() string {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to get GetGroupListGuilds.")
+ return "10"
+ }
+ return instance.Settings.GetGroupListGuilds
+}
+
+// 获取GetGroupListReturnGuilds开关
+func GetGroupListReturnGuilds() bool {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to GetGroupListReturnGuilds value.")
+ return false
+ }
+ return instance.Settings.GetGroupListReturnGuilds
+}
+
+// 获取 GetGroupListGuidsType 数量
+func GetGroupListGuidsType() int {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to get GetGroupListGuidsType.")
+ return 0
+ }
+ return instance.Settings.GetGroupListGuidsType
+}
+
+// 获取 GetGroupListDelay 数量
+func GetGroupListDelay() int {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to get GetGroupListDelay.")
+ return 0
+ }
+ return instance.Settings.GetGroupListDelay
+}
diff --git a/handlers/get_group_list.go b/handlers/get_group_list.go
index 61294642..712c5b0c 100644
--- a/handlers/get_group_list.go
+++ b/handlers/get_group_list.go
@@ -7,6 +7,7 @@ import (
"time"
"github.com/hoshinonyaruko/gensokyo/callapi"
+ "github.com/hoshinonyaruko/gensokyo/config"
"github.com/hoshinonyaruko/gensokyo/idmap"
"github.com/hoshinonyaruko/gensokyo/mylog"
"github.com/tencent-connect/botgo/dto"
@@ -59,82 +60,67 @@ func GetGroupList(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.Open
// 初始化 groupList.Data 为一个空数组
groupList.Data = []Group{}
- // 检查时间差异
- if time.Since(lastCallTime) > 5*time.Minute {
- // 如果超过5分钟,则重置分页状态
- globalPager = &dto.GuildPager{Limit: "10"}
- }
- // 全局pager
- guilds, err := api.MeGuilds(context.TODO(), globalPager)
- if err != nil {
- mylog.Println("Error fetching guild list:", err)
- return "", nil
- }
- if len(guilds) > 0 {
- // 更新Pager的After为最后一个元素的ID
- globalPager.After = guilds[len(guilds)-1].ID
- }
- lastCallTime = time.Now() // 更新上次调用API的时间
- //如果为空 则不使用分页
- if len(guilds) == 0 {
- Pager := &dto.GuildPager{Limit: "10"}
- guilds, err = api.MeGuilds(context.TODO(), Pager)
- if err != nil {
- mylog.Println("Error fetching guild list2:", err)
- return "", nil
- }
- }
- for _, guild := range guilds {
- joinedAtTime, err := guild.JoinedAt.Time()
- if err != nil {
- mylog.Println("Error parsing JoinedAt timestamp:", err)
- continue
- }
- groupID, _ := strconv.ParseInt(guild.ID, 10, 64)
- joinedAtTimestamp := int32(joinedAtTime.Unix()) // 获取 10 位时间戳并转换为 int32 类型
- group := Group{
- GroupCreateTime: joinedAtTimestamp,
- GroupID: groupID,
- GroupLevel: 0,
- GroupMemo: guild.Desc,
- GroupName: "*" + guild.Name,
- MaxMemberCount: int32(guild.MaxMembers), // 确保这里也是 int32 类型
- MemberCount: int32(guild.MemberCount), // 将这里也转换为 int32 类型
- }
- groupList.Data = append(groupList.Data, group)
- // 获取每个guild的channel信息
- channels, err := api.Channels(context.TODO(), guild.ID) // 使用guild.ID作为参数
- if err != nil {
- mylog.Println("Error fetching channels list:", err)
- continue
- }
- // 将channel信息转换为Group对象并添加到groups
- for _, channel := range channels {
- // 转换ChannelID64
- ChannelID64, err := idmap.StoreIDv2(channel.ID)
+ if config.GetGroupListAllGuilds() {
+ pager := &dto.GuildPager{Limit: "100"}
+ totalFetched := 0
+
+ for {
+ guilds, err := api.MeGuilds(context.TODO(), pager)
if err != nil {
- mylog.Printf("Error storing ID: %v", err)
+ mylog.Println("Error fetching guild list:", err)
+ break
}
- // 根据channel.Type添加前缀
- groupName := channel.Name
- if channel.Type == dto.ChannelTypeText {
- groupName = "&" + groupName
+ fetched := len(guilds)
+ if fetched == 0 {
+ break // 没有更多数据时退出循环
}
- channelGroup := Group{
- GroupCreateTime: 0, // 频道没有直接对应的创建时间字段
- GroupID: ChannelID64,
- GroupLevel: 0, // 频道没有直接对应的级别字段
- GroupMemo: "", // 频道没有直接对应的描述字段
- GroupName: groupName,
- MaxMemberCount: 0, // 频道没有直接对应的最大成员数字段
- MemberCount: 0, // 频道没有直接对应的成员数字段
- }
+ totalFetched += fetched
+ requestCount := totalFetched / 100
+ mylog.Printf("Fetched %d guilds in request %d, total %d guilds\n", fetched, requestCount, totalFetched)
+
+ // 更新after,准备下一次请求
+ pager.After = guilds[fetched-1].ID
- groupList.Data = append(groupList.Data, channelGroup)
+ for _, guild := range guilds {
+ ProcessGuildAndChannels(guild, api, &groupList.Data)
+ }
+ delay := config.GetGroupListDelay() // 获取配置中的延迟时间,单位为毫秒
+ time.Sleep(time.Duration(delay) * time.Millisecond) // 使用配置的延迟时间
+ }
+ } else if config.GetGroupListReturnGuilds() {
+ // 检查时间差异
+ if time.Since(lastCallTime) > 5*time.Minute {
+ // 如果超过5分钟,则重置分页状态
+ guildsLimit := config.GetGetGroupListGuilds()
+ globalPager = &dto.GuildPager{Limit: guildsLimit}
+ }
+ // 全局pager
+ guilds, err := api.MeGuilds(context.TODO(), globalPager)
+ if err != nil {
+ mylog.Println("Error fetching guild list:", err)
+ return "", nil
+ }
+ if len(guilds) > 0 {
+ // 更新Pager的After为最后一个元素的ID
+ globalPager.After = guilds[len(guilds)-1].ID
+ }
+ lastCallTime = time.Now() // 更新上次调用API的时间
+ //如果为空 则不使用分页
+ if len(guilds) == 0 {
+ Pager := &dto.GuildPager{Limit: "10"}
+ guilds, err = api.MeGuilds(context.TODO(), Pager)
+ if err != nil {
+ mylog.Println("Error fetching guild list2:", err)
+ return "", nil
+ }
+ }
+ for _, guild := range guilds {
+ ProcessGuildAndChannels(guild, api, &groupList.Data)
}
}
+
//从idmaps数据库找群,组合成群列表需要的格式
groupIDs, err := idmap.FindKeysBySubAndType("group", "type")
if err != nil {
@@ -189,3 +175,71 @@ func GetGroupList(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.Open
mylog.Printf("get_group_list: %s", result)
return string(result), nil
}
+
+// ProcessGuildAndChannels 处理单个guild及其channels,并将结果添加到groupList.Data
+func ProcessGuildAndChannels(guild *dto.Guild, api openapi.OpenAPI, groupListData *[]Group) {
+ joinedAtTime, err := guild.JoinedAt.Time()
+ if err != nil {
+ mylog.Println("Error parsing JoinedAt timestamp:", err)
+ return
+ }
+ groupID, _ := strconv.ParseInt(guild.ID, 10, 64)
+ joinedAtTimestamp := int32(joinedAtTime.Unix()) // 获取 10 位时间戳并转换为 int32 类型
+ group := Group{
+ GroupCreateTime: joinedAtTimestamp,
+ GroupID: groupID,
+ GroupLevel: 0,
+ GroupMemo: guild.Desc,
+ GroupName: "*" + guild.Name,
+ MaxMemberCount: int32(guild.MaxMembers),
+ MemberCount: int32(guild.MemberCount),
+ }
+ *groupListData = append(*groupListData, group)
+
+ channels, err := api.Channels(context.TODO(), guild.ID)
+ if err != nil {
+ mylog.Println("Error fetching channels list:", err)
+ return
+ }
+
+ guidsType := config.GetGroupListGuidsType()
+ textChannelCount := 0 // 用于记录dto.ChannelTypeText类型的频道数量
+
+ for _, channel := range channels {
+ ChannelID64, err := idmap.StoreIDv2(channel.ID)
+ if err != nil {
+ mylog.Printf("Error storing ID: %v", err)
+ }
+
+ // 当guidsType不为0时,对频道类型进行特殊处理
+ if guidsType != 0 {
+ if channel.Type == dto.ChannelTypeText {
+ textChannelCount++
+ // 当guidsType为1但textChannelCount大于1时,或当guidsType为2但textChannelCount大于2时,跳过当前频道
+ if (guidsType == 1 && textChannelCount > 1) || (guidsType == 2 && textChannelCount > 2) {
+ continue
+ }
+ } else {
+ // 如果频道类型不是dto.ChannelTypeText,则根据guidsType丢弃
+ continue
+ }
+ }
+
+ groupName := channel.Name
+ if channel.Type == dto.ChannelTypeText {
+ groupName = "&" + groupName
+ }
+
+ channelGroup := Group{
+ GroupCreateTime: 0,
+ GroupID: ChannelID64,
+ GroupLevel: 0,
+ GroupMemo: "",
+ GroupName: groupName,
+ MaxMemberCount: 0,
+ MemberCount: 0,
+ }
+
+ *groupListData = append(*groupListData, channelGroup)
+ }
+}
diff --git a/template/config_template.go b/template/config_template.go
index a0a255e2..52c6711b 100644
--- a/template/config_template.go
+++ b/template/config_template.go
@@ -138,6 +138,12 @@ settings:
fix_11300: false #修复11300报错,需要在develop_bot_id填入自己机器人的appid. 11300原因暂时未知,临时修复方案.
lotus_without_idmaps: false #lotus只通过url,图片上传,语音,不通过id转换,在本地当前gsk维护idmaps转换.
+ get_g_list_all_guilds : false #在获取群列表api时,轮询获取全部的频道列表(api一次只能获取100个),建议仅在广播公告通知等特别场景时开启.
+ get_g_list_delay : 500 #轮询时的延迟时间,毫秒数.
+ get_g_list_guilds_type : 0 #0=全部返回,1=获取第1个子频道.以此类推.可以缩减返回值的大小.
+ get_g_list_guilds : "10" #在获取群列表api时,一次返回的频道数量.这里是string,不要去掉引号.最大100(5分钟内连续请求=翻页),获取全部请开启get_g_list_return_guilds.
+ get_g_list_return_guilds : true #获取群列表时是否返回频道列表.
+
title : "Gensokyo © 2023 - Hoshinonyaruko" #程序的标题 如果多个机器人 可根据标题区分
custom_bot_name : "Gensokyo全域机器人" #自定义机器人名字,会在api调用中返回,默认Gensokyo全域机器人
From 6df84f8fa2b2c93af4fd0f18482365fb56765622 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Fri, 22 Mar 2024 21:53:23 +0800
Subject: [PATCH 10/33] beta345
---
go.mod | 3 +--
go.sum | 4 ---
main.go | 1 +
server/uploadpic.go | 65 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 67 insertions(+), 6 deletions(-)
diff --git a/go.mod b/go.mod
index ab7d1abe..e64ad884 100644
--- a/go.mod
+++ b/go.mod
@@ -22,7 +22,6 @@ require (
require (
github.com/clbanning/mxj v1.8.4 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
- github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-querystring v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
@@ -70,6 +69,6 @@ require (
golang.org/x/net v0.10.0
golang.org/x/sys v0.13.0
golang.org/x/text v0.9.0 // indirect
- google.golang.org/protobuf v1.32.0 // indirect
+ google.golang.org/protobuf v1.32.0
mvdan.cc/xurls v1.1.0
)
diff --git a/go.sum b/go.sum
index c368c245..bf141ce6 100644
--- a/go.sum
+++ b/go.sum
@@ -70,8 +70,6 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -276,8 +274,6 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/main.go b/main.go
index 66037a94..cf690003 100644
--- a/main.go
+++ b/main.go
@@ -320,6 +320,7 @@ func main() {
r.GET("/updateport", server.HandleIpupdate)
r.POST("/uploadpic", server.UploadBase64ImageHandler(rateLimiter))
r.POST("/uploadpicv2", server.UploadBase64ImageHandlerV2(rateLimiter, apiV2))
+ r.POST("/uploadpicv3", server.UploadBase64ImageHandlerV3(rateLimiter, api))
r.POST("/uploadrecord", server.UploadBase64RecordHandler(rateLimiter))
r.Static("/channel_temp", "./channel_temp")
if config.GetFrpPort() == "0" && !config.GetDisableWebui() {
diff --git a/server/uploadpic.go b/server/uploadpic.go
index b1fc1c77..ca642439 100644
--- a/server/uploadpic.go
+++ b/server/uploadpic.go
@@ -2,6 +2,7 @@ package server
import (
"bytes"
+ "context"
"crypto/md5"
"encoding/base64"
"encoding/hex"
@@ -13,6 +14,7 @@ import (
_ "image/png"
"net/http"
"os"
+ "strings"
"time"
"github.com/gin-gonic/gin"
@@ -20,6 +22,7 @@ import (
"github.com/hoshinonyaruko/gensokyo/idmap"
"github.com/hoshinonyaruko/gensokyo/images"
"github.com/hoshinonyaruko/gensokyo/mylog"
+ "github.com/tencent-connect/botgo/dto"
"github.com/tencent-connect/botgo/openapi"
)
@@ -160,6 +163,68 @@ func UploadBase64ImageHandlerV2(rateLimiter *RateLimiter, apiv2 openapi.OpenAPI)
}
}
+func UploadBase64ImageHandlerV3(rateLimiter *RateLimiter, apiv1 openapi.OpenAPI) gin.HandlerFunc {
+ return func(c *gin.Context) {
+ ipAddress := c.ClientIP()
+ if !rateLimiter.CheckAndUpdateRateLimit(ipAddress) {
+ c.JSON(http.StatusTooManyRequests, gin.H{"error": "rate limit exceeded"})
+ return
+ }
+
+ base64Image := c.PostForm("base64Image")
+ channelID := c.PostForm("channelID")
+
+ if channelID == "" {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "channelID is required"})
+ return
+ }
+
+ fileImageData, err := base64.StdEncoding.DecodeString(base64Image)
+ if err != nil {
+ mylog.Printf("Base64 解码失败: %v", err)
+ return
+ }
+ // 压缩 只有设置了阈值才会压缩
+ compressedData, err := images.CompressSingleImage(fileImageData)
+ if err != nil {
+ mylog.Printf("Error compressing image: %v", err)
+ return
+ }
+
+ newMessage := &dto.MessageToCreate{
+ Content: "",
+ MsgID: "1000",
+ MsgType: 0,
+ Timestamp: time.Now().Unix(),
+ }
+
+ if _, err = apiv1.PostMessageMultipart(context.TODO(), channelID, newMessage, compressedData); err != nil {
+ mylog.Printf("使用multipart发送图文信息失败: %v message_id %v", err, 1000)
+ return
+ }
+
+ // 计算压缩数据的MD5值
+ // 计算压缩数据的MD5值
+ md5Hash := md5.Sum(compressedData)
+ md5String := strings.ToUpper(hex.EncodeToString(md5Hash[:]))
+ imageURL := fmt.Sprintf("https://gchat.qpic.cn/qmeetpic/0/0-0-%s/0", md5String)
+
+ // 获取图片宽高
+ height, width, err := images.GetImageDimensions(imageURL)
+ if err != nil {
+ mylog.Printf("获取图片宽高出错: %v", err)
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{
+ "url": imageURL,
+ "channelID": channelID,
+ "width": width,
+ "height": height,
+ })
+ }
+}
+
// 闭包,网页后端,语音床逻辑,基于gin和www静态文件的简易语音床
func UploadBase64RecordHandler(rateLimiter *RateLimiter) gin.HandlerFunc {
return func(c *gin.Context) {
From 2aac729308e239bdaad0567b3bd37a0ee684624e Mon Sep 17 00:00:00 2001
From: cosmo
Date: Fri, 22 Mar 2024 22:45:41 +0800
Subject: [PATCH 11/33] beta346
---
images/format.go | 13 ++++++++++++-
server/uploadpic.go | 1 -
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/images/format.go b/images/format.go
index a5cb61c2..4790afd0 100644
--- a/images/format.go
+++ b/images/format.go
@@ -12,6 +12,7 @@ import (
// 宽度 高度
func GetImageDimensions(url string) (int, int, error) {
+ // 原有的后缀判断逻辑
if strings.HasSuffix(url, ".png") {
return getPNGDimensions(url)
} else if strings.HasSuffix(url, ".jpg") || strings.HasSuffix(url, ".jpeg") {
@@ -19,7 +20,17 @@ func GetImageDimensions(url string) (int, int, error) {
} else if strings.HasSuffix(url, ".gif") {
return getGIFDimensions(url)
}
- return 0, 0, fmt.Errorf("unsupported image format")
+
+ // 如果图片格式不受支持,则尝试其他方法
+ methods := []func(string) (int, int, error){getPNGDimensions, getJpegDimensions, getGIFDimensions}
+ for _, method := range methods {
+ width, height, err := method(url)
+ if err == nil && (width != 0 || height != 0) {
+ return width, height, nil
+ }
+ }
+
+ return 0, 0, fmt.Errorf("unsupported image format or failed to get dimensions")
}
func getPNGDimensions(url string) (int, int, error) {
diff --git a/server/uploadpic.go b/server/uploadpic.go
index ca642439..c60cc337 100644
--- a/server/uploadpic.go
+++ b/server/uploadpic.go
@@ -203,7 +203,6 @@ func UploadBase64ImageHandlerV3(rateLimiter *RateLimiter, apiv1 openapi.OpenAPI)
return
}
- // 计算压缩数据的MD5值
// 计算压缩数据的MD5值
md5Hash := md5.Sum(compressedData)
md5String := strings.ToUpper(hex.EncodeToString(md5Hash[:]))
From 75469893361a4b8f295071fbbabc8664f79c58c8 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Sat, 23 Mar 2024 11:10:53 +0800
Subject: [PATCH 12/33] beta347
---
config/config.go | 37 +++++++++++++
handlers/send_group_msg.go | 9 ++-
handlers/send_msg.go | 6 ++
handlers/send_private_msg.go | 7 +++
images/upload_api.go | 103 +++++++++++++++++++++++++++++++++++
template/config_template.go | 6 +-
6 files changed, 165 insertions(+), 3 deletions(-)
diff --git a/config/config.go b/config/config.go
index 2f68ec44..d97e6d4d 100644
--- a/config/config.go
+++ b/config/config.go
@@ -158,6 +158,9 @@ type Settings struct {
GetGroupListReturnGuilds bool `yaml:"get_g_list_return_guilds"`
GetGroupListGuidsType int `yaml:"get_g_list_guilds_type"`
GetGroupListDelay int `yaml:"get_g_list_delay"`
+ GlobalServerTempQQguild bool `yaml:"global_server_temp_qqguild"`
+ ServerTempQQguild string `yaml:"server_temp_qqguild"`
+ ServerTempQQguildPool []string `yaml:"server_temp_qqguild_pool"`
}
// LoadConfig 从文件中加载配置并初始化单例配置
@@ -1961,3 +1964,37 @@ func GetGroupListDelay() int {
}
return instance.Settings.GetGroupListDelay
}
+
+// 获取GetGlobalServerTempQQguild开关
+func GetGlobalServerTempQQguild() bool {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to GlobalServerTempQQguild value.")
+ return false
+ }
+ return instance.Settings.GlobalServerTempQQguild
+}
+
+// 获取ServerTempQQguild
+func GetServerTempQQguild() string {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to ServerTempQQguild value.")
+ return "0"
+ }
+ return instance.Settings.ServerTempQQguild
+}
+
+// 获取ServerTempQQguildPool
+func GetServerTempQQguildPool() []string {
+ mu.Lock()
+ defer mu.Unlock()
+ if instance != nil {
+ return instance.Settings.ServerTempQQguildPool
+ }
+ return nil // 返回nil,如果instance为nil
+}
diff --git a/handlers/send_group_msg.go b/handlers/send_group_msg.go
index 3e4f0c6f..1caf0507 100644
--- a/handlers/send_group_msg.go
+++ b/handlers/send_group_msg.go
@@ -76,7 +76,12 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUseridV2(message.Params.UserID)
}
-
+ // New checks for UserID and GroupID being nil or 0
+ if (message.Params.UserID == nil || !checkZeroUserID(message.Params.UserID)) &&
+ (message.Params.GroupID == nil || !checkZeroGroupID(message.Params.GroupID)) {
+ mylog.Printf("send_group_msgs接收到错误action: %v", message)
+ return "", nil
+ }
mylog.Printf("send_group_msg获取到信息类型:%v", msgType)
var idInt64 int64
var err error
@@ -1116,7 +1121,7 @@ func SendStackMessages(apiv2 openapi.OpenAPI, messageid string, GroupID string)
mylog.Printf("取出数量: %v", count)
pairs := echo.PopGlobalStackMulti(count)
for i, pair := range pairs {
- mylog.Printf("发送栈中的消息匹配 %v: %v", pair.Group, GroupID)
+ //mylog.Printf("发送栈中的消息匹配 %v: %v", pair.Group, GroupID)
if pair.Group == GroupID {
// 发送消息
msgseq := echo.GetMappingSeq(messageid)
diff --git a/handlers/send_msg.go b/handlers/send_msg.go
index f9aca80a..42578736 100644
--- a/handlers/send_msg.go
+++ b/handlers/send_msg.go
@@ -65,6 +65,12 @@ func HandleSendMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.Ope
if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUseridV2(message.Params.UserID)
}
+ // New checks for UserID and GroupID being nil or 0
+ if (message.Params.UserID == nil || !checkZeroUserID(message.Params.UserID)) &&
+ (message.Params.GroupID == nil || !checkZeroGroupID(message.Params.GroupID)) {
+ mylog.Printf("send_group_msgs接收到错误action: %v", message)
+ return "", nil
+ }
var idInt64, idInt642 int64
var err error
diff --git a/handlers/send_private_msg.go b/handlers/send_private_msg.go
index e71c493b..f8daf4c5 100644
--- a/handlers/send_private_msg.go
+++ b/handlers/send_private_msg.go
@@ -67,6 +67,13 @@ func HandleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open
if msgType == "" && message.Params.GroupID != nil && checkZeroGroupID(message.Params.GroupID) {
msgType = GetMessageTypeByGroupidV2(message.Params.GroupID)
}
+ // New checks for UserID and GroupID being nil or 0
+ if (message.Params.UserID == nil || !checkZeroUserID(message.Params.UserID)) &&
+ (message.Params.GroupID == nil || !checkZeroGroupID(message.Params.GroupID)) {
+ mylog.Printf("send_group_msgs接收到错误action: %v", message)
+ return "", nil
+ }
+
var idInt64 int64
var err error
diff --git a/images/upload_api.go b/images/upload_api.go
index 0ee3d461..f70bff01 100644
--- a/images/upload_api.go
+++ b/images/upload_api.go
@@ -13,6 +13,7 @@ import (
"net/url"
"regexp"
"strings"
+ "sync"
"github.com/hoshinonyaruko/gensokyo/config"
"github.com/hoshinonyaruko/gensokyo/echo"
@@ -24,6 +25,12 @@ import (
"google.golang.org/protobuf/proto"
)
+// 包级私有变量,用于存储当前URL索引
+var (
+ currentURLIndex int
+ urlsMutex sync.Mutex
+)
+
// uploadMedia 上传媒体并返回FileInfo
func uploadMedia(ctx context.Context, groupID string, richMediaMessage *dto.RichMediaMessage, apiv2 openapi.OpenAPI) (string, error) {
// 调用API来上传媒体
@@ -55,6 +62,17 @@ func isNumeric(s string) bool {
func UploadBase64ImageToServer(msgid string, base64Image string, groupID string, apiv2 openapi.OpenAPI) (string, uint64, uint32, uint32, error) {
var picURL string
var err error
+ // 检查是否应该使用全局服务器临时QQ群的特殊上传行为
+ if config.GetGlobalServerTempQQguild() {
+ // 直接调用UploadBehaviorV3
+ downloadURL, width, height, err := UploadBehaviorV3(base64Image)
+ if err != nil {
+ log.Printf("Error UploadBehaviorV3: %v", err)
+ return "", 0, 0, 0, nil
+ }
+ return downloadURL, 0, width, height, nil
+ }
+
extraPicAuditingType := config.GetOssType()
switch extraPicAuditingType {
@@ -200,6 +218,51 @@ func originalUploadBehavior(base64Image string) (string, error) {
return "", errors.New("local server uses a private address; image upload failed")
}
+func UploadBehaviorV3(base64Image string) (string, uint32, uint32, error) {
+ urls := config.GetServerTempQQguildPool()
+ if len(urls) > 0 {
+ urlsMutex.Lock()
+ url := urls[currentURLIndex]
+ currentURLIndex = (currentURLIndex + 1) % len(urls)
+ urlsMutex.Unlock()
+
+ resp, width, height, err := postImageToServerV3(base64Image, url)
+ if err != nil {
+ return "", 0, 0, err
+ }
+ return resp, width, height, nil
+ } else {
+ protocol := "http"
+ serverPort := config.GetPortValue()
+ if serverPort == "443" {
+ protocol = "https"
+ }
+
+ serverDir := config.GetServer_dir()
+ url := fmt.Sprintf("%s://%s:%s/uploadpicv3", protocol, serverDir, serverPort)
+
+ if config.GetLotusValue() {
+ resp, width, height, err := postImageToServerV3(base64Image, url)
+ if err != nil {
+ return "", 0, 0, err
+ }
+ return resp, width, height, nil
+ } else {
+ if serverPort == "443" {
+ protocol = "http"
+ serverPort = "444"
+ }
+ url = fmt.Sprintf("%s://127.0.0.1:%s/uploadpicv3", protocol, serverPort)
+
+ resp, width, height, err := postImageToServerV3(base64Image, url)
+ if err != nil {
+ return "", 0, 0, err
+ }
+ return resp, width, height, nil
+ }
+ }
+}
+
// 将base64语音通过lotus转换成url
func originalUploadBehaviorRecord(base64Image string) (string, error) {
// 根据serverPort确定协议
@@ -271,6 +334,46 @@ func postImageToServer(base64Image, targetURL string) (string, error) {
return "", fmt.Errorf("URL not found in response")
}
+// 请求图床api(图床就是lolus为false的gensokyo)
+func postImageToServerV3(base64Image, targetURL string) (string, uint32, uint32, error) {
+ data := url.Values{}
+ channelID := config.GetServerTempQQguild()
+ data.Set("base64Image", base64Image) // 修改字段名以与服务器匹配
+ data.Set("channelID", channelID) // 修改字段名以与服务器匹配
+
+ resp, err := http.PostForm(targetURL, data)
+ if err != nil {
+ return "", 0, 0, fmt.Errorf("failed to send request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ return "", 0, 0, fmt.Errorf("error response from server: %s", resp.Status)
+ }
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return "", 0, 0, fmt.Errorf("failed to read response body: %v", err)
+ }
+
+ var responseMap map[string]interface{}
+ if err := json.Unmarshal(body, &responseMap); err != nil {
+ return "", 0, 0, fmt.Errorf("failed to unmarshal response: %v", err)
+ }
+
+ url, okURL := responseMap["url"].(string)
+ width, okWidth := responseMap["width"].(float64) // JSON numbers are decoded as float64
+ height, okHeight := responseMap["height"].(float64)
+ if !okURL {
+ return "", 0, 0, fmt.Errorf("uRL not found in response")
+ }
+ if !okWidth || !okHeight {
+ return "", 0, 0, fmt.Errorf("width or Height not found in response")
+ }
+
+ return url, uint32(width), uint32(height), nil
+}
+
// 请求语音床api(图床就是lolus为false的gensokyo)
func postRecordToServer(base64Image, targetURL string) (string, error) {
data := url.Values{}
diff --git a/template/config_template.go b/template/config_template.go
index 52c6711b..92fa87d6 100644
--- a/template/config_template.go
+++ b/template/config_template.go
@@ -52,7 +52,7 @@ settings:
record_bitRate : 24000 #语音文件的比特率 默认25000 代表 25 kbps 最高无限 请根据带宽 您发送的实际码率调整
card_nick : "" #默认为空,连接mirai-overflow时,请设置为非空,这里是机器人对用户称谓,为空为插件获取,mirai不支持
auto_bind : true #测试功能,后期会移除
- AMsgRetryAsPMsg_Count : 1 #当主动信息发送失败时,自动转为后续的被动信息发送,需要开启Lazy message id,该配置项为每次跟随被动信息发送的信息数量,最大5,建议1-3
+ AMsgRetryAsPMsg_Count : 30 #当主动信息发送失败时,自动转为后续的被动信息发送,需要开启Lazy message id,该配置项为所有群、频道的主动转被动消息队列最大长度,建议30-100,无上限
reconnect_times : 100 #反向ws连接失败后的重试次数,希望一直重试,可设置9999
heart_beat_interval : 10 #反向ws心跳间隔 单位秒 推荐5-10
launch_reconnect_times : 1 #启动时尝试反向ws连接次数,建议先打开应用端再开启gensokyo,因为启动时连接会阻塞webui启动,默认只连接一次,可自行增大
@@ -144,6 +144,10 @@ settings:
get_g_list_guilds : "10" #在获取群列表api时,一次返回的频道数量.这里是string,不要去掉引号.最大100(5分钟内连续请求=翻页),获取全部请开启get_g_list_return_guilds.
get_g_list_return_guilds : true #获取群列表时是否返回频道列表.
+ global_server_temp_qqguild : false #需设置server_temp_qqguild,公域私域均可用,以频道为底层发图,速度快,该接口为进阶接口,使用有一定难度.
+ server_temp_qqguild : "0" #在v3图片接口采用固定的子频道号,可以是帖子子频道 https://www.yuque.com/km57bt/hlhnxg/uqmnsno3vx1ytp2q
+ server_temp_qqguild_pool : [] #填写v3发图接口的endpoint http://127.0.0.1:12345/uploadpicv3 当填写多个时采用循环方式负载均衡,注,不包括自身,如需要自身也要填写
+
title : "Gensokyo © 2023 - Hoshinonyaruko" #程序的标题 如果多个机器人 可根据标题区分
custom_bot_name : "Gensokyo全域机器人" #自定义机器人名字,会在api调用中返回,默认Gensokyo全域机器人
From 3ea73d59c7a58d47df9cd30c2da1e1c8691e692c Mon Sep 17 00:00:00 2001
From: cosmo
Date: Sun, 24 Mar 2024 01:00:33 +0800
Subject: [PATCH 13/33] beta348
---
botgo/openapi/iface.go | 2 +
botgo/openapi/v1/message.go | 30 ++
botgo/openapi/v1/resource.go | 4 +-
botgo/openapi/v2/message.go | 30 ++
botgo/openapi/v2/resource.go | 4 +-
callapi/callapi.go | 63 +++-
handlers/delete_msg.go | 110 ++++++
handlers/get_group_member_list.go | 16 +-
handlers/get_guild_channel_list.go | 2 +-
handlers/message_parser.go | 196 ++++++++++-
handlers/send_group_forward_msg.go | 2 +-
handlers/send_group_msg.go | 32 +-
handlers/send_group_msg_raw.go | 493 +++++++++++++++++++++++++++
handlers/send_guild_channel_forum.go | 10 +-
handlers/send_guild_channel_msg.go | 36 +-
handlers/send_guild_private_msg.go | 12 +-
handlers/send_msg.go | 8 +-
handlers/send_private_msg.go | 14 +-
httpapi/httpapi.go | 60 +++-
19 files changed, 1043 insertions(+), 81 deletions(-)
create mode 100644 handlers/delete_msg.go
create mode 100644 handlers/send_group_msg_raw.go
diff --git a/botgo/openapi/iface.go b/botgo/openapi/iface.go
index d9670d8e..58bd24ec 100644
--- a/botgo/openapi/iface.go
+++ b/botgo/openapi/iface.go
@@ -74,6 +74,8 @@ type MessageAPI interface {
PatchMessage(ctx context.Context,
channelID string, messageID string, msg *dto.MessageToCreate) (*dto.Message, error)
RetractMessage(ctx context.Context, channelID, msgID string, options ...RetractMessageOption) error
+ RetractGroupMessage(ctx context.Context, groupID, msgID string, options ...RetractMessageOption) error
+ RetractC2CMessage(ctx context.Context, userID, msgID string, options ...RetractMessageOption) error
// PostSettingGuide 发送设置引导
PostSettingGuide(ctx context.Context, channelID string, atUserIDs []string) (*dto.Message, error)
diff --git a/botgo/openapi/v1/message.go b/botgo/openapi/v1/message.go
index 43e11c4c..4285a823 100644
--- a/botgo/openapi/v1/message.go
+++ b/botgo/openapi/v1/message.go
@@ -175,6 +175,36 @@ func (o *openAPI) RetractMessage(ctx context.Context,
return err
}
+// RetractMessage 撤回群消息
+func (o *openAPI) RetractGroupMessage(ctx context.Context,
+ groupID, msgID string, options ...openapi.RetractMessageOption) error {
+ request := o.request(ctx).
+ SetPathParam("group_id", groupID).
+ SetPathParam("message_id", string(msgID))
+ for _, option := range options {
+ if option == openapi.RetractMessageOptionHidetip {
+ request = request.SetQueryParam("hidetip", "true")
+ }
+ }
+ _, err := request.Delete(o.getURL(groupMessagesURL))
+ return err
+}
+
+// RetractMessage 撤回私聊消息
+func (o *openAPI) RetractC2CMessage(ctx context.Context,
+ UserID, msgID string, options ...openapi.RetractMessageOption) error {
+ request := o.request(ctx).
+ SetPathParam("user_id", UserID).
+ SetPathParam("message_id", string(msgID))
+ for _, option := range options {
+ if option == openapi.RetractMessageOptionHidetip {
+ request = request.SetQueryParam("hidetip", "true")
+ }
+ }
+ _, err := request.Delete(o.getURL(c2cMessageURI))
+ return err
+}
+
// PostSettingGuide 发送设置引导消息, atUserID为要at的用户
func (o *openAPI) PostSettingGuide(ctx context.Context,
channelID string, atUserIDs []string) (*dto.Message, error) {
diff --git a/botgo/openapi/v1/resource.go b/botgo/openapi/v1/resource.go
index 85496f83..6f554df0 100644
--- a/botgo/openapi/v1/resource.go
+++ b/botgo/openapi/v1/resource.go
@@ -34,7 +34,8 @@ const (
c2cMessagesURI uri = "/v2/users/{user_id}/messages"
c2cRichMediaURI uri = "/v2/users/{user_id}/files"
- messageURI uri = "/channels/{channel_id}/messages/{message_id}"
+ messageURI uri = "/channels/{channel_id}/messages/{message_id}"
+ groupMessagesURL uri = "/v2/groups/{group_id}/messages/{message_id}"
userMeURI uri = "/users/@me"
userMeGuildsURI uri = "/users/@me/guilds"
@@ -53,6 +54,7 @@ const (
dmsURI uri = "/dms/{guild_id}/messages"
dmsMessageURI uri = "/dms/{guild_id}/messages/{message_id}"
+ c2cMessageURI uri = "/v2/users/{user_id}/messages/{message_id}"
channelAnnouncesURI = "/channels/{channel_id}/announces"
channelAnnounceURI = "/channels/{channel_id}/announces/{message_id}"
diff --git a/botgo/openapi/v2/message.go b/botgo/openapi/v2/message.go
index 4627d3d0..d3e23707 100644
--- a/botgo/openapi/v2/message.go
+++ b/botgo/openapi/v2/message.go
@@ -175,6 +175,36 @@ func (o *openAPIv2) RetractMessage(ctx context.Context,
return err
}
+// RetractMessage 撤回群消息
+func (o *openAPIv2) RetractGroupMessage(ctx context.Context,
+ groupID, msgID string, options ...openapi.RetractMessageOption) error {
+ request := o.request(ctx).
+ SetPathParam("group_id", groupID).
+ SetPathParam("message_id", string(msgID))
+ for _, option := range options {
+ if option == openapi.RetractMessageOptionHidetip {
+ request = request.SetQueryParam("hidetip", "true")
+ }
+ }
+ _, err := request.Delete(o.getURL(groupMessagesURL))
+ return err
+}
+
+// RetractMessage 撤回私聊消息
+func (o *openAPIv2) RetractC2CMessage(ctx context.Context,
+ UserID, msgID string, options ...openapi.RetractMessageOption) error {
+ request := o.request(ctx).
+ SetPathParam("user_id", UserID).
+ SetPathParam("message_id", string(msgID))
+ for _, option := range options {
+ if option == openapi.RetractMessageOptionHidetip {
+ request = request.SetQueryParam("hidetip", "true")
+ }
+ }
+ _, err := request.Delete(o.getURL(c2cMessageURI))
+ return err
+}
+
// PostSettingGuide 发送设置引导消息, atUserID为要at的用户
func (o *openAPIv2) PostSettingGuide(ctx context.Context,
channelID string, atUserIDs []string) (*dto.Message, error) {
diff --git a/botgo/openapi/v2/resource.go b/botgo/openapi/v2/resource.go
index b8835c1a..2649d46b 100644
--- a/botgo/openapi/v2/resource.go
+++ b/botgo/openapi/v2/resource.go
@@ -34,7 +34,8 @@ const (
c2cMessagesURI uri = "/v2/users/{user_id}/messages"
c2cRichMediaURI uri = "/v2/users/{user_id}/files"
- messageURI uri = "/channels/{channel_id}/messages/{message_id}"
+ messageURI uri = "/channels/{channel_id}/messages/{message_id}"
+ groupMessagesURL uri = "/v2/groups/{group_id}/messages/{message_id}"
userMeURI uri = "/users/@me"
userMeGuildsURI uri = "/users/@me/guilds"
@@ -53,6 +54,7 @@ const (
dmsURI uri = "/dms/{guild_id}/messages"
dmsMessageURI uri = "/dms/{guild_id}/messages/{message_id}"
+ c2cMessageURI uri = "/v2/users/{user_id}/messages/{message_id}"
channelAnnouncesURI = "/channels/{channel_id}/announces"
channelAnnounceURI = "/channels/{channel_id}/announces/{message_id}"
diff --git a/callapi/callapi.go b/callapi/callapi.go
index e6e88536..c0e6a5ff 100644
--- a/callapi/callapi.go
+++ b/callapi/callapi.go
@@ -68,18 +68,19 @@ func (a *ActionMessage) UnmarshalJSON(data []byte) error {
// params类型
type ParamsContent struct {
- BotQQ string `json:"botqq"`
- ChannelID string `json:"channel_id"`
- GuildID string `json:"guild_id"`
- GroupID interface{} `json:"group_id"` // 每一种onebotv11实现的字段类型都可能不同
- Message interface{} `json:"message"` // 这里使用interface{}因为它可能是多种类型
- Messages interface{} `json:"messages,omitempty"` // 坑爹转发信息
- UserID interface{} `json:"user_id"` // 这里使用interface{}因为它可能是多种类型
- Duration int `json:"duration,omitempty"` // 可选的整数
- Enable bool `json:"enable,omitempty"` // 可选的布尔值
+ BotQQ string `json:"botqq,omitempty"`
+ ChannelID interface{} `json:"channel_id,omitempty"`
+ GuildID interface{} `json:"guild_id,omitempty"`
+ GroupID interface{} `json:"group_id,omitempty"` // 每一种onebotv11实现的字段类型都可能不同
+ MessageID interface{} `json:"message_id,omitempty"` // 用于撤回信息
+ Message interface{} `json:"message,omitempty"` // 这里使用interface{}因为它可能是多种类型
+ Messages interface{} `json:"messages,omitempty"` // 坑爹转发信息
+ UserID interface{} `json:"user_id,omitempty"` // 这里使用interface{}因为它可能是多种类型
+ Duration int `json:"duration,omitempty"` // 可选的整数
+ Enable bool `json:"enable,omitempty"` // 可选的布尔值
// handle quick operation
- Context Context `json:"context"` // context 字段
- Operation Operation `json:"operation"` // operation 字段
+ Context Context `json:"context,omitempty"` // context 字段
+ Operation Operation `json:"operation,omitempty"` // operation 字段
}
// Context 结构体用于存储 context 字段相关信息
@@ -106,8 +107,11 @@ type Operation struct {
func (p *ParamsContent) UnmarshalJSON(data []byte) error {
type Alias ParamsContent
aux := &struct {
- GroupID interface{} `json:"group_id"`
- UserID interface{} `json:"user_id"`
+ GroupID interface{} `json:"group_id"`
+ UserID interface{} `json:"user_id"`
+ MessageID interface{} `json:"message_id"`
+ ChannelID interface{} `json:"channel_id"`
+ GuildID interface{} `json:"guild_id"`
*Alias
}{
Alias: (*Alias)(p),
@@ -138,6 +142,39 @@ func (p *ParamsContent) UnmarshalJSON(data []byte) error {
return fmt.Errorf("UserID has unsupported type")
}
+ switch v := aux.MessageID.(type) {
+ case nil: // 当UserID不存在时
+ p.MessageID = ""
+ case float64: // JSON的数字默认被解码为float64
+ p.MessageID = fmt.Sprintf("%.0f", v) // 将其转换为字符串,忽略小数点后的部分
+ case string:
+ p.MessageID = v
+ default:
+ return fmt.Errorf("MessageID has unsupported type")
+ }
+
+ switch v := aux.ChannelID.(type) {
+ case nil: // 当ChannelID不存在时
+ p.ChannelID = ""
+ case float64: // JSON的数字默认被解码为float64
+ p.ChannelID = fmt.Sprintf("%.0f", v) // 将其转换为字符串,忽略小数点后的部分
+ case string:
+ p.ChannelID = v
+ default:
+ return fmt.Errorf("MessageID has unsupported type")
+ }
+
+ switch v := aux.GuildID.(type) {
+ case nil: // 当GuildID不存在时
+ p.GuildID = ""
+ case float64: // JSON的数字默认被解码为float64
+ p.GuildID = fmt.Sprintf("%.0f", v) // 将其转换为字符串,忽略小数点后的部分
+ case string:
+ p.GuildID = v
+ default:
+ return fmt.Errorf("MessageID has unsupported type")
+ }
+
return nil
}
diff --git a/handlers/delete_msg.go b/handlers/delete_msg.go
new file mode 100644
index 00000000..f7a87295
--- /dev/null
+++ b/handlers/delete_msg.go
@@ -0,0 +1,110 @@
+package handlers
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+
+ "github.com/hoshinonyaruko/gensokyo/callapi"
+ "github.com/hoshinonyaruko/gensokyo/idmap"
+ "github.com/hoshinonyaruko/gensokyo/mylog"
+ "github.com/tencent-connect/botgo/openapi"
+)
+
+func init() {
+ callapi.RegisterHandler("delete_msg", DeleteMsg)
+}
+
+func DeleteMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) (string, error) {
+
+ //还原msgid
+ RealMsgID, err := idmap.RetrieveRowByIDv2(message.Params.MessageID.(string))
+ if err != nil {
+ mylog.Printf("error retrieving real RChannelID: %v", err)
+ }
+ //重新赋值
+ message.Params.MessageID = RealMsgID
+ //撤回频道信息
+ if message.Params.ChannelID != nil && message.Params.ChannelID != "" {
+ var RChannelID string
+ var err error
+ // 使用RetrieveRowByIDv2还原真实的ChannelID
+ RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID.(string))
+ if err != nil {
+ mylog.Printf("error retrieving real RChannelID: %v", err)
+ }
+ message.Params.ChannelID = RChannelID
+ err = api.RetractMessage(context.TODO(), message.Params.ChannelID.(string), message.Params.MessageID.(string), openapi.RetractMessageOptionHidetip)
+ if err != nil {
+ fmt.Println("Error retracting channel message:", err)
+ }
+
+ }
+
+ //撤回频道私信
+ if message.Params.GuildID != nil && message.Params.GuildID != "" {
+ //这里很复杂 要取的话需要调用internal-api 根据情况还原,虚拟成群就用群(channel-id)还原完整channel-id,
+ //然后internal-api读配置获取guild-id ,虚拟成私信就用userid还原完整userid,然后读channel-id然后读guild-id
+ //因为GuildID本身不直接出现在ob11事件里。
+ err := api.RetractDMMessage(context.TODO(), message.Params.GuildID.(string), message.Params.MessageID.(string), openapi.RetractMessageOptionHidetip)
+ if err != nil {
+ fmt.Println("Error retracting DM message:", err)
+ }
+
+ }
+
+ //撤回群信息
+ if message.Params.GroupID != nil && message.Params.GroupID != "" {
+ var originalGroupID string
+ originalGroupID, err := idmap.RetrieveRowByIDv2(message.Params.GroupID.(string))
+ if err != nil {
+ mylog.Printf("Error retrieving original GroupID: %v", err)
+ }
+ message.Params.GroupID = originalGroupID
+ err = api.RetractGroupMessage(context.TODO(), message.Params.GroupID.(string), message.Params.MessageID.(string), openapi.RetractMessageOptionHidetip)
+ if err != nil {
+ fmt.Println("Error retracting group message:", err)
+ }
+
+ }
+
+ //撤回C2C私信消息列表
+ if message.Params.UserID != nil && message.Params.UserID != "" {
+ var UserID string
+ //还原真实的userid
+ UserID, err := idmap.RetrieveRowByIDv2(message.Params.UserID.(string))
+ if err != nil {
+ mylog.Printf("Error reading config: %v", err)
+ return "", nil
+ }
+ message.Params.UserID = UserID
+ err = api.RetractC2CMessage(context.TODO(), message.Params.UserID.(string), message.Params.MessageID.(string), openapi.RetractMessageOptionHidetip)
+ if err != nil {
+ fmt.Println("Error retracting C2C message:", err)
+ }
+
+ }
+
+ var response GetStatusResponse
+ response.Message = ""
+ response.RetCode = 0
+ response.Status = "ok"
+ response.Echo = message.Echo
+
+ outputMap := structToMap(response)
+
+ mylog.Printf("delete_msg: %+v\n", outputMap)
+
+ err = client.SendMessage(outputMap)
+ if err != nil {
+ mylog.Printf("Error sending message via client: %v", err)
+ }
+ //把结果从struct转换为json
+ result, err := json.Marshal(response)
+ if err != nil {
+ mylog.Printf("Error marshaling data: %v", err)
+ //todo 符合onebotv11 ws返回的错误码
+ return "", nil
+ }
+ return string(result), nil
+}
diff --git a/handlers/get_group_member_list.go b/handlers/get_group_member_list.go
index 51e4602e..05069f31 100644
--- a/handlers/get_group_member_list.go
+++ b/handlers/get_group_member_list.go
@@ -123,7 +123,7 @@ func GetGroupMemberList(client callapi.Client, api openapi.OpenAPI, apiv2 openap
//用group_id还原出channelid 这是虚拟成群的私聊信息
message.Params.ChannelID = message.Params.GroupID.(string)
// 使用RetrieveRowByIDv2还原真实的ChannelID
- RChannelID, err := idmap.RetrieveRowByIDv2(message.Params.ChannelID)
+ RChannelID, err := idmap.RetrieveRowByIDv2(message.Params.ChannelID.(string))
if err != nil {
mylog.Printf("error retrieving real ChannelID: %v", err)
}
@@ -147,7 +147,7 @@ func GetGroupMemberList(client callapi.Client, api openapi.OpenAPI, apiv2 openap
var members []MemberList
var userIDInt, groupIDInt uint64
// 使用 message.Params.ChannelID 作为 id 来调用 FindSubKeysById
- userIDs, err := idmap.FindSubKeysByIdPro(message.Params.ChannelID)
+ userIDs, err := idmap.FindSubKeysByIdPro(message.Params.ChannelID.(string))
if err != nil {
mylog.Printf("Error retrieving user IDs: %v", err)
return "", nil // 或者处理错误
@@ -254,7 +254,7 @@ func GetGroupMemberList(client callapi.Client, api openapi.OpenAPI, apiv2 openap
//用GroupID给ChannelID赋值,因为是把频道虚拟成了群
message.Params.ChannelID = message.Params.GroupID.(string)
//将真实id转为int userid64
- _, userIDInt64, err = idmap.StoreIDv2Pro(message.Params.ChannelID, memberFromAPI.User.ID)
+ _, userIDInt64, err = idmap.StoreIDv2Pro(message.Params.ChannelID.(string), memberFromAPI.User.ID)
if err != nil {
mylog.Fatalf("Error storing ID: %v", err)
}
@@ -277,14 +277,14 @@ func GetGroupMemberList(client callapi.Client, api openapi.OpenAPI, apiv2 openap
var RChannelID string
//根据api调用中的参数,还原真实的频道号
if memberFromAPI.User.ID != "" && config.GetIdmapPro() {
- RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID, memberFromAPI.User.ID)
+ RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID.(string), memberFromAPI.User.ID)
if err != nil {
mylog.Printf("测试,通过Proid获取的RChannelID出错232:%v", err)
}
}
if RChannelID == "" {
// 使用RetrieveRowByIDv2还原真实的ChannelID
- RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID)
+ RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID.(string))
if err != nil {
mylog.Printf("测试,通过idmap.RetrieveRowByIDv2获取的RChannelID出错241:%v", err)
}
@@ -303,9 +303,9 @@ func GetGroupMemberList(client callapi.Client, api openapi.OpenAPI, apiv2 openap
GroupID: uint64(groupIDInt),
Nickname: memberFromAPI.Nick,
Card: memberFromAPI.Nick, // 使用昵称作为默认值(TODO: 将来可能发生变更)
- Sex: "0", // 使用默认值
- Age: 0, // 使用默认值
- Area: "0", // 使用默认值
+ Sex: "0", // 使用默认值
+ Age: 0, // 使用默认值
+ Area: "0", // 使用默认值
JoinTime: joinTimeInt,
LastSentTime: 0, // 使用默认值
Level: "0", // 0
diff --git a/handlers/get_guild_channel_list.go b/handlers/get_guild_channel_list.go
index 9bcc249c..c568f86e 100644
--- a/handlers/get_guild_channel_list.go
+++ b/handlers/get_guild_channel_list.go
@@ -28,7 +28,7 @@ func GetGuildChannelList(client callapi.Client, api openapi.OpenAPI, apiv2 opena
guildID := message.Params.GuildID
// 根据请求参数调用API
- channels, err := api.Channels(context.TODO(), guildID)
+ channels, err := api.Channels(context.TODO(), guildID.(string))
if err != nil {
// 如果发生错误,记录日志并返回null
mylog.Printf("Error fetching channels: %v", err)
diff --git a/handlers/message_parser.go b/handlers/message_parser.go
index 7e530e53..5b7d2e64 100644
--- a/handlers/message_parser.go
+++ b/handlers/message_parser.go
@@ -40,18 +40,202 @@ type ServerResponse struct {
Data struct {
MessageID int `json:"message_id"`
} `json:"data"`
- Message string `json:"message"`
- RetCode int `json:"retcode"`
- Status string `json:"status"`
- Echo interface{} `json:"echo"`
+ Message string `json:"message"`
+ GroupID int64 `json:"group_id,omitempty"`
+ UserID int64 `json:"user_id,omitempty"`
+ ChannelID int64 `json:"channel_id,omitempty"`
+ GuildID string `json:"guild_id,omitempty"`
+ RetCode int `json:"retcode"`
+ Status string `json:"status"`
+ Echo interface{} `json:"echo"`
+}
+
+// 发送成功回执 todo 返回可互转的messageid 实现群撤回api
+func SendResponse(client callapi.Client, err error, message *callapi.ActionMessage, resp *dto.GroupMessageResponse) (string, error) {
+ var messageID64 int64
+ var mapErr error
+ // 设置响应值
+ response := ServerResponse{}
+ if resp != nil {
+ messageID64, mapErr = idmap.StoreIDv2(resp.Message.ID)
+ if mapErr != nil {
+ mylog.Printf("Error storing ID: %v", mapErr)
+ return "", nil
+ }
+ response.Data.MessageID = int(messageID64)
+ } else {
+ // Default ID handling
+ response.Data.MessageID = 123
+ }
+ // 映射str的GroupID到int
+ GroupID64, errr := idmap.StoreIDv2(message.Params.GroupID.(string))
+ if errr != nil {
+ mylog.Errorf("failed to convert ChannelID to int: %v", err)
+ return "", nil
+ }
+ response.GroupID = GroupID64
+ response.Echo = message.Echo
+ if err != nil {
+ response.Message = err.Error() // 可选:在响应中添加错误消息
+ //response.RetCode = -1 // 可以是任何非零值,表示出错
+ //response.Status = "failed"
+ response.RetCode = 0 //官方api审核异步的 审核中默认返回失败,但其实信息发送成功了
+ response.Status = "ok"
+ } else {
+ response.Message = ""
+ response.RetCode = 0
+ response.Status = "ok"
+ }
+
+ // 转化为map并发送
+ outputMap := structToMap(response)
+ // 将map转换为JSON字符串
+ jsonResponse, jsonErr := json.Marshal(outputMap)
+ if jsonErr != nil {
+ log.Printf("Error marshaling response to JSON: %v", jsonErr)
+ return "", jsonErr
+ }
+ //发送给ws 客户端
+ sendErr := client.SendMessage(outputMap)
+ if sendErr != nil {
+ mylog.Printf("Error sending message via client: %v", sendErr)
+ return "", sendErr
+ }
+
+ mylog.Printf("发送成功回执: %+v", string(jsonResponse))
+ return string(jsonResponse), nil
}
// 发送成功回执 todo 返回可互转的messageid 实现频道撤回api
-func SendResponse(client callapi.Client, err error, message *callapi.ActionMessage) (string, error) {
+func SendGuildResponse(client callapi.Client, err error, message *callapi.ActionMessage, resp *dto.Message) (string, error) {
+ var messageID64 int64
+ var mapErr error
// 设置响应值
response := ServerResponse{}
- response.Data.MessageID = 123 // todo 实现messageid转换
+ if resp != nil {
+ messageID64, mapErr = idmap.StoreIDv2(resp.ID)
+ if mapErr != nil {
+ mylog.Printf("Error storing ID: %v", mapErr)
+ return "", nil
+ }
+ response.Data.MessageID = int(messageID64)
+ } else {
+ // Default ID handling
+ response.Data.MessageID = 123
+ }
+ //转换成int
+ ChannelID64, errr := idmap.StoreIDv2(message.Params.ChannelID.(string))
+ if errr != nil {
+ mylog.Printf("Error storing ID: %v", err)
+ return "", nil
+ }
+ response.ChannelID = ChannelID64
+ response.Echo = message.Echo
+ if err != nil {
+ response.Message = err.Error() // 可选:在响应中添加错误消息
+ //response.RetCode = -1 // 可以是任何非零值,表示出错
+ //response.Status = "failed"
+ response.RetCode = 0 //官方api审核异步的 审核中默认返回失败,但其实信息发送成功了
+ response.Status = "ok"
+ } else {
+ response.Message = ""
+ response.RetCode = 0
+ response.Status = "ok"
+ }
+
+ // 转化为map并发送
+ outputMap := structToMap(response)
+ // 将map转换为JSON字符串
+ jsonResponse, jsonErr := json.Marshal(outputMap)
+ if jsonErr != nil {
+ log.Printf("Error marshaling response to JSON: %v", jsonErr)
+ return "", jsonErr
+ }
+ //发送给ws 客户端
+ sendErr := client.SendMessage(outputMap)
+ if sendErr != nil {
+ mylog.Printf("Error sending message via client: %v", sendErr)
+ return "", sendErr
+ }
+
+ mylog.Printf("发送成功回执: %+v", string(jsonResponse))
+ return string(jsonResponse), nil
+}
+
+// 发送成功回执 todo 返回可互转的messageid 实现C2C撤回api
+func SendC2CResponse(client callapi.Client, err error, message *callapi.ActionMessage, resp *dto.C2CMessageResponse) (string, error) {
+ var messageID64 int64
+ var mapErr error
+ // 设置响应值
+ response := ServerResponse{}
+ if resp != nil {
+ messageID64, mapErr = idmap.StoreIDv2(resp.Message.ID)
+ if mapErr != nil {
+ mylog.Printf("Error storing ID: %v", mapErr)
+ return "", nil
+ }
+ response.Data.MessageID = int(messageID64)
+ } else {
+ // Default ID handling
+ response.Data.MessageID = 123
+ }
+ //将真实id转为int userid64
+ userid64, errr := idmap.StoreIDv2(message.Params.UserID.(string))
+ if errr != nil {
+ mylog.Fatalf("Error storing ID: %v", err)
+ }
+ response.UserID = userid64
+ response.Echo = message.Echo
+ if err != nil {
+ response.Message = err.Error() // 可选:在响应中添加错误消息
+ //response.RetCode = -1 // 可以是任何非零值,表示出错
+ //response.Status = "failed"
+ response.RetCode = 0 //官方api审核异步的 审核中默认返回失败,但其实信息发送成功了
+ response.Status = "ok"
+ } else {
+ response.Message = ""
+ response.RetCode = 0
+ response.Status = "ok"
+ }
+
+ // 转化为map并发送
+ outputMap := structToMap(response)
+ // 将map转换为JSON字符串
+ jsonResponse, jsonErr := json.Marshal(outputMap)
+ if jsonErr != nil {
+ log.Printf("Error marshaling response to JSON: %v", jsonErr)
+ return "", jsonErr
+ }
+ //发送给ws 客户端
+ sendErr := client.SendMessage(outputMap)
+ if sendErr != nil {
+ mylog.Printf("Error sending message via client: %v", sendErr)
+ return "", sendErr
+ }
+
+ mylog.Printf("发送成功回执: %+v", string(jsonResponse))
+ return string(jsonResponse), nil
+}
+
+// 会返回guildid的频道私信专用SendGuildPrivateResponse
+func SendGuildPrivateResponse(client callapi.Client, err error, message *callapi.ActionMessage, resp *dto.Message, guildID string) (string, error) {
+ var messageID64 int64
+ var mapErr error
+ // 设置响应值
+ response := ServerResponse{}
+ if resp != nil {
+ messageID64, mapErr = idmap.StoreIDv2(resp.ID)
+ if mapErr != nil {
+ mylog.Printf("Error storing ID: %v", mapErr)
+ return "", nil
+ }
+ response.Data.MessageID = int(messageID64)
+ } else {
+ // Default ID handling
+ response.Data.MessageID = 123
+ }
response.Echo = message.Echo
+ response.GuildID = guildID
if err != nil {
response.Message = err.Error() // 可选:在响应中添加错误消息
//response.RetCode = -1 // 可以是任何非零值,表示出错
diff --git a/handlers/send_group_forward_msg.go b/handlers/send_group_forward_msg.go
index ef31d0d8..6795e931 100644
--- a/handlers/send_group_forward_msg.go
+++ b/handlers/send_group_forward_msg.go
@@ -66,6 +66,6 @@ func HandleSendGroupForwardMsg(client callapi.Client, api openapi.OpenAPI, apiv2
count++
time.Sleep(500 * time.Millisecond) // 每条消息之间的延时
}
- retmsg, _ = SendResponse(client, nil, &message)
+ retmsg, _ = SendResponse(client, nil, &message, nil)
return retmsg, nil
}
diff --git a/handlers/send_group_msg.go b/handlers/send_group_msg.go
index 1caf0507..2cfb59e9 100644
--- a/handlers/send_group_msg.go
+++ b/handlers/send_group_msg.go
@@ -297,7 +297,7 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
}
// 发送组合消息
- _, err = apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
+ resp, err := apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
if err != nil {
mylog.Printf("发送组合消息失败: %v", err)
}
@@ -310,7 +310,7 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
}
// 发送成功回执
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendResponse(client, err, &message, resp)
delete(foundItems, imageType) // 从foundItems中删除已处理的图片项
messageText = ""
@@ -331,7 +331,7 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
groupMessage.Timestamp = time.Now().Unix() // 设置时间戳
//重新为err赋值
- _, err = apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
+ resp, err := apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
if err != nil {
mylog.Printf("发送文本群组信息失败: %v", err)
}
@@ -343,9 +343,9 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
echo.PushGlobalStack(pair)
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendResponse(client, err, &message, resp)
}
-
+ var resp *dto.GroupMessageResponse
// 遍历foundItems并发送每种信息
for key, urls := range foundItems {
for _, url := range urls {
@@ -367,7 +367,7 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
return "", nil // 或其他错误处理
}
//重新为err赋值
- _, err = apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
+ resp, err := apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
if err != nil {
mylog.Printf("发送md信息失败: %v", err)
}
@@ -379,7 +379,7 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
echo.PushGlobalStack(pair)
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendResponse(client, err, &message, resp)
}
continue // 跳过这个项,继续下一个
}
@@ -398,7 +398,7 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
}
groupMessage.Timestamp = time.Now().Unix() // 设置时间戳
//重新为err赋值
- _, err = apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
+ resp, err = apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
if err != nil {
mylog.Printf("发送文本报错信息失败: %v", err)
}
@@ -426,7 +426,7 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
}
groupMessage.Timestamp = time.Now().Unix() // 设置时间戳
//重新为err赋值
- _, err = apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
+ resp, err = apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
if err != nil {
mylog.Printf("发送图片失败: %v", err)
}
@@ -439,7 +439,7 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
}
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendResponse(client, err, &message, resp)
}
}
case "guild":
@@ -447,12 +447,12 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
message.Params.ChannelID = message.Params.GroupID.(string)
var RChannelID string
if message.Params.UserID != nil && config.GetIdmapPro() {
- RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID, message.Params.UserID.(string))
+ RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID.(string), message.Params.UserID.(string))
mylog.Printf("测试,通过Proid获取的RChannelID:%v", RChannelID)
}
if RChannelID == "" {
// 使用RetrieveRowByIDv2还原真实的ChannelID
- RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID)
+ RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID.(string))
}
if err != nil {
mylog.Printf("error retrieving real RChannelID: %v", err)
@@ -472,11 +472,11 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
return "", nil
}
if Vuserid != "" && config.GetIdmapPro() {
- RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID, Vuserid)
+ RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID.(string), Vuserid)
mylog.Printf("测试,通过Proid获取的RChannelID:%v", RChannelID)
} else {
// 使用RetrieveRowByIDv2还原真实的ChannelID
- RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID)
+ RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID.(string))
}
if err != nil {
mylog.Printf("error retrieving real ChannelID: %v", err)
@@ -497,12 +497,12 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
message.Params.ChannelID = message.Params.GroupID.(string)
var RChannelID string
if message.Params.UserID != nil && config.GetIdmapPro() {
- RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID, message.Params.UserID.(string))
+ RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID.(string), message.Params.UserID.(string))
mylog.Printf("测试,通过Proid获取的RChannelID:%v", RChannelID)
}
if RChannelID == "" {
// 使用RetrieveRowByIDv2还原真实的ChannelID
- RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID)
+ RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID.(string))
}
if err != nil {
mylog.Printf("error retrieving real RChannelID: %v", err)
diff --git a/handlers/send_group_msg_raw.go b/handlers/send_group_msg_raw.go
new file mode 100644
index 00000000..e3ecb263
--- /dev/null
+++ b/handlers/send_group_msg_raw.go
@@ -0,0 +1,493 @@
+package handlers
+
+import (
+ "context"
+ "regexp"
+ "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/tencent-connect/botgo/dto"
+ "github.com/tencent-connect/botgo/dto/keyboard"
+ "github.com/tencent-connect/botgo/openapi"
+)
+
+func init() {
+ callapi.RegisterHandler("send_group_msg_raw", HandleSendGroupMsgRaw)
+}
+
+func HandleSendGroupMsgRaw(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) (string, error) {
+ // 使用 message.Echo 作为key来获取消息类型
+ var msgType string
+ if echoStr, ok := message.Echo.(string); ok {
+ // 当 message.Echo 是字符串类型时执行此块
+ msgType = echo.GetMsgTypeByKey(echoStr)
+ }
+ // 检查GroupID是否为0
+ checkZeroGroupID := func(id interface{}) bool {
+ switch v := id.(type) {
+ case int:
+ return v != 0
+ case int64:
+ return v != 0
+ case string:
+ return v != "0" // 检查字符串形式的0
+ default:
+ return true // 如果不是int、int64或string,假定它不为0
+ }
+ }
+
+ // 检查UserID是否为0
+ checkZeroUserID := func(id interface{}) bool {
+ switch v := id.(type) {
+ case int:
+ return v != 0
+ case int64:
+ return v != 0
+ case string:
+ return v != "0" // 同样检查字符串形式的0
+ default:
+ return true // 如果不是int、int64或string,假定它不为0
+ }
+ }
+
+ if msgType == "" && message.Params.GroupID != nil && checkZeroGroupID(message.Params.GroupID) {
+ msgType = GetMessageTypeByGroupid(config.GetAppIDStr(), message.Params.GroupID)
+ }
+ if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
+ msgType = GetMessageTypeByUserid(config.GetAppIDStr(), message.Params.UserID)
+ }
+ if msgType == "" && message.Params.GroupID != nil && checkZeroGroupID(message.Params.GroupID) {
+ msgType = GetMessageTypeByGroupidV2(message.Params.GroupID)
+ }
+ if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
+ msgType = GetMessageTypeByUseridV2(message.Params.UserID)
+ }
+ // New checks for UserID and GroupID being nil or 0
+ if (message.Params.UserID == nil || !checkZeroUserID(message.Params.UserID)) &&
+ (message.Params.GroupID == nil || !checkZeroGroupID(message.Params.GroupID)) {
+ mylog.Printf("send_group_msgs接收到错误action: %v", message)
+ return "", nil
+ }
+ mylog.Printf("send_group_msg获取到信息类型:%v", msgType)
+ var idInt64 int64
+ var err error
+ var retmsg string
+
+ if message.Params.GroupID != "" {
+ idInt64, err = ConvertToInt64(message.Params.GroupID)
+ } else if message.Params.UserID != "" {
+ idInt64, err = ConvertToInt64(message.Params.UserID)
+ }
+
+ //设置递归 对直接向gsk发送action时有效果
+ if msgType == "" {
+ messageCopy := message
+ if err != nil {
+ mylog.Printf("错误:无法转换 ID %v\n", err)
+ } else {
+ // 递归3次
+ echo.AddMapping(idInt64, 4)
+ // 递归调用handleSendGroupMsg,使用设置的消息类型
+ echo.AddMsgType(config.GetAppIDStr(), idInt64, "group_private")
+ retmsg, _ = HandleSendGroupMsg(client, api, apiv2, messageCopy)
+ }
+ }
+
+ switch msgType {
+ case "group":
+ // 解析消息内容
+ messageText, foundItems := parseMessageContent(message.Params, message, client, api, apiv2)
+ var SSM bool
+
+ var originalGroupID, originalUserID string
+ // 检查UserID是否为nil
+ if message.Params.UserID != nil && config.GetIdmapPro() {
+ // 如果UserID不是nil且配置为使用Pro版本,则调用RetrieveRowByIDv2Pro
+ originalGroupID, originalUserID, err = idmap.RetrieveRowByIDv2Pro(message.Params.GroupID.(string), message.Params.UserID.(string))
+ if err != nil {
+ mylog.Printf("Error1 retrieving original GroupID: %v", err)
+ }
+ mylog.Printf("测试,通过idmaps-pro获取的originalGroupID:%v", originalGroupID)
+ if originalGroupID == "" {
+ originalGroupID, err = idmap.RetrieveRowByIDv2(message.Params.GroupID.(string))
+ if err != nil {
+ mylog.Printf("Error2 retrieving original GroupID: %v", err)
+ return "", nil
+ }
+ mylog.Printf("测试,通过idmaps获取的originalGroupID:%v", originalGroupID)
+ }
+ } else {
+ // 如果UserID是nil或配置不使用Pro版本,则调用RetrieveRowByIDv2
+ originalGroupID, err = idmap.RetrieveRowByIDv2(message.Params.GroupID.(string))
+ if err != nil {
+ mylog.Printf("Error retrieving original GroupID: %v", err)
+ }
+ // 检查 message.Params.UserID 是否为 nil
+ if message.Params.UserID == nil {
+ //mylog.Println("UserID is nil")
+ } else {
+ // 进行类型断言,确认 UserID 不是 nil
+ userID, ok := message.Params.UserID.(string)
+ if !ok {
+ mylog.Println("UserID is not a string")
+ // 处理类型断言失败的情况
+ } else {
+ originalUserID, err = idmap.RetrieveRowByIDv2(userID)
+ if err != nil {
+ mylog.Printf("Error retrieving original UserID: %v", err)
+ }
+ }
+ }
+ }
+ message.Params.GroupID = originalGroupID
+ message.Params.UserID = originalUserID
+
+ // 检查字符串是否仅包含数字
+ isNumeric := func(s string) bool {
+ return regexp.MustCompile(`^\d+$`).MatchString(s)
+ }
+
+ messageID := message.Params.MessageID.(string)
+
+ if isNumeric(messageID) && messageID != "0" {
+ // 当messageID是字符串形式的数字时,执行转换
+ RealMsgID, err := idmap.RetrieveRowByIDv2(messageID)
+ if err != nil {
+ mylog.Printf("error retrieving real MessageID: %v", err)
+ } else {
+ // 重新赋值,RealMsgID的类型与message.Params.MessageID兼容
+ messageID = RealMsgID
+ }
+ }
+
+ //2000是群主动 此时不能被动转主动
+ if SSM {
+ //mylog.Printf("正在使用Msgid:%v 补发之前失败的主动信息,请注意AtoP不要设置超过3,否则可能会影响正常信息发送", messageID)
+ //mylog.Printf("originalGroupID:%v ", originalGroupID)
+ SendStackMessages(apiv2, messageID, message.Params.GroupID.(string))
+ }
+ mylog.Println("群组发信息messageText:", messageText)
+
+ mylog.Printf("群组发信息使用messageID:[%v]", messageID)
+ var singleItem = make(map[string][]string)
+ var imageType, imageUrl string
+ imageCount := 0
+
+ // 检查不同类型的图片并计算数量
+ if imageURLs, ok := foundItems["local_image"]; ok && len(imageURLs) == 1 {
+ imageType = "local_image"
+ imageUrl = imageURLs[0]
+ imageCount++
+ } else if imageURLs, ok := foundItems["url_image"]; ok && len(imageURLs) == 1 {
+ imageType = "url_image"
+ imageUrl = imageURLs[0]
+ imageCount++
+ } else if imageURLs, ok := foundItems["url_images"]; ok && len(imageURLs) == 1 {
+ imageType = "url_images"
+ imageUrl = imageURLs[0]
+ imageCount++
+ } else if base64Images, ok := foundItems["base64_image"]; ok && len(base64Images) == 1 {
+ imageType = "base64_image"
+ imageUrl = base64Images[0]
+ imageCount++
+ }
+
+ if imageCount == 1 && messageText != "" {
+ mylog.Printf("发图文混合信息-群")
+ // 创建包含单个图片的 singleItem
+ singleItem[imageType] = []string{imageUrl}
+ msgseq := echo.GetMappingSeq(messageID)
+ echo.AddMappingSeq(messageID, msgseq+1)
+ groupReply := generateGroupMessage(messageID, singleItem, "", msgseq+1, apiv2, message.Params.GroupID.(string))
+ // 进行类型断言
+ richMediaMessage, ok := groupReply.(*dto.RichMediaMessage)
+ if !ok {
+ mylog.Printf("Error: Expected RichMediaMessage type for key ")
+ return "", nil
+ }
+ var groupMessage *dto.MessageToCreate
+ var transmd bool
+ var md *dto.Markdown
+ var kb *keyboard.MessageKeyboard
+ //判断是否需要自动转换md
+ if config.GetTwoWayEcho() {
+ md, kb, transmd = auto_md(message, messageText, richMediaMessage)
+ }
+
+ //如果没有转换成md发送
+ if !transmd {
+ // 上传图片并获取FileInfo
+ fileInfo, err := uploadMedia(context.TODO(), message.Params.GroupID.(string), richMediaMessage, apiv2)
+ if err != nil {
+ mylog.Printf("上传图片失败: %v", err)
+ return "", nil // 或其他错误处理
+ }
+ // 创建包含文本和图像信息的消息
+ msgseq = echo.GetMappingSeq(messageID)
+ echo.AddMappingSeq(messageID, msgseq+1)
+ groupMessage = &dto.MessageToCreate{
+ Content: messageText, // 添加文本内容
+ Media: dto.Media{
+ FileInfo: fileInfo, // 添加图像信息
+ },
+ MsgID: messageID,
+ MsgSeq: msgseq,
+ MsgType: 7, // 假设7是组合消息类型
+ }
+ groupMessage.Timestamp = time.Now().Unix() // 设置时间戳
+ } else {
+ //将kb和md组合成groupMessage并用MsgType=2发送
+
+ msgseq = echo.GetMappingSeq(messageID)
+ echo.AddMappingSeq(messageID, msgseq+1)
+ groupMessage = &dto.MessageToCreate{
+ Content: "markdown", // 添加文本内容
+ MsgID: messageID,
+ MsgSeq: msgseq,
+ Markdown: md,
+ Keyboard: kb,
+ MsgType: 2, // 假设7是组合消息类型
+ }
+ groupMessage.Timestamp = time.Now().Unix() // 设置时间戳
+
+ }
+ // 发送组合消息
+ resp, err := apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
+ if err != nil {
+ mylog.Printf("发送组合消息失败: %v", err)
+ }
+ if err != nil && strings.Contains(err.Error(), `"code":22009`) {
+ mylog.Printf("信息发送失败,加入到队列中,下次被动信息进行发送")
+ var pair echo.MessageGroupPair
+ pair.Group = message.Params.GroupID.(string)
+ pair.GroupMessage = groupMessage
+ echo.PushGlobalStack(pair)
+ }
+
+ // 发送成功回执
+ retmsg, _ = SendResponse(client, err, &message, resp)
+
+ delete(foundItems, imageType) // 从foundItems中删除已处理的图片项
+ messageText = ""
+ }
+
+ // 优先发送文本信息
+ if messageText != "" {
+ msgseq := echo.GetMappingSeq(messageID)
+ echo.AddMappingSeq(messageID, msgseq+1)
+ groupReply := generateGroupMessage(messageID, nil, messageText, msgseq+1, apiv2, message.Params.GroupID.(string))
+
+ // 进行类型断言
+ groupMessage, ok := groupReply.(*dto.MessageToCreate)
+ if !ok {
+ mylog.Println("Error: Expected MessageToCreate type.")
+ return "", nil // 或其他错误处理
+ }
+
+ groupMessage.Timestamp = time.Now().Unix() // 设置时间戳
+ //重新为err赋值
+ resp, err := apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
+ if err != nil {
+ mylog.Printf("发送文本群组信息失败: %v", err)
+ }
+ if err != nil && strings.Contains(err.Error(), `"code":22009`) {
+ mylog.Printf("信息发送失败,加入到队列中,下次被动信息进行发送")
+ var pair echo.MessageGroupPair
+ pair.Group = message.Params.GroupID.(string)
+ pair.GroupMessage = groupMessage
+ echo.PushGlobalStack(pair)
+ }
+ //发送成功回执
+ retmsg, _ = SendResponse(client, err, &message, resp)
+ }
+ var resp *dto.GroupMessageResponse
+ // 遍历foundItems并发送每种信息
+ for key, urls := range foundItems {
+ for _, url := range urls {
+ var singleItem = make(map[string][]string)
+ singleItem[key] = []string{url} // 创建一个只包含一个 URL 的 singleItem
+ //mylog.Println("singleItem:", singleItem)
+ msgseq := echo.GetMappingSeq(messageID)
+ echo.AddMappingSeq(messageID, msgseq+1)
+ groupReply := generateGroupMessage(messageID, singleItem, "", msgseq+1, apiv2, message.Params.GroupID.(string))
+ // 进行类型断言
+ richMediaMessage, ok := groupReply.(*dto.RichMediaMessage)
+ if !ok {
+ mylog.Printf("Error: Expected RichMediaMessage type for key %s.", key)
+ if key == "markdown" || key == "qqmusic" {
+ // 进行类型断言
+ groupMessage, ok := groupReply.(*dto.MessageToCreate)
+ if !ok {
+ mylog.Println("Error: Expected MessageToCreate type.")
+ return "", nil // 或其他错误处理
+ }
+ //重新为err赋值
+ resp, err := apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
+ if err != nil {
+ mylog.Printf("发送md信息失败: %v", err)
+ }
+ if err != nil && strings.Contains(err.Error(), `"code":22009`) {
+ mylog.Printf("信息发送失败,加入到队列中,下次被动信息进行发送")
+ var pair echo.MessageGroupPair
+ pair.Group = message.Params.GroupID.(string)
+ pair.GroupMessage = groupMessage
+ echo.PushGlobalStack(pair)
+ }
+ //发送成功回执
+ retmsg, _ = SendResponse(client, err, &message, resp)
+ }
+ continue // 跳过这个项,继续下一个
+ }
+ message_return, err := apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), richMediaMessage)
+ if err != nil {
+ mylog.Printf("发送 %s 信息失败_send_group_msg: %v", key, err)
+ if config.GetSendError() { //把报错当作文本发出去
+ msgseq := echo.GetMappingSeq(messageID)
+ echo.AddMappingSeq(messageID, msgseq+1)
+ groupReply := generateGroupMessage(messageID, nil, err.Error(), msgseq+1, apiv2, message.Params.GroupID.(string))
+ // 进行类型断言
+ groupMessage, ok := groupReply.(*dto.MessageToCreate)
+ if !ok {
+ mylog.Println("Error: Expected MessageToCreate type.")
+ return "", nil // 或其他错误处理
+ }
+ groupMessage.Timestamp = time.Now().Unix() // 设置时间戳
+ //重新为err赋值
+ resp, err = apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
+ if err != nil {
+ mylog.Printf("发送文本报错信息失败: %v", err)
+ }
+ if err != nil && strings.Contains(err.Error(), `"code":22009`) {
+ mylog.Printf("信息发送失败,加入到队列中,下次被动信息进行发送")
+ var pair echo.MessageGroupPair
+ pair.Group = message.Params.GroupID.(string)
+ pair.GroupMessage = groupMessage
+ echo.PushGlobalStack(pair)
+ }
+ }
+ }
+ if message_return != nil && message_return.MediaResponse != nil && message_return.MediaResponse.FileInfo != "" {
+ msgseq := echo.GetMappingSeq(messageID)
+ echo.AddMappingSeq(messageID, msgseq+1)
+ media := dto.Media{
+ FileInfo: message_return.MediaResponse.FileInfo,
+ }
+ groupMessage := &dto.MessageToCreate{
+ Content: " ",
+ MsgID: messageID,
+ MsgSeq: msgseq,
+ MsgType: 7, // 默认文本类型
+ Media: media,
+ }
+ groupMessage.Timestamp = time.Now().Unix() // 设置时间戳
+ //重新为err赋值
+ resp, err = apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage)
+ if err != nil {
+ mylog.Printf("发送图片失败: %v", err)
+ }
+ if err != nil && strings.Contains(err.Error(), `"code":22009`) {
+ mylog.Printf("信息发送失败,加入到队列中,下次被动信息进行发送")
+ var pair echo.MessageGroupPair
+ pair.Group = message.Params.GroupID.(string)
+ pair.GroupMessage = groupMessage
+ echo.PushGlobalStack(pair)
+ }
+ }
+ //发送成功回执
+ retmsg, _ = SendResponse(client, err, &message, resp)
+ }
+ }
+ case "guild":
+ //用GroupID给ChannelID赋值,因为我们是把频道虚拟成了群
+ message.Params.ChannelID = message.Params.GroupID.(string)
+ var RChannelID string
+ if message.Params.UserID != nil && config.GetIdmapPro() {
+ RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID.(string), message.Params.UserID.(string))
+ mylog.Printf("测试,通过Proid获取的RChannelID:%v", RChannelID)
+ }
+ if RChannelID == "" {
+ // 使用RetrieveRowByIDv2还原真实的ChannelID
+ RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID.(string))
+ }
+ if err != nil {
+ mylog.Printf("error retrieving real RChannelID: %v", err)
+ }
+ message.Params.ChannelID = RChannelID
+ //这一句是group_private的逻辑,发频道信息用的是channelid
+ //message.Params.GroupID = value
+ retmsg, _ = HandleSendGuildChannelMsg(client, api, apiv2, message)
+ case "guild_private":
+ //用group_id还原出channelid 这是虚拟成群的私聊信息
+ var RChannelID string
+ var Vuserid string
+ message.Params.ChannelID = message.Params.GroupID.(string)
+ Vuserid, ok := message.Params.UserID.(string)
+ if !ok {
+ mylog.Printf("Error illegal UserID")
+ return "", nil
+ }
+ if Vuserid != "" && config.GetIdmapPro() {
+ RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID.(string), Vuserid)
+ mylog.Printf("测试,通过Proid获取的RChannelID:%v", RChannelID)
+ } else {
+ // 使用RetrieveRowByIDv2还原真实的ChannelID
+ RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID.(string))
+ }
+ if err != nil {
+ mylog.Printf("error retrieving real ChannelID: %v", err)
+ }
+ //读取ini 通过ChannelID取回之前储存的guild_id
+ value, err := idmap.ReadConfigv2(RChannelID, "guild_id")
+ if err != nil {
+ mylog.Printf("Error reading config: %v", err)
+ return "", nil
+ }
+ retmsg, _ = HandleSendGuildChannelPrivateMsg(client, api, apiv2, message, &value, &RChannelID)
+ case "group_private":
+ //用userid还原出openid 这是虚拟成群的群聊私聊信息
+ message.Params.UserID = message.Params.GroupID.(string)
+ retmsg, _ = HandleSendPrivateMsg(client, api, apiv2, message)
+ case "forum":
+ //用GroupID给ChannelID赋值,因为我们是把频道虚拟成了群
+ message.Params.ChannelID = message.Params.GroupID.(string)
+ var RChannelID string
+ if message.Params.UserID != nil && config.GetIdmapPro() {
+ RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID.(string), message.Params.UserID.(string))
+ mylog.Printf("测试,通过Proid获取的RChannelID:%v", RChannelID)
+ }
+ if RChannelID == "" {
+ // 使用RetrieveRowByIDv2还原真实的ChannelID
+ RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID.(string))
+ }
+ if err != nil {
+ mylog.Printf("error retrieving real RChannelID: %v", err)
+ }
+ message.Params.ChannelID = RChannelID
+ //这一句是group_private的逻辑,发频道信息用的是channelid
+ //message.Params.GroupID = value
+ retmsg, _ = HandleSendGuildChannelForum(client, api, apiv2, message)
+ default:
+ mylog.Printf("Unknown message type: %s", msgType)
+ }
+ //重置递归类型
+ if echo.GetMapping(idInt64) <= 0 {
+ echo.AddMsgType(config.GetAppIDStr(), idInt64, "")
+ }
+ echo.AddMapping(idInt64, echo.GetMapping(idInt64)-1)
+
+ //递归3次枚举类型
+ if echo.GetMapping(idInt64) > 0 {
+ tryMessageTypes := []string{"group", "guild", "guild_private"}
+ messageCopy := message // 创建message的副本
+ echo.AddMsgType(config.GetAppIDStr(), idInt64, tryMessageTypes[echo.GetMapping(idInt64)-1])
+ delay := config.GetSendDelay()
+ time.Sleep(time.Duration(delay) * time.Millisecond)
+ retmsg, _ = HandleSendGroupMsg(client, api, apiv2, messageCopy)
+ }
+ return retmsg, nil
+}
diff --git a/handlers/send_guild_channel_forum.go b/handlers/send_guild_channel_forum.go
index 7b1d5ee4..fd686c48 100644
--- a/handlers/send_guild_channel_forum.go
+++ b/handlers/send_guild_channel_forum.go
@@ -70,6 +70,12 @@ func HandleSendGuildChannelForum(client callapi.Client, api openapi.OpenAPI, api
if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUseridV2(message.Params.UserID)
}
+ // New checks for UserID and GroupID being nil or 0
+ if (message.Params.UserID == nil || !checkZeroUserID(message.Params.UserID)) &&
+ (message.Params.GroupID == nil || !checkZeroGroupID(message.Params.GroupID)) {
+ mylog.Printf("send_group_msgs接收到错误action: %v", message)
+ return "", nil
+ }
//当不转换频道信息时(不支持频道私聊)
if msgType == "" {
@@ -90,12 +96,12 @@ func HandleSendGuildChannelForum(client callapi.Client, api openapi.OpenAPI, api
if err != nil {
mylog.Printf("组合帖子信息失败: %v", err)
}
- if _, err = api.PostFourm(context.TODO(), channelID, Forum); err != nil {
+ if _, err = api.PostFourm(context.TODO(), channelID.(string), Forum); err != nil {
mylog.Printf("发送帖子信息失败: %v", err)
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendResponse(client, err, &message, nil)
default:
mylog.Printf("2Unknown message type: %s", msgType)
diff --git a/handlers/send_guild_channel_msg.go b/handlers/send_guild_channel_msg.go
index a9e8a48b..aeb263a9 100644
--- a/handlers/send_guild_channel_msg.go
+++ b/handlers/send_guild_channel_msg.go
@@ -74,6 +74,12 @@ func HandleSendGuildChannelMsg(client callapi.Client, api openapi.OpenAPI, apiv2
if msgType == "" && message.Params.UserID != nil && checkZeroUserID(message.Params.UserID) {
msgType = GetMessageTypeByUseridV2(message.Params.UserID)
}
+ // New checks for UserID and GroupID being nil or 0
+ if (message.Params.UserID == nil || !checkZeroUserID(message.Params.UserID)) &&
+ (message.Params.GroupID == nil || !checkZeroGroupID(message.Params.GroupID)) {
+ mylog.Printf("send_group_msgs接收到错误action: %v", message)
+ return "", nil
+ }
//当不转换频道信息时(不支持频道私聊)
if msgType == "" {
msgType = "guild"
@@ -89,7 +95,7 @@ func HandleSendGuildChannelMsg(client callapi.Client, api openapi.OpenAPI, apiv2
var messageID string
if config.GetLazyMessageId() {
//由于实现了Params的自定义unmarshell 所以可以类型安全的断言为string
- messageID = echo.GetLazyMessagesId(channelID)
+ messageID = echo.GetLazyMessagesId(channelID.(string))
mylog.Printf("GetLazyMessagesId: %v", messageID)
}
if messageID == "" {
@@ -136,6 +142,7 @@ func HandleSendGuildChannelMsg(client callapi.Client, api openapi.OpenAPI, apiv2
imageCount++
}
+ var resp *dto.Message
if imageCount == 1 && messageText != "" {
//我想优化一下这里,让它优雅一点
mylog.Printf("发图文混合信息-频道")
@@ -157,7 +164,7 @@ func HandleSendGuildChannelMsg(client callapi.Client, api openapi.OpenAPI, apiv2
}
newMessage.Timestamp = time.Now().Unix() // 设置时间戳
- if _, err = api.PostMessage(context.TODO(), channelID, newMessage); err != nil {
+ if _, err = api.PostMessage(context.TODO(), channelID.(string), newMessage); err != nil {
mylog.Printf("发送图文混合信息失败: %v", err)
}
// 检查是否是 40003 错误
@@ -184,7 +191,7 @@ func HandleSendGuildChannelMsg(client callapi.Client, api openapi.OpenAPI, apiv2
mylog.Printf("Error compressing image: %v", err)
}
// 使用 Multipart 方法发送
- if _, err = api.PostMessageMultipart(context.TODO(), channelID, newMessage, compressedData); err != nil {
+ if _, err = api.PostMessageMultipart(context.TODO(), channelID.(string), newMessage, compressedData); err != nil {
mylog.Printf("40003重试,使用 multipart 发送图文混合信息失败: %v message_id %v", err, messageID)
}
}
@@ -212,12 +219,12 @@ func HandleSendGuildChannelMsg(client callapi.Client, api openapi.OpenAPI, apiv2
}
newMessage.Timestamp = time.Now().Unix() // 设置时间戳
// 使用Multipart方法发送
- if _, err = api.PostMessageMultipart(context.TODO(), channelID, newMessage, compressedData); err != nil {
+ if resp, err = api.PostMessageMultipart(context.TODO(), channelID.(string), newMessage, compressedData); err != nil {
mylog.Printf("使用multipart发送图文信息失败: %v message_id %v", err, messageID)
}
}
// 发送成功回执
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendGuildResponse(client, err, &message, resp)
delete(foundItems, imageType) // 从foundItems中删除已处理的图片项
messageText = ""
}
@@ -228,11 +235,11 @@ func HandleSendGuildChannelMsg(client callapi.Client, api openapi.OpenAPI, apiv2
msgseq := echo.GetMappingSeq(messageID)
echo.AddMappingSeq(messageID, msgseq+1)
textMsg, _ := GenerateReplyMessage(messageID, nil, messageText, msgseq+1)
- if _, err = api.PostMessage(context.TODO(), channelID, textMsg); err != nil {
+ if resp, err = api.PostMessage(context.TODO(), channelID.(string), textMsg); err != nil {
mylog.Printf("发送文本信息失败: %v", err)
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendGuildResponse(client, err, &message, resp)
}
// 遍历foundItems并发送每种信息
@@ -259,13 +266,13 @@ func HandleSendGuildChannelMsg(client callapi.Client, api openapi.OpenAPI, apiv2
mylog.Printf("Error compressing image: %v", err)
}
// 使用Multipart方法发送
- if _, err = api.PostMessageMultipart(context.TODO(), channelID, reply, compressedData); err != nil {
+ if resp, err = api.PostMessageMultipart(context.TODO(), channelID.(string), reply, compressedData); err != nil {
mylog.Printf("使用multipart发送 %s 信息失败: %v message_id %v", key, err, messageID)
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendGuildResponse(client, err, &message, resp)
} else {
- if _, err = api.PostMessage(context.TODO(), channelID, reply); err != nil {
+ if _, err = api.PostMessage(context.TODO(), channelID.(string), reply); err != nil {
mylog.Printf("发送 %s 信息失败: %v", key, err)
}
// 检查是否是 40003 错误
@@ -292,14 +299,14 @@ func HandleSendGuildChannelMsg(client callapi.Client, api openapi.OpenAPI, apiv2
mylog.Printf("Error compressing image: %v", err)
}
// 使用 Multipart 方法发送
- if _, err = api.PostMessageMultipart(context.TODO(), channelID, reply, compressedData); err != nil {
+ if resp, err = api.PostMessageMultipart(context.TODO(), channelID.(string), reply, compressedData); err != nil {
mylog.Printf("40003重试,使用 multipart 发送 %s 信息失败: %v message_id %v", key, err, messageID)
}
}
}
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendGuildResponse(client, err, &message, resp)
}
}
}
@@ -311,11 +318,12 @@ func HandleSendGuildChannelMsg(client callapi.Client, api openapi.OpenAPI, apiv2
var RChannelID string
var err error
// 使用RetrieveRowByIDv2还原真实的ChannelID
- RChannelID, err = idmap.RetrieveRowByIDv2(channelID)
+ RChannelID, err = idmap.RetrieveRowByIDv2(channelID.(string))
if err != nil {
mylog.Printf("error retrieving real UserID: %v", err)
}
- retmsg, _ = HandleSendGuildChannelPrivateMsg(client, api, apiv2, message, &guildID, &RChannelID)
+ RguildID := guildID.(string)
+ retmsg, _ = HandleSendGuildChannelPrivateMsg(client, api, apiv2, message, &RguildID, &RChannelID)
case "forum":
//api一样的 直接丢进去试试
retmsg, _ = HandleSendGuildChannelForum(client, api, apiv2, message)
diff --git a/handlers/send_guild_private_msg.go b/handlers/send_guild_private_msg.go
index 72e7bf30..2177aa18 100644
--- a/handlers/send_guild_private_msg.go
+++ b/handlers/send_guild_private_msg.go
@@ -196,17 +196,17 @@ func HandleSendGuildChannelPrivateMsg(client callapi.Client, api openapi.OpenAPI
ChannelID: channelID,
CreateTime: timestampStr,
}
-
+ var resp *dto.Message
// 优先发送文本信息
if messageText != "" {
msgseq := echo.GetMappingSeq(messageID)
echo.AddMappingSeq(messageID, msgseq+1)
textMsg, _ := GenerateReplyMessage(messageID, nil, messageText, msgseq+1)
- if _, err = apiv2.PostDirectMessage(context.TODO(), dm, textMsg); err != nil {
+ if resp, err = apiv2.PostDirectMessage(context.TODO(), dm, textMsg); err != nil {
mylog.Printf("发送文本信息失败: %v", err)
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendGuildPrivateResponse(client, err, &message, resp, guildID)
}
// 遍历foundItems并发送每种信息
@@ -232,16 +232,16 @@ func HandleSendGuildChannelPrivateMsg(client callapi.Client, api openapi.OpenAPI
if err != nil {
mylog.Printf("Error compressing image: %v", err)
}
- if _, err = api.PostDirectMessageMultipart(context.TODO(), dm, reply, compressedData); err != nil {
+ if resp, err = api.PostDirectMessageMultipart(context.TODO(), dm, reply, compressedData); err != nil {
mylog.Printf("使用multipart发送 %s 信息失败: %v message_id %v", key, err, messageID)
}
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendGuildResponse(client, err, &message, resp)
} else {
// 处理非 Base64 图片的逻辑
if _, err = api.PostDirectMessage(context.TODO(), dm, reply); err != nil {
mylog.Printf("发送 %s 信息失败: %v", key, err)
}
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendGuildPrivateResponse(client, err, &message, resp, guildID)
}
}
}
diff --git a/handlers/send_msg.go b/handlers/send_msg.go
index 42578736..5a4137e8 100644
--- a/handlers/send_msg.go
+++ b/handlers/send_msg.go
@@ -122,12 +122,12 @@ func HandleSendMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.Ope
message.Params.ChannelID = message.Params.GroupID.(string)
var RChannelID string
if message.Params.UserID != nil && config.GetIdmapPro() {
- RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID, message.Params.UserID.(string))
+ RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID.(string), message.Params.UserID.(string))
mylog.Printf("测试,通过Proid获取的RChannelID:%v", RChannelID)
}
if RChannelID == "" {
// 使用RetrieveRowByIDv2还原真实的ChannelID
- RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID)
+ RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID.(string))
}
if err != nil {
mylog.Printf("error retrieving real RChannelID: %v", err)
@@ -148,12 +148,12 @@ func HandleSendMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.Ope
message.Params.ChannelID = message.Params.GroupID.(string)
var RChannelID string
if message.Params.UserID != nil && config.GetIdmapPro() {
- RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID, message.Params.UserID.(string))
+ RChannelID, _, err = idmap.RetrieveRowByIDv2Pro(message.Params.ChannelID.(string), message.Params.UserID.(string))
mylog.Printf("测试,通过Proid获取的RChannelID:%v", RChannelID)
}
if RChannelID == "" {
// 使用RetrieveRowByIDv2还原真实的ChannelID
- RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID)
+ RChannelID, err = idmap.RetrieveRowByIDv2(message.Params.ChannelID.(string))
}
if err != nil {
mylog.Printf("error retrieving real RChannelID: %v", err)
diff --git a/handlers/send_private_msg.go b/handlers/send_private_msg.go
index f8daf4c5..be98f276 100644
--- a/handlers/send_private_msg.go
+++ b/handlers/send_private_msg.go
@@ -96,7 +96,7 @@ func HandleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open
HandleSendPrivateMsg(client, api, apiv2, messageCopy)
}
}
-
+ var resp *dto.C2CMessageResponse
switch msgType {
//这里是pr上来的,我也不明白为什么私聊会出现group类型 猜测是为了匹配包含了groupid的私聊?
case "group_private", "group":
@@ -206,14 +206,14 @@ func HandleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open
groupMessage.Timestamp = time.Now().Unix() // 设置时间戳
// 发送组合消息
- _, err = apiv2.PostC2CMessage(context.TODO(), UserID, groupMessage)
+ resp, err = apiv2.PostC2CMessage(context.TODO(), UserID, groupMessage)
if err != nil {
mylog.Printf("发送组合消息失败: %v", err)
return "", nil // 或其他错误处理
}
// 发送成功回执
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendC2CResponse(client, err, &message, resp)
delete(foundItems, imageType) // 从foundItems中删除已处理的图片项
messageText = ""
@@ -233,14 +233,14 @@ func HandleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open
}
groupMessage.Timestamp = time.Now().Unix() // 设置时间戳
- _, err := apiv2.PostC2CMessage(context.TODO(), UserID, groupMessage)
+ resp, err := apiv2.PostC2CMessage(context.TODO(), UserID, groupMessage)
if err != nil {
mylog.Printf("发送文本私聊信息失败: %v", err)
//如果失败 防止进入递归
return "", nil
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendC2CResponse(client, err, &message, resp)
}
// 遍历foundItems并发送每种信息
@@ -294,13 +294,13 @@ func HandleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open
}
groupMessage.Timestamp = time.Now().Unix() // 设置时间戳
//重新为err赋值
- _, err = apiv2.PostC2CMessage(context.TODO(), UserID, groupMessage)
+ resp, err = apiv2.PostC2CMessage(context.TODO(), UserID, groupMessage)
if err != nil {
mylog.Printf("发送 %s 私聊信息失败: %v", key, err)
}
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message)
+ retmsg, _ = SendC2CResponse(client, err, &message, resp)
}
}
//这里是pr上来的,我也不明白为什么私聊会出现guild类型
diff --git a/httpapi/httpapi.go b/httpapi/httpapi.go
index 986bc2e6..5f95d4f2 100644
--- a/httpapi/httpapi.go
+++ b/httpapi/httpapi.go
@@ -1,11 +1,12 @@
package httpapi
import (
- "github.com/hoshinonyaruko/gensokyo/config"
"net/http"
"strconv"
"strings"
+ "github.com/hoshinonyaruko/gensokyo/config"
+
"github.com/gin-gonic/gin"
"github.com/hoshinonyaruko/gensokyo/callapi"
"github.com/hoshinonyaruko/gensokyo/handlers"
@@ -29,6 +30,10 @@ func CombinedMiddleware(api openapi.OpenAPI, apiV2 openapi.OpenAPI) gin.HandlerF
handleSendGroupMessage(c, api, apiV2)
return
}
+ if c.Request.URL.Path == "/send_group_msg_raw" {
+ handleSendGroupMessageRaw(c, api, apiV2)
+ return
+ }
if c.Request.URL.Path == "/send_private_msg" {
handleSendPrivateMessage(c, api, apiV2)
return
@@ -102,6 +107,59 @@ func handleSendGroupMessage(c *gin.Context, api openapi.OpenAPI, apiV2 openapi.O
c.String(http.StatusOK, retmsg)
}
+// handleSendGroupMessageRaw 处理发送群聊消息的请求
+func handleSendGroupMessageRaw(c *gin.Context, api openapi.OpenAPI, apiV2 openapi.OpenAPI) {
+ var retmsg string
+ var req struct {
+ GroupID int64 `json:"group_id" form:"group_id"`
+ MessageID string `json:"message_id" form:"message_id"`
+ UserID *int64 `json:"user_id,omitempty" form:"user_id"`
+ Message string `json:"message" form:"message"`
+ AutoEscape bool `json:"auto_escape" form:"auto_escape"`
+ }
+
+ // 根据请求方法解析参数
+ if c.Request.Method == http.MethodGet {
+ // 从URL查询参数解析
+ if err := c.ShouldBindQuery(&req); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+ } else {
+ // 从JSON或表单数据解析
+ if err := c.ShouldBind(&req); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+ }
+
+ // 使用解析后的参数处理请求
+ client := &HttpAPIClient{}
+ // 创建 ActionMessage 实例
+ message := callapi.ActionMessage{
+ Action: "send_group_msg_raw",
+ Params: callapi.ParamsContent{
+ GroupID: strconv.FormatInt(req.GroupID, 10), // 注意这里需要转换类型,因为 GroupID 是 int64
+ MessageID: req.MessageID,
+ Message: req.Message,
+ },
+ }
+ // 如果 UserID 存在,则加入到参数中
+ if req.UserID != nil {
+ message.Params.UserID = strconv.FormatInt(*req.UserID, 10)
+ }
+ // 调用处理函数
+ retmsg, err := handlers.HandleSendGroupMsgRaw(client, api, apiV2, message)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
+ return
+ }
+
+ // 返回处理结果
+ c.Header("Content-Type", "application/json")
+ c.String(http.StatusOK, retmsg)
+}
+
// handleSendPrivateMessage 处理发送私聊消息的请求
func handleSendPrivateMessage(c *gin.Context, api openapi.OpenAPI, apiV2 openapi.OpenAPI) {
var retmsg string
From ab6c474385c4ab445f7916d75ae00d2d6babe6f0 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Sun, 24 Mar 2024 17:24:55 +0800
Subject: [PATCH 14/33] beta349
---
botgo/dto/message_create.go | 1 +
config/config.go | 470 ++++++++++++++++++++++++++----------
images/upload_api.go | 60 +++--
main.go | 7 +
template/config_template.go | 128 +++++-----
5 files changed, 452 insertions(+), 214 deletions(-)
diff --git a/botgo/dto/message_create.go b/botgo/dto/message_create.go
index 0e1be64b..0107c976 100644
--- a/botgo/dto/message_create.go
+++ b/botgo/dto/message_create.go
@@ -21,6 +21,7 @@ type RichMediaMessage struct {
EventID string `json:"event_id,omitempty"` // 要回复的事件id, 逻辑同MsgID
FileType uint64 `json:"file_type,omitempty"` // 业务类型,图片,文件,语音,视频 文件类型,取值:1图片,2视频,3语音(目前语音只支持silk格式)
URL string `json:"url,omitempty"`
+ FileData string `json:"file_data,omitempty"` //没有base64头的base64
SrvSendMsg bool `json:"srv_send_msg,omitempty"`
Content string `json:"content,omitempty"`
}
diff --git a/config/config.go b/config/config.go
index d97e6d4d..a5a6bf91 100644
--- a/config/config.go
+++ b/config/config.go
@@ -9,6 +9,7 @@ import (
"regexp"
"strings"
"sync"
+ "time"
"github.com/hoshinonyaruko/gensokyo/mylog"
"github.com/hoshinonyaruko/gensokyo/sys"
@@ -31,136 +32,170 @@ type VisualPrefixConfig struct {
NoWhiteResponse string `yaml:"No_White_Response"`
}
type Settings struct {
- WsAddress []string `yaml:"ws_address"`
- AppID uint64 `yaml:"app_id"`
- Token string `yaml:"token"`
- ClientSecret string `yaml:"client_secret"`
- TextIntent []string `yaml:"text_intent"`
- GlobalChannelToGroup bool `yaml:"global_channel_to_group"`
- GlobalPrivateToChannel bool `yaml:"global_private_to_channel"`
- GlobalForumToChannel bool `yaml:"global_forum_to_channel"`
- Array bool `yaml:"array"`
- Server_dir string `yaml:"server_dir"`
- Lotus bool `yaml:"lotus"`
- Port string `yaml:"port"`
- WsToken []string `yaml:"ws_token,omitempty"` // 连接wss时使用,不是wss可留空 一一对应
- MasterID []string `yaml:"master_id,omitempty"` // 如果需要在群权限判断是管理员是,将user_id填入这里,master_id是一个文本数组
- EnableWsServer bool `yaml:"enable_ws_server,omitempty"` //正向ws开关
- WsServerToken string `yaml:"ws_server_token,omitempty"` //正向ws token
- IdentifyFile bool `yaml:"identify_file"` // 域名校验文件
- Crt string `yaml:"crt"`
- Key string `yaml:"key"`
- DeveloperLog bool `yaml:"developer_log"`
- Username string `yaml:"server_user_name"`
- Password string `yaml:"server_user_password"`
- ImageLimit int `yaml:"image_sizelimit"`
- RemovePrefix bool `yaml:"remove_prefix"`
- BackupPort string `yaml:"backup_port"`
- DevlopAcDir string `yaml:"develop_access_token_dir"`
- RemoveAt bool `yaml:"remove_at"`
- DevBotid string `yaml:"develop_bot_id"`
- SandBoxMode bool `yaml:"sandbox_mode"`
- Title string `yaml:"title"`
- HashID bool `yaml:"hash_id"`
- TwoWayEcho bool `yaml:"twoway_echo"`
- LazyMessageId bool `yaml:"lazy_message_id"`
- WhitePrefixMode bool `yaml:"white_prefix_mode"`
- WhitePrefixs []string `yaml:"white_prefixs"`
- BlackPrefixMode bool `yaml:"black_prefix_mode"`
- BlackPrefixs []string `yaml:"black_prefixs"`
- VisualPrefixs []VisualPrefixConfig `yaml:"visual_prefixs"`
- VisibleIp bool `yaml:"visible_ip"`
- ForwardMsgLimit int `yaml:"forward_msg_limit"`
- DevMessgeID bool `yaml:"dev_message_id"`
- LogLevel int `yaml:"log_level"`
- SaveLogs bool `yaml:"save_logs"`
- BindPrefix string `yaml:"bind_prefix"`
- MePrefix string `yaml:"me_prefix"`
- FrpPort string `yaml:"frp_port"`
- RemoveBotAtGroup bool `yaml:"remove_bot_at_group"`
- ImageLimitB int `yaml:"image_limit"`
- RecordSampleRate int `yaml:"record_sampleRate"`
- RecordBitRate int `yaml:"record_bitRate"`
- NoWhiteResponse string `yaml:"No_White_Response"`
- SendError bool `yaml:"send_error"`
- AddAtGroup bool `yaml:"add_at_group"`
- UrlPicTransfer bool `yaml:"url_pic_transfer"`
- LotusPassword string `yaml:"lotus_password"`
- WsServerPath string `yaml:"ws_server_path"`
- IdmapPro bool `yaml:"idmap_pro"`
- CardAndNick string `yaml:"card_nick"`
- AutoBind bool `yaml:"auto_bind"`
- CustomBotName string `yaml:"custom_bot_name"`
- SendDelay int `yaml:"send_delay"`
- AtoPCount int `yaml:"AMsgRetryAsPMsg_Count"`
- ReconnecTimes int `yaml:"reconnect_times"`
- HeartBeatInterval int `yaml:"heart_beat_interval"`
- LaunchReconectTimes int `yaml:"launch_reconnect_times"`
- UnlockPrefix string `yaml:"unlock_prefix"`
- WhiteBypass []int64 `yaml:"white_bypass"`
- TransferUrl bool `yaml:"transfer_url"`
- HttpAddress string `yaml:"http_address"`
- AccessToken string `yaml:"http_access_token"`
- HttpVersion int `yaml:"http_version"`
- HttpTimeOut int `yaml:"http_timeout"`
- PostUrl []string `yaml:"post_url"`
- PostSecret []string `yaml:"post_secret"`
- PostMaxRetries []int `yaml:"post_max_retries"`
- PostRetriesInterval []int `yaml:"post_retries_interval"`
- NativeOb11 bool `yaml:"native_ob11"`
- RamDomSeq bool `yaml:"ramdom_seq"`
- UrlToQrimage bool `yaml:"url_to_qrimage"`
- QrSize int `yaml:"qr_size"`
- WhiteBypassRevers bool `yaml:"white_bypass_reverse"`
- GuildUrlImageToBase64 bool `yaml:"guild_url_image_to_base64"`
- TencentBucketName string `yaml:"t_COS_BUCKETNAME"`
- TencentBucketRegion string `yaml:"t_COS_REGION"`
- TencentCosSecretid string `yaml:"t_COS_SECRETID"`
- TencentSecretKey string `yaml:"t_COS_SECRETKEY"`
- TencentAudit bool `yaml:"t_audit"`
- OssType int `yaml:"oss_type"`
- BaiduBOSBucketName string `yaml:"b_BOS_BUCKETNAME"`
- BaiduBCEAK string `yaml:"b_BCE_AK"`
- BaiduBCESK string `yaml:"b_BCE_SK"`
- BaiduAudit int `yaml:"b_audit"`
- AliyunEndpoint string `yaml:"a_OSS_EndPoint"`
- AliyunAccessKeyId string `yaml:"a_OSS_AccessKeyId"`
- AliyunAccessKeySecret string `yaml:"a_OSS_AccessKeySecret"`
- AliyunBucketName string `yaml:"a_OSS_BucketName"`
- AliyunAudit bool `yaml:"a_audit"`
- Alias []string `yaml:"alias"`
- SelfIntroduce []string `yaml:"self_introduce"`
- WhiteEnable []bool `yaml:"white_enable"`
- IdentifyAppids []int64 `yaml:"identify_appids"`
- TransFormApiIds bool `yaml:"transform_api_ids"`
- CustomTemplateID string `yaml:"custom_template_id"`
- KeyBoardID string `yaml:"keyboard_id"`
- Uin int64 `yaml:"uin"`
- VwhitePrefixMode bool `yaml:"v_white_prefix_mode"`
- Enters []string `yaml:"enters"`
- LinkPrefix string `yaml:"link_prefix"`
- LinkBots []string `yaml:"link_bots"`
- LinkText string `yaml:"link_text"`
- LinkPic string `yaml:"link_pic"`
- MusicPrefix string `yaml:"music_prefix"`
- DisableWebui bool `yaml:"disable_webui"`
- ShardCount int `yaml:"shard_count"`
- ShardID int `yaml:"shard_id"`
- BotForumTitle string `yaml:"bot_forum_title"`
- GlobalInteractionToMessage bool `yaml:"global_interaction_to_message"`
- AutoPutInteraction bool `yaml:"auto_put_interaction"`
- PutInteractionDelay int `yaml:"put_interaction_delay"`
- ImgUpApiVtv2 bool `yaml:"img_up_api_ntv2"`
- Fix11300 bool `yaml:"fix_11300"`
- LotusWithoutIdmaps bool `yaml:"lotus_without_idmaps"`
- GetGroupListAllGuilds bool `yaml:"get_g_list_all_guilds"`
- GetGroupListGuilds string `yaml:"get_g_list_guilds"`
- GetGroupListReturnGuilds bool `yaml:"get_g_list_return_guilds"`
- GetGroupListGuidsType int `yaml:"get_g_list_guilds_type"`
- GetGroupListDelay int `yaml:"get_g_list_delay"`
- GlobalServerTempQQguild bool `yaml:"global_server_temp_qqguild"`
- ServerTempQQguild string `yaml:"server_temp_qqguild"`
- ServerTempQQguildPool []string `yaml:"server_temp_qqguild_pool"`
+ //反向ws设置
+ WsAddress []string `yaml:"ws_address"`
+ WsToken []string `yaml:"ws_token,omitempty"`
+ ReconnecTimes int `yaml:"reconnect_times"`
+ HeartBeatInterval int `yaml:"heart_beat_interval"`
+ LaunchReconectTimes int `yaml:"launch_reconnect_times"`
+ //基础配置
+ AppID uint64 `yaml:"app_id"`
+ Uin int64 `yaml:"uin"`
+ Token string `yaml:"token"`
+ ClientSecret string `yaml:"client_secret"`
+ ShardCount int `yaml:"shard_count"`
+ ShardID int `yaml:"shard_id"`
+ //事件订阅类
+ TextIntent []string `yaml:"text_intent"`
+ //转换类
+ GlobalChannelToGroup bool `yaml:"global_channel_to_group"`
+ GlobalPrivateToChannel bool `yaml:"global_private_to_channel"`
+ GlobalForumToChannel bool `yaml:"global_forum_to_channel"`
+ GlobalInteractionToMessage bool `yaml:"global_interaction_to_message"`
+ HashID bool `yaml:"hash_id"`
+ IdmapPro bool `yaml:"idmap_pro"`
+ //gensokyo互联类
+ Server_dir string `yaml:"server_dir"`
+ Port string `yaml:"port"`
+ BackupPort string `yaml:"backup_port"`
+ Lotus bool `yaml:"lotus"`
+ LotusPassword string `yaml:"lotus_password"`
+ LotusWithoutIdmaps bool `yaml:"lotus_without_idmaps"`
+ //增强配置
+ MasterID []string `yaml:"master_id,omitempty"`
+ RecordSampleRate int `yaml:"record_sampleRate"`
+ RecordBitRate int `yaml:"record_bitRate"`
+ CardAndNick string `yaml:"card_nick"`
+ AutoBind bool `yaml:"auto_bind"`
+ //发图相关
+ OssType int `yaml:"oss_type"`
+ ImageLimit int `yaml:"image_sizelimit"`
+ ImageLimitB int `yaml:"image_limit"`
+ GuildUrlImageToBase64 bool `yaml:"guild_url_image_to_base64"`
+ UrlPicTransfer bool `yaml:"url_pic_transfer"`
+ ImgUpApiVtv2 bool `yaml:"img_up_api_ntv2"`
+ UploadPicV2Base64 bool `yaml:"uploadpicv2_b64"`
+ GlobalServerTempQQguild bool `yaml:"global_server_temp_qqguild"`
+ ServerTempQQguild string `yaml:"server_temp_qqguild"`
+ ServerTempQQguildPool []string `yaml:"server_temp_qqguild_pool"`
+ //正向ws设置
+ WsServerPath string `yaml:"ws_server_path"`
+ EnableWsServer bool `yaml:"enable_ws_server,omitempty"`
+ WsServerToken string `yaml:"ws_server_token,omitempty"`
+ //ssl和链接转换类
+ IdentifyFile bool `yaml:"identify_file"`
+ IdentifyAppids []int64 `yaml:"identify_appids"`
+ Crt string `yaml:"crt"`
+ Key string `yaml:"key"`
+ //日志类
+ DeveloperLog bool `yaml:"developer_log"`
+ LogLevel int `yaml:"log_level"`
+ SaveLogs bool `yaml:"save_logs"`
+ //webui相关
+ DisableWebui bool `yaml:"disable_webui"`
+ Username string `yaml:"server_user_name"`
+ Password string `yaml:"server_user_password"`
+ //指令魔法类
+ RemovePrefix bool `yaml:"remove_prefix"`
+ RemoveAt bool `yaml:"remove_at"`
+ RemoveBotAtGroup bool `yaml:"remove_bot_at_group"`
+ AddAtGroup bool `yaml:"add_at_group"`
+ WhitePrefixMode bool `yaml:"white_prefix_mode"`
+ VwhitePrefixMode bool `yaml:"v_white_prefix_mode"`
+ WhitePrefixs []string `yaml:"white_prefixs"`
+ WhiteBypass []int64 `yaml:"white_bypass"`
+ WhiteEnable []bool `yaml:"white_enable"`
+ WhiteBypassRevers bool `yaml:"white_bypass_reverse"`
+ NoWhiteResponse string `yaml:"No_White_Response"`
+ BlackPrefixMode bool `yaml:"black_prefix_mode"`
+ BlackPrefixs []string `yaml:"black_prefixs"`
+ Alias []string `yaml:"alias"`
+ Enters []string `yaml:"enters"`
+ VisualPrefixs []VisualPrefixConfig `yaml:"visual_prefixs"`
+ //开发增强类
+ DevlopAcDir string `yaml:"develop_access_token_dir"`
+ DevBotid string `yaml:"develop_bot_id"`
+ SandBoxMode bool `yaml:"sandbox_mode"`
+ DevMessgeID bool `yaml:"dev_message_id"`
+ SendError bool `yaml:"send_error"`
+ //增长营销类
+ SelfIntroduce []string `yaml:"self_introduce"`
+ //api修改
+ GetGroupListAllGuilds bool `yaml:"get_g_list_all_guilds"`
+ GetGroupListGuilds string `yaml:"get_g_list_guilds"`
+ GetGroupListReturnGuilds bool `yaml:"get_g_list_return_guilds"`
+ GetGroupListGuidsType int `yaml:"get_g_list_guilds_type"`
+ GetGroupListDelay int `yaml:"get_g_list_delay"`
+ ForwardMsgLimit int `yaml:"forward_msg_limit"`
+ CustomBotName string `yaml:"custom_bot_name"`
+ TransFormApiIds bool `yaml:"transform_api_ids"`
+ AutoPutInteraction bool `yaml:"auto_put_interaction"`
+ PutInteractionDelay int `yaml:"put_interaction_delay"`
+ //onebot修改
+ TwoWayEcho bool `yaml:"twoway_echo"`
+ Array bool `yaml:"array"`
+ NativeOb11 bool `yaml:"native_ob11"`
+ //url相关
+ VisibleIp bool `yaml:"visible_ip"`
+ UrlToQrimage bool `yaml:"url_to_qrimage"`
+ QrSize int `yaml:"qr_size"`
+ TransferUrl bool `yaml:"transfer_url"`
+ //框架修改
+ Title string `yaml:"title"`
+ FrpPort string `yaml:"frp_port"`
+ //MD相关
+ CustomTemplateID string `yaml:"custom_template_id"`
+ KeyBoardID string `yaml:"keyboard_id"`
+ //发送行为修改
+ LazyMessageId bool `yaml:"lazy_message_id"`
+ RamDomSeq bool `yaml:"ramdom_seq"`
+ BotForumTitle string `yaml:"bot_forum_title"`
+ AtoPCount int `yaml:"AMsgRetryAsPMsg_Count"`
+ SendDelay int `yaml:"send_delay"`
+ //错误临时修复类
+ Fix11300 bool `yaml:"fix_11300"`
+ //内置指令
+ BindPrefix string `yaml:"bind_prefix"`
+ MePrefix string `yaml:"me_prefix"`
+ UnlockPrefix string `yaml:"unlock_prefix"`
+ LinkPrefix string `yaml:"link_prefix"`
+ MusicPrefix string `yaml:"music_prefix"`
+ LinkBots []string `yaml:"link_bots"`
+ LinkText string `yaml:"link_text"`
+ LinkPic string `yaml:"link_pic"`
+ //HTTP API配置
+ HttpAddress string `yaml:"http_address"`
+ AccessToken string `yaml:"http_access_token"`
+ HttpVersion int `yaml:"http_version"`
+ HttpTimeOut int `yaml:"http_timeout"`
+ PostUrl []string `yaml:"post_url"`
+ PostSecret []string `yaml:"post_secret"`
+ PostMaxRetries []int `yaml:"post_max_retries"`
+ PostRetriesInterval []int `yaml:"post_retries_interval"`
+ //腾讯云
+ TencentBucketName string `yaml:"t_COS_BUCKETNAME"`
+ TencentBucketRegion string `yaml:"t_COS_REGION"`
+ TencentCosSecretid string `yaml:"t_COS_SECRETID"`
+ TencentSecretKey string `yaml:"t_COS_SECRETKEY"`
+ TencentAudit bool `yaml:"t_audit"`
+ //百度云
+ BaiduBOSBucketName string `yaml:"b_BOS_BUCKETNAME"`
+ BaiduBCEAK string `yaml:"b_BCE_AK"`
+ BaiduBCESK string `yaml:"b_BCE_SK"`
+ BaiduAudit int `yaml:"b_audit"`
+ //阿里云
+ AliyunEndpoint string `yaml:"a_OSS_EndPoint"`
+ AliyunAccessKeyId string `yaml:"a_OSS_AccessKeyId"`
+ AliyunAccessKeySecret string `yaml:"a_OSS_AccessKeySecret"`
+ AliyunBucketName string `yaml:"a_OSS_BucketName"`
+ AliyunAudit bool `yaml:"a_audit"`
+}
+
+// CommentInfo 用于存储注释及其定位信息
+type CommentBlock struct {
+ Comments []string // 一个或多个连续的注释
+ TargetKey string // 注释所指向的键(如果有)
+ Offset int // 注释与目标键之间的行数
}
// LoadConfig 从文件中加载配置并初始化单例配置
@@ -204,6 +239,169 @@ func LoadConfig(path string) (*Config, error) {
return instance, nil
}
+func CreateAndWriteConfigTemp() error {
+ // 读取config.yml
+ configFile, err := os.ReadFile("config.yml")
+ if err != nil {
+ return err
+ }
+
+ // 获取当前日期
+ currentDate := time.Now().Format("2006-1-2")
+ // 重命名原始config.yml文件
+ err = os.Rename("config.yml", "config"+currentDate+".yml")
+ if err != nil {
+ return err
+ }
+
+ var config Config
+ err = yaml.Unmarshal(configFile, &config)
+ if err != nil {
+ return err
+ }
+
+ // 创建config_temp.yml文件
+ tempFile, err := os.Create("config.yml")
+ if err != nil {
+ return err
+ }
+ defer tempFile.Close()
+
+ // 使用yaml.Encoder写入,以保留注释
+ encoder := yaml.NewEncoder(tempFile)
+ encoder.SetIndent(2) // 设置缩进
+ err = encoder.Encode(config)
+ if err != nil {
+ return err
+ }
+
+ // 处理注释并重命名文件
+ err = addCommentsToConfigTemp(template.ConfigTemplate, "config.yml")
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func parseTemplate(template string) ([]CommentBlock, map[string]string) {
+ var blocks []CommentBlock
+ lines := strings.Split(template, "\n")
+
+ var currentBlock CommentBlock
+ var lastKey string
+
+ directComments := make(map[string]string)
+
+ for _, line := range lines {
+ trimmed := strings.TrimSpace(line)
+ if strings.HasPrefix(trimmed, "#") {
+ currentBlock.Comments = append(currentBlock.Comments, trimmed) // 收集注释行
+ } else {
+ if containsKey(trimmed) {
+ key := strings.SplitN(trimmed, ":", 2)[0]
+ trimmedKey := strings.TrimSpace(key)
+
+ if len(currentBlock.Comments) > 0 {
+ currentBlock.TargetKey = lastKey // 关联到上一个找到的键
+ blocks = append(blocks, currentBlock)
+ currentBlock = CommentBlock{} // 重置为新的注释块
+ }
+
+ // 如果当前行包含注释,则单独处理
+ if parts := strings.SplitN(trimmed, "#", 2); len(parts) > 1 {
+ directComments[trimmedKey] = "#" + parts[1]
+ }
+ lastKey = trimmedKey // 更新最后一个键
+ } else if len(currentBlock.Comments) > 0 {
+ // 如果当前行不是注释行且存在挂起的注释,但并没有新的键出现,将其作为独立的注释块
+ blocks = append(blocks, currentBlock)
+ currentBlock = CommentBlock{} // 重置为新的注释块
+ }
+ }
+ }
+
+ // 处理文件末尾的挂起注释块
+ if len(currentBlock.Comments) > 0 {
+ blocks = append(blocks, currentBlock)
+ }
+
+ return blocks, directComments
+}
+
+func addCommentsToConfigTemp(template, tempFilePath string) error {
+ commentBlocks, directComments := parseTemplate(template)
+ //fmt.Printf("%v\n", directComments)
+
+ // 读取并分割新生成的配置文件内容
+ content, err := os.ReadFile(tempFilePath)
+ if err != nil {
+ return err
+ }
+ lines := strings.Split(string(content), "\n")
+
+ // 处理并插入注释
+ for _, block := range commentBlocks {
+ // 根据注释块的目标键,找到插入位置并插入注释
+ for i, line := range lines {
+ if containsKey(line) {
+ key := strings.SplitN(line, ":", 2)[0]
+ if strings.TrimSpace(key) == block.TargetKey {
+ // 在目标键之前插入注释
+ insertionPoint := i + block.Offset
+ if insertionPoint >= len(lines) {
+ lines = append(lines, block.Comments...)
+ } else {
+ lines = append(lines[:insertionPoint], append(block.Comments, lines[insertionPoint:]...)...)
+ }
+ break
+ }
+ }
+ }
+ }
+
+ // 处理直接跟在键后面的注释
+ // 接着处理直接跟在键后面的注释
+ for i, line := range lines {
+ if containsKey(line) {
+ key := strings.SplitN(line, ":", 2)[0]
+ trimmedKey := strings.TrimSpace(key)
+ //fmt.Printf("%v\n", trimmedKey)
+ if comment, exists := directComments[trimmedKey]; exists {
+ // 如果这个键有直接的注释
+ lines[i] = line + " " + comment
+ }
+ }
+ }
+
+ // 重新组合lines为一个字符串,准备写回文件
+ updatedContent := strings.Join(lines, "\n")
+
+ // 写回更新后的内容到原配置文件
+ err = os.WriteFile(tempFilePath, []byte(updatedContent), 0644)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// containsKey 检查给定的字符串行是否可能包含YAML键。
+// 它尝试排除注释行和冒号用于其他目的的行(例如,在URLs中)。
+func containsKey(line string) bool {
+ // 去除行首和行尾的空格
+ trimmedLine := strings.TrimSpace(line)
+
+ // 如果行是注释,直接返回false
+ if strings.HasPrefix(trimmedLine, "#") {
+ return false
+ }
+
+ // 检查是否存在冒号,如果不存在,则直接返回false
+ colonIndex := strings.Index(trimmedLine, ":")
+ return colonIndex != -1
+}
+
// 确保配置完整性
func ensureConfigComplete(path string) error {
// 读取配置文件到缓冲区
@@ -1998,3 +2196,15 @@ func GetServerTempQQguildPool() []string {
}
return nil // 返回nil,如果instance为nil
}
+
+// 获取UploadPicV2Base64开关
+func GetUploadPicV2Base64() bool {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to UploadPicV2 value.")
+ return false
+ }
+ return instance.Settings.UploadPicV2Base64
+}
diff --git a/images/upload_api.go b/images/upload_api.go
index f70bff01..8287f3fc 100644
--- a/images/upload_api.go
+++ b/images/upload_api.go
@@ -73,26 +73,27 @@ func UploadBase64ImageToServer(msgid string, base64Image string, groupID string,
return downloadURL, 0, width, height, nil
}
- extraPicAuditingType := config.GetOssType()
-
- switch extraPicAuditingType {
- case 0:
- picURL, err = originalUploadBehavior(base64Image)
- case 1:
- picURL, err = oss.UploadAndAuditImage(base64Image) // 腾讯
- case 2:
- picURL, err = oss.UploadAndAuditImageB(base64Image) // 百度
- case 3:
- picURL, err = oss.UploadAndAuditImageA(base64Image) // 阿里
- default:
- return "", 0, 0, 0, errors.New("invalid extraPicAuditingType")
- }
- if err != nil {
- return "", 0, 0, 0, err
+ //v2接口是否使用base64
+ if !config.GetUploadPicV2Base64() {
+ extraPicAuditingType := config.GetOssType()
+ switch extraPicAuditingType {
+ case 0:
+ picURL, err = originalUploadBehavior(base64Image)
+ case 1:
+ picURL, err = oss.UploadAndAuditImage(base64Image) // 腾讯
+ case 2:
+ picURL, err = oss.UploadAndAuditImageB(base64Image) // 百度
+ case 3:
+ picURL, err = oss.UploadAndAuditImageA(base64Image) // 阿里
+ default:
+ return "", 0, 0, 0, errors.New("invalid extraPicAuditingType")
+ }
+ if err != nil {
+ return "", 0, 0, 0, err
+ }
}
if config.GetImgUpApiVtv2() && groupID != "" {
-
if msgid == "" {
msgid = echo.GetLazyMessagesId(groupID)
}
@@ -109,13 +110,25 @@ func UploadBase64ImageToServer(msgid string, base64Image string, groupID string,
// 用originalGroupID更新groupID
groupID = originalGroupID
}
- richMediaMessage := &dto.RichMediaMessage{
- EventID: msgid,
- FileType: 1, // 1代表图片
- URL: picURL,
- Content: "", // 这个字段文档没有了
- SrvSendMsg: false,
+ var richMediaMessage *dto.RichMediaMessage
+ if !config.GetUploadPicV2Base64() {
+ richMediaMessage = &dto.RichMediaMessage{
+ EventID: msgid,
+ FileType: 1, // 1代表图片
+ URL: picURL,
+ Content: "", // 这个字段文档没有了
+ SrvSendMsg: false,
+ }
+ } else {
+ richMediaMessage = &dto.RichMediaMessage{
+ EventID: msgid,
+ FileType: 1, // 1代表图片
+ FileData: base64Image,
+ Content: "", // 这个字段文档没有了
+ SrvSendMsg: false,
+ }
}
+
var fileInfo string
//尝试群聊发图
fileInfo, err = uploadMedia(context.TODO(), groupID, richMediaMessage, apiv2)
@@ -146,6 +159,7 @@ func UploadBase64ImageToServer(msgid string, base64Image string, groupID string,
// 从Proto消息中读取值
realGroupID := mainMessage.GetA().GetB().GetInfo().GetDetail().GetGroupInfo().GetGroupNumber()
downloadURL := mainMessage.GetA().GetImageData().GetImageInfo().GetUrl()
+ downloadURL = "https://multimedia.nt.qq.com.cn" + downloadURL
width := mainMessage.GetA().GetImageData().GetWidth()
height := mainMessage.GetA().GetImageData().GetHeight()
diff --git a/main.go b/main.go
index cf690003..6dd281e0 100644
--- a/main.go
+++ b/main.go
@@ -44,6 +44,7 @@ var p *Processor.Processors
func main() {
// 定义faststart命令行标志。默认为false。
fastStart := flag.Bool("faststart", false, "start without initialization if set")
+ tidy := flag.Bool("tidy", false, "backup and tidy your config.yml")
// 解析命令行参数到定义的标志。
flag.Parse()
@@ -52,6 +53,12 @@ func main() {
if !*fastStart {
sys.InitBase() // 如果不是faststart模式,则执行初始化
}
+ if *tidy {
+ //备份配置 并刷新
+ config.CreateAndWriteConfigTemp()
+ log.Println("配置文件已更新为新版,当前配置文件已备份.如产生问题请到群196173384反馈开发者。")
+ return
+ }
if _, err := os.Stat("config.yml"); os.IsNotExist(err) {
var ip string
var err error
diff --git a/template/config_template.go b/template/config_template.go
index 92fa87d6..76c9fc7f 100644
--- a/template/config_template.go
+++ b/template/config_template.go
@@ -6,11 +6,19 @@ settings:
#反向ws设置
ws_address: ["ws://:"] # WebSocket服务的地址 支持多个["","",""]
ws_token: ["","",""] #连接wss地址时服务器所需的token,按顺序一一对应,如果是ws地址,没有密钥,请留空.
+ reconnect_times : 100 #反向ws连接失败后的重试次数,希望一直重试,可设置9999
+ heart_beat_interval : 10 #反向ws心跳间隔 单位秒 推荐5-10
+ launch_reconnect_times : 1 #启动时尝试反向ws连接次数,建议先打开应用端再开启gensokyo,因为启动时连接会阻塞webui启动,默认只连接一次,可自行增大
+
+ #基础设置
app_id: 12345 # 你的应用ID
uin : 0 # 你的机器人QQ号,点击机器人资料卡查看
token: "" # 你的应用令牌
client_secret: "" # 你的客户端密钥
+ shard_count: 1 #分片数量 默认1
+ shard_id: 0 #当前分片id 默认从0开始,详细请看 https://bot.q.qq.com/wiki/develop/api/gateway/reference.html
+ #事件订阅
text_intent: # 请根据公域 私域来选择intent,错误的intent将连接失败
- "ATMessageEventHandler" # 频道at信息
- "DirectMessageHandler" # 私域频道私信(dms)
@@ -25,71 +33,63 @@ settings:
# - "C2CMessageEventHandler" # 群私聊 仅频道机器人时候需要注释
# - "ThreadEventHandler" # 频道发帖事件 仅频道私域机器人可用
-
+ #转换类
global_channel_to_group: true # 是否将频道转换成群 默认true
global_private_to_channel: false # 是否将私聊转换成频道 如果是群场景 会将私聊转为群(方便提审\测试)
global_forum_to_channel: false # 是否将频道帖子信息转化为频道 子频道信息 如果开启global_channel_to_group会进一步转换为群信息
global_interaction_to_message : false # 是否将按钮和表态回调转化为消息 仅在设置了按钮回调中的message时有效
- bot_forum_title : "机器人帖子" # 机器人发帖子回复默认标题
- array: false # 连接trss云崽请开启array
hash_id : false # 使用hash来进行idmaps转换,可以让user_id不是123开始的递增值
+ idmap_pro : false #需开启hash_id配合,高级id转换增强,可以多个真实值bind到同一个虚拟值,对于每个用户,每个群\私聊\判断私聊\频道,都会产生新的虚拟值,但可以多次bind,bind到同一个数字.数据库负担会变大.
- server_dir: "" # 提供图片上传服务的服务器(图床)需要带端口号. 如果需要发base64图,需为公网ip,且开放对应端口
- port: "15630" # idmaps和图床对外开放的端口号
+ #Gensokyo互联类
+ server_dir: "" # Lotus地址.不带http头的域名或ip,提供图片上传服务的服务器(图床)需要带端口号. 如果需要发base64图,需为公网ip,且开放对应端口
+ port: "15630" # Lotus端口.idmaps和图床对外开放的端口号,若要连接到另一个gensokyo,也是链接端口
backup_port : "5200" # 当totus为ture时,port值不再是本地webui的端口,使用lotus_Port来访问webui
-
- lotus: false # lotus特性默认为false,当为true时,将会连接到另一个lotus为false的gensokyo。
- # 使用它提供的图床和idmaps服务(场景:同一个机器人在不同服务器运行,或内网需要发送base64图)。
- # 如果需要发送base64图片,需要设置正确的公网server_dir和开放对应的port
- lotus_password : "" # lotus鉴权 设置后,从gsk需要保持相同密码来访问主gsk
+ lotus: false # lotus特性默认为false,当为true时,将会连接到另一个lotus为false的gensokyo。使用它提供的图床和idmaps服务(场景:同一个机器人在不同服务器运行,或内网需要发送base64图)。如果需要发送base64图片,需要设置正确的公网server_dir和开放对应的port, lotus鉴权 设置后,从gsk需要保持相同密码来访问主gsk
+ lotus_password : ""
+ lotus_without_idmaps: false #lotus只通过url,图片上传,语音,不通过id转换,在本地当前gsk维护idmaps转换.
#增强配置项
-
- image_sizelimit : 0 #代表kb 腾讯api要求图片1500ms完成传输 如果图片发不出 请提升上行或设置此值 默认为0 不压缩
- image_limit : 100 #每分钟上传的最大图片数量,可自行增加
master_id : ["1","2"] #群场景尚未开放获取管理员和列表能力,手动从日志中获取需要设置为管理,的user_id并填入(适用插件有权限判断场景)
record_sampleRate : 24000 #语音文件的采样率 最高48000 默认24000 单位Khz
record_bitRate : 24000 #语音文件的比特率 默认25000 代表 25 kbps 最高无限 请根据带宽 您发送的实际码率调整
card_nick : "" #默认为空,连接mirai-overflow时,请设置为非空,这里是机器人对用户称谓,为空为插件获取,mirai不支持
auto_bind : true #测试功能,后期会移除
- AMsgRetryAsPMsg_Count : 30 #当主动信息发送失败时,自动转为后续的被动信息发送,需要开启Lazy message id,该配置项为所有群、频道的主动转被动消息队列最大长度,建议30-100,无上限
- reconnect_times : 100 #反向ws连接失败后的重试次数,希望一直重试,可设置9999
- heart_beat_interval : 10 #反向ws心跳间隔 单位秒 推荐5-10
- launch_reconnect_times : 1 #启动时尝试反向ws连接次数,建议先打开应用端再开启gensokyo,因为启动时连接会阻塞webui启动,默认只连接一次,可自行增大
- native_ob11 : false #如果你的机器人收到事件报错,请开启此选项增加兼容性
- ramdom_seq : false #当多开gensokyo时,如果遇到群信息只能发出一条,请开启每个gsk的此项.(建议使用一个gsk连接多个应用)
- url_to_qrimage : false #将信息中的url转换为二维码单独作为图片发出,需要同时设置 #SSL配置类 机器人发送URL设置 的 transfer_url 为 true visible_ip也需要为true
- qr_size : 200 #二维码尺寸,单位像素
- guild_url_image_to_base64 : false #解决频道发不了某些url图片,报错40003问题
+
+ #发图相关
oss_type : 0 #请完善后方具体配置 完成#腾讯云配置...,0代表配置server dir port服务器自行上传(省钱),1,腾讯cos存储桶 2,百度oss存储桶 3,阿里oss存储桶
- self_introduce : ["",""] #自我介绍,可设置多个随机发送,当不为空时,机器人被邀入群会发送自定义自我介绍 需手动添加新textintent - "GroupAddRobotEventHandler" - "GroupDelRobotEventHandler"
+ image_sizelimit : 0 #代表kb 腾讯api要求图片1500ms完成传输 如果图片发不出 请提升上行或设置此值 默认为0 不压缩
+ image_limit : 100 #每分钟上传的最大图片数量,可自行增加
+ guild_url_image_to_base64 : false #解决频道发不了某些url图片,报错40003问题
+ url_pic_transfer : false #把图片url(任意来源图链)变成你备案的白名单url 需要较高上下行+ssl+自备案域名+设置白名单域名(暂时不需要)
+ img_up_api_ntv2: false #gsk内建图片上传api 开启后全局有效 是否将图片转换为ntqq图床url(md发图用,自行调用)文档:https://www.yuque.com/km57bt/hlhnxg/ig2nk88fccykn6dm
+ uploadpicv2_b64: true #uploadpicv2接口使用base64直接上传 https://www.yuque.com/km57bt/hlhnxg/ig2nk88fccykn6dm
+ global_server_temp_qqguild : false #需设置server_temp_qqguild,公域私域均可用,以频道为底层发图,速度快,该接口为进阶接口,使用有一定难度.
+ server_temp_qqguild : "0" #在v3图片接口采用固定的子频道号,可以是帖子子频道 https://www.yuque.com/km57bt/hlhnxg/uqmnsno3vx1ytp2q
+ server_temp_qqguild_pool : [] #填写v3发图接口的endpoint http://127.0.0.1:12345/uploadpicv3 当填写多个时采用循环方式负载均衡,注,不包括自身,如需要自身也要填写
#正向ws设置
ws_server_path : "ws" #默认监听0.0.0.0:port/ws_server_path 若有安全需求,可不放通port到公网,或设置ws_server_token 若想监听/ 可改为"",若想监听到不带/地址请写nil
enable_ws_server: true #是否启用正向ws服务器 监听server_dir:port/ws_server_path
ws_server_token : "12345" #正向ws的token 不启动正向ws可忽略 可为空
- #SSL配置类 机器人发送URL设置
-
+ #SSL配置类 和 白名单域名自动验证
identify_file : true #自动生成域名校验文件,在q.qq.com配置信息URL,在server_dir填入自己已备案域名,正确解析到机器人所在服务器ip地址,机器人即可发送链接
identify_appids : [] #默认不需要设置,完成SSL配置类+server_dir设置为域名+完成备案+ssl全套设置后,若有多个机器人需要过域名校验(自己名下)可设置,格式为,整数appid,组成的数组
crt : "" #证书路径 从你的域名服务商或云服务商申请签发SSL证书(qq要求SSL)
key : "" #密钥路径 Apache(crt文件、key文件)示例: "C:\\123.key" \需要双写成\\
- transfer_url : true #默认开启,关闭后自理url发送,配置server_dir为你的域名,配置crt和key后,将域名/url和/image在q.qq.com后台通过校验,自动使用302跳转处理机器人发出的所有域名.
-
+
#日志类
-
developer_log : false #开启开发者日志 默认关闭
log_level : 1 # 0=debug 1=info 2=warning 3=error 默认1
save_logs : false #自动储存日志
#webui设置
-
+ disable_webui: false #禁用webui
server_user_name : "useradmin" #默认网页面板用户名
server_user_password : "admin" #默认网页面板密码
- #指令过滤类
-
+ #指令魔法类
remove_prefix : false #是否忽略公域机器人指令前第一个/
remove_at : false #是否忽略公域机器人指令前第一个[CQ:aq,qq=机器人] 场景(公域机器人,但插件未适配at开头)
remove_bot_at_group : true #因为群聊机器人不支持发at,开启本开关会自动隐藏群机器人发出的at(不影响频道场景)
@@ -120,48 +120,59 @@ settings:
No_White_Response : ""
#开发增强类
-
develop_access_token_dir : "" #开发者测试环境access_token自定义获取地址 默认留空 请留空忽略
develop_bot_id : "1234" #开发者环境需自行获取botid 填入 用户请不要设置这两行...开发者调试用
sandbox_mode : false #默认false 如果你只希望沙箱频道使用,请改为true
dev_message_id : false #在沙盒和测试环境使用无限制msg_id 仅沙盒有效,正式环境请关闭,内测结束后,tx侧未来会移除
send_error : true #将报错用文本发出,避免机器人被审核报无响应
- url_pic_transfer : false #把图片url(任意来源图链)变成你备案的白名单url 需要较高上下行+ssl+自备案域名+设置白名单域名(暂时不需要)
- idmap_pro : false #需开启hash_id配合,高级id转换增强,可以多个真实值bind到同一个虚拟值,对于每个用户,每个群\私聊\判断私聊\频道,都会产生新的虚拟值,但可以多次bind,bind到同一个数字.数据库负担会变大.
- send_delay : 300 #单位 毫秒 默认300ms 可以视情况减少到100或者50
- disable_webui: false #禁用webui
- shard_count: 1 #分片数量 默认1
- shard_id: 0 #当前分片id 默认从0开始,详细请看 https://bot.q.qq.com/wiki/develop/api/gateway/reference.html
- auto_put_interaction : false #自动回应按钮回调的/interactions/{interaction_id} 注本api需要邮件申请,详细方法参考群公告:196173384
- put_interaction_delay : 0 #单位毫秒 表示回应已收到回调类型的按钮的毫秒数 会按用户进行区分 非全局delay
- img_up_api_ntv2: false #gsk内建图片上传api 是否将图片转换为ntqq图床url(md发图用,自行调用)文档:https://www.yuque.com/km57bt/hlhnxg/ig2nk88fccykn6dm
- fix_11300: false #修复11300报错,需要在develop_bot_id填入自己机器人的appid. 11300原因暂时未知,临时修复方案.
- lotus_without_idmaps: false #lotus只通过url,图片上传,语音,不通过id转换,在本地当前gsk维护idmaps转换.
+ #增长营销类(推荐gensokyo-broadcast项目)
+ self_introduce : ["",""] #自我介绍,可设置多个随机发送,当不为空时,机器人被邀入群会发送自定义自我介绍 需手动添加新textintent - "GroupAddRobotEventHandler" - "GroupDelRobotEventHandler"
+
+
+ #API修改
get_g_list_all_guilds : false #在获取群列表api时,轮询获取全部的频道列表(api一次只能获取100个),建议仅在广播公告通知等特别场景时开启.
get_g_list_delay : 500 #轮询时的延迟时间,毫秒数.
get_g_list_guilds_type : 0 #0=全部返回,1=获取第1个子频道.以此类推.可以缩减返回值的大小.
get_g_list_guilds : "10" #在获取群列表api时,一次返回的频道数量.这里是string,不要去掉引号.最大100(5分钟内连续请求=翻页),获取全部请开启get_g_list_return_guilds.
get_g_list_return_guilds : true #获取群列表时是否返回频道列表.
+ forward_msg_limit : 3 #发送折叠转发信息时的最大限制条数 若要发转发信息 请设置lazy_message_id为true
+ custom_bot_name : "Gensokyo全域机器人" #自定义api返回的机器人名字,会在api调用中返回,默认Gensokyo全域机器人
+ transform_api_ids : true #对get_group_menmber_list\get_group_member_info\get_group_list生效,是否在其中返回转换后的值(默认转换,不转换请自行处理插件逻辑,比如调用gsk的http api转换)
+ auto_put_interaction : false #自动回应按钮回调的/interactions/{interaction_id} 注本api需要邮件申请,详细方法参考群公告:196173384
+ put_interaction_delay : 0 #单位毫秒 表示回应已收到回调类型的按钮的毫秒数 会按用户进行区分 非全局delay
- global_server_temp_qqguild : false #需设置server_temp_qqguild,公域私域均可用,以频道为底层发图,速度快,该接口为进阶接口,使用有一定难度.
- server_temp_qqguild : "0" #在v3图片接口采用固定的子频道号,可以是帖子子频道 https://www.yuque.com/km57bt/hlhnxg/uqmnsno3vx1ytp2q
- server_temp_qqguild_pool : [] #填写v3发图接口的endpoint http://127.0.0.1:12345/uploadpicv3 当填写多个时采用循环方式负载均衡,注,不包括自身,如需要自身也要填写
+ #Onebot修改
+ twoway_echo : false #是否采用双向echo,根据机器人选择,獭獭\早苗 true 红色问答\椛椛 或者其他 请使用 false
+ array: false # 连接trss云崽请开启array
+ native_ob11 : false #如果你的机器人收到事件报错,请开启此选项增加兼容性
+ #URL相关
+ visible_ip : false #转换url时,如果server_dir是ip true将以ip形式发出url 默认隐藏url 将server_dir配置为自己域名可以转换url
+ url_to_qrimage : false #将信息中的url转换为二维码单独作为图片发出,需要同时设置 #SSL配置类 机器人发送URL设置 的 transfer_url 为 true visible_ip也需要为true
+ qr_size : 200 #二维码尺寸,单位像素
+ transfer_url : true #默认开启,关闭后自理url发送,配置server_dir为你的域名,配置crt和key后,将域名/url和/image在q.qq.com后台通过校验,自动使用302跳转处理机器人发出的所有域名.
+
+ #框架修改
title : "Gensokyo © 2023 - Hoshinonyaruko" #程序的标题 如果多个机器人 可根据标题区分
- custom_bot_name : "Gensokyo全域机器人" #自定义机器人名字,会在api调用中返回,默认Gensokyo全域机器人
+ frp_port : "0" #不使用请保持为0,frp的端口,frp有内外端口,请在frp软件设置gensokyo的port,并将frp显示的对外端口填入这里
- twoway_echo : false #是否采用双向echo,根据机器人选择,獭獭\早苗 true 红色问答\椛椛 或者其他 请使用 false
+ #MD相关
custom_template_id : "" #自动转换图文信息到md所需要的id *需要应用端支持双方向echo
keyboard_id : "" #自动转换图文信息到md所需要的按钮id *需要应用端支持双方向echo
- lazy_message_id : false #false=message_id 条条准确对应 true=message_id 按时间范围随机对应(适合主动推送bot)前提,有足够多的活跃信息刷新id池
-
- visible_ip : false #转换url时,如果server_dir是ip true将以ip形式发出url 默认隐藏url 将server_dir配置为自己域名可以转换url
- forward_msg_limit : 3 #发送折叠转发信息时的最大限制条数 若要发转发信息 请设置lazy_message_id为true
- transform_api_ids : true #对get_group_menmber_list\get_group_member_info\get_group_list生效,是否在其中返回转换后的值(默认转换,不转换请自行处理插件逻辑,比如调用gsk的http api转换)
- #bind指令类
+ #发送行为修改
+ lazy_message_id : false #false=message_id 条条准确对应 true=message_id 按时间范围随机对应(适合主动推送bot)前提,有足够多的活跃信息刷新id池
+ ramdom_seq : false #当多开gensokyo时,如果遇到群信息只能发出一条,请开启每个gsk的此项.(建议使用一个gsk连接多个应用)
+ bot_forum_title : "机器人帖子" # 机器人发帖子回复默认标题
+ AMsgRetryAsPMsg_Count : 30 #当主动信息发送失败时,自动转为后续的被动信息发送,需要开启Lazy message id,该配置项为所有群、频道的主动转被动消息队列最大长度,建议30-100,无上限
+ send_delay : 300 #单位 毫秒 默认300ms 可以视情况减少到100或者50
+
+ #错误临时修复类
+ fix_11300: false #修复11300报错,需要在develop_bot_id填入自己机器人的appid. 11300原因暂时未知,临时修复方案.
+
+ #内置指令类
bind_prefix : "/bind" #需设置 #增强配置项 master_id 可触发
me_prefix : "/me" #需设置 #增强配置项 master_id 可触发
unlock_prefix : "/unlock" #频道私信卡住了? gsk可以帮到你 在任意子频道发送unlock 你会收到来自机器人的频道私信
@@ -171,18 +182,13 @@ settings:
link_text : "" #友情链接文本 不可为空!
link_pic : "" #友情链接图片 可为空 需url图片 可带端口 不填可能会有显示错误
- #穿透\cos\oss类配置(可选!)
- frp_port : "0" #不使用请保持为0,frp的端口,frp有内外端口,请在frp软件设置gensokyo的port,并将frp显示的对外端口填入这里
-
- #HTTP API配置
-
- #正向http
+ #HTTP API配置-正向http
http_address: "" #http监听地址 与websocket独立 示例:0.0.0.0:5700 为空代表不开启
http_access_token: "" #http访问令牌
http_version : 11 #暂时只支持11
http_timeout: 5 #反向 HTTP 超时时间, 单位秒,<5 时将被忽略
- #反向http
+ #HTTP API配置-反向http
post_url: [""] #反向HTTP POST地址列表 为空代表不开启 示例:http://192.168.0.100:5789
post_secret: [""] #密钥
post_max_retries: [3] #最大重试,0 时禁用
From 8a8304532710c10bc77ca25d766da9fa5ce82289 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Sun, 24 Mar 2024 18:24:17 +0800
Subject: [PATCH 15/33] beta350
---
config/config.go | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/config/config.go b/config/config.go
index a5a6bf91..c33f3a3b 100644
--- a/config/config.go
+++ b/config/config.go
@@ -34,7 +34,7 @@ type VisualPrefixConfig struct {
type Settings struct {
//反向ws设置
WsAddress []string `yaml:"ws_address"`
- WsToken []string `yaml:"ws_token,omitempty"`
+ WsToken []string `yaml:"ws_token"`
ReconnecTimes int `yaml:"reconnect_times"`
HeartBeatInterval int `yaml:"heart_beat_interval"`
LaunchReconectTimes int `yaml:"launch_reconnect_times"`
@@ -62,7 +62,7 @@ type Settings struct {
LotusPassword string `yaml:"lotus_password"`
LotusWithoutIdmaps bool `yaml:"lotus_without_idmaps"`
//增强配置
- MasterID []string `yaml:"master_id,omitempty"`
+ MasterID []string `yaml:"master_id"`
RecordSampleRate int `yaml:"record_sampleRate"`
RecordBitRate int `yaml:"record_bitRate"`
CardAndNick string `yaml:"card_nick"`
@@ -80,8 +80,8 @@ type Settings struct {
ServerTempQQguildPool []string `yaml:"server_temp_qqguild_pool"`
//正向ws设置
WsServerPath string `yaml:"ws_server_path"`
- EnableWsServer bool `yaml:"enable_ws_server,omitempty"`
- WsServerToken string `yaml:"ws_server_token,omitempty"`
+ EnableWsServer bool `yaml:"enable_ws_server"`
+ WsServerToken string `yaml:"ws_server_token"`
//ssl和链接转换类
IdentifyFile bool `yaml:"identify_file"`
IdentifyAppids []int64 `yaml:"identify_appids"`
From 0eb64d67cdd26d00b48bdb5d21be8209291e0f93 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Sun, 24 Mar 2024 19:46:09 +0800
Subject: [PATCH 16/33] beta351
---
images/upload_api.go | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/images/upload_api.go b/images/upload_api.go
index 8287f3fc..35608fa3 100644
--- a/images/upload_api.go
+++ b/images/upload_api.go
@@ -12,6 +12,7 @@ import (
"net/http"
"net/url"
"regexp"
+ "strconv"
"strings"
"sync"
@@ -94,10 +95,12 @@ func UploadBase64ImageToServer(msgid string, base64Image string, groupID string,
}
if config.GetImgUpApiVtv2() && groupID != "" {
- if msgid == "" {
- msgid = echo.GetLazyMessagesId(groupID)
- }
+
if isNumeric(groupID) {
+ //用转换前的群号获取msgid
+ if msgid == "" {
+ msgid = echo.GetLazyMessagesId(groupID)
+ }
// 检查groupID是否为纯数字构成 RetrieveRowByIDv2是通用逻辑,也可以将userid还原为32位数originaluserid
// 但没有私信权限,故没有测试
originalGroupID, err := idmap.RetrieveRowByIDv2(groupID)
@@ -109,6 +112,18 @@ func UploadBase64ImageToServer(msgid string, base64Image string, groupID string,
// 用originalGroupID更新groupID
groupID = originalGroupID
+ } else {
+ // 映射str的GroupID到int
+ GroupID64, err := idmap.StoreIDv2(groupID)
+ if err != nil {
+ log.Printf("failed to convert ChannelID to int: %v", err)
+ return picURL, 0, 0, 0, nil
+ }
+ groupIDTemp := strconv.FormatInt(GroupID64, 10)
+ //用数字的群号获取msgid
+ if msgid == "" {
+ msgid = echo.GetLazyMessagesId(groupIDTemp)
+ }
}
var richMediaMessage *dto.RichMediaMessage
if !config.GetUploadPicV2Base64() {
From 123be98de0f2fd1a02730b0f2e4df69c2968c602 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Sun, 24 Mar 2024 20:39:57 +0800
Subject: [PATCH 17/33] beta352
---
images/upload_api.go | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/images/upload_api.go b/images/upload_api.go
index 35608fa3..6c5a983e 100644
--- a/images/upload_api.go
+++ b/images/upload_api.go
@@ -174,7 +174,11 @@ func UploadBase64ImageToServer(msgid string, base64Image string, groupID string,
// 从Proto消息中读取值
realGroupID := mainMessage.GetA().GetB().GetInfo().GetDetail().GetGroupInfo().GetGroupNumber()
downloadURL := mainMessage.GetA().GetImageData().GetImageInfo().GetUrl()
- downloadURL = "https://multimedia.nt.qq.com.cn" + downloadURL
+ //https的地址不能放到md里
+ //downloadURL = "https://multimedia.nt.qq.com.cn" + downloadURL
+ // 将 downloadURL 中的所有下划线 "_" 替换为 "%5f"
+ downloadURL = strings.Replace(downloadURL, "_", "%5f", -1)
+ downloadURL = "http://multimedia.nt.qq.com" + downloadURL
width := mainMessage.GetA().GetImageData().GetWidth()
height := mainMessage.GetA().GetImageData().GetHeight()
From 33611e15ac6486ae42255d3969a144fb728a9265 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Mon, 25 Mar 2024 13:41:10 +0800
Subject: [PATCH 18/33] beta353
---
config/config.go | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/config/config.go b/config/config.go
index c33f3a3b..d10feda5 100644
--- a/config/config.go
+++ b/config/config.go
@@ -347,11 +347,19 @@ func addCommentsToConfigTemp(template, tempFilePath string) error {
if containsKey(line) {
key := strings.SplitN(line, ":", 2)[0]
if strings.TrimSpace(key) == block.TargetKey {
- // 在目标键之前插入注释
- insertionPoint := i + block.Offset
+ // 计算基本插入点:在目标键之后
+ insertionPoint := i + block.Offset + 1
+
+ // 向下移动插入点直到找到键行或到达文件末尾
+ for insertionPoint < len(lines) && !containsKey(lines[insertionPoint]) {
+ insertionPoint++
+ }
+
+ // 在计算出的插入点插入注释
if insertionPoint >= len(lines) {
- lines = append(lines, block.Comments...)
+ lines = append(lines, block.Comments...) // 如果到达文件末尾,直接追加注释
} else {
+ // 插入注释到计算出的位置
lines = append(lines[:insertionPoint], append(block.Comments, lines[insertionPoint:]...)...)
}
break
From 3d9d2b6dcbc5c9a05c11985e92c7b64fe2e5d781 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Mon, 25 Mar 2024 20:13:28 +0800
Subject: [PATCH 19/33] beta354
---
Processor/ProcessGroupMessage.go | 2 +-
Processor/Processor.go | 22 ++++++++++++----------
handlers/message_parser.go | 21 ++++++++++++++++-----
handlers/send_group_msg.go | 11 +++++++++++
idmap/service.go | 25 ++++++++++++-------------
5 files changed, 52 insertions(+), 29 deletions(-)
diff --git a/Processor/ProcessGroupMessage.go b/Processor/ProcessGroupMessage.go
index eee3eedd..4cacbfab 100644
--- a/Processor/ProcessGroupMessage.go
+++ b/Processor/ProcessGroupMessage.go
@@ -51,7 +51,7 @@ func (p *Processors) ProcessGroupMessage(data *dto.WSGroupATMessageData) error {
// 映射str的GroupID到int
GroupID64, err = idmap.StoreIDv2(data.GroupID)
if err != nil {
- mylog.Errorf("failed to convert ChannelID to int: %v", err)
+ mylog.Errorf("failed to convert GroupID64 to int: %v", err)
return nil
}
// 映射str的userid到int
diff --git a/Processor/Processor.go b/Processor/Processor.go
index 44f24d0d..297cffef 100644
--- a/Processor/Processor.go
+++ b/Processor/Processor.go
@@ -344,22 +344,24 @@ func (p *Processors) HandleFrameworkCommand(messageText string, data interface{}
// 获取MasterID数组
masterIDs := config.GetMasterID()
- // 根据realid获取new(用户id)
- now, new, err = idmap.RetrieveVirtualValuev2(realid)
- if err != nil {
- mylog.Printf("根据realid获取new(用户id) 错误:%v", err)
- }
- // 根据realid获取new(群id)
- nowgroup, newgroup, err = idmap.RetrieveVirtualValuev2(realid2)
- if err != nil {
- mylog.Printf("根据realid获取new(群id)错误:%v", err)
- }
+
// idmaps-pro获取群和用户id
if config.GetIdmapPro() {
newpro1, newpro2, err = idmap.RetrieveVirtualValuev2Pro(realid2, realid)
if err != nil {
mylog.Printf("idmaps-pro获取群和用户id 错误:%v", err)
}
+ } else {
+ // 根据realid获取new(用户id)
+ now, new, err = idmap.RetrieveVirtualValuev2(realid)
+ if err != nil {
+ mylog.Printf("根据realid获取new(用户id) 错误:%v", err)
+ }
+ // 根据realid获取new(群id)
+ nowgroup, newgroup, err = idmap.RetrieveVirtualValuev2(realid2)
+ if err != nil {
+ mylog.Printf("根据realid获取new(群id)错误:%v", err)
+ }
}
// 检查真实值或虚拟值是否在数组中
var realValueIncluded, virtualValueIncluded bool
diff --git a/handlers/message_parser.go b/handlers/message_parser.go
index 5b7d2e64..6d106509 100644
--- a/handlers/message_parser.go
+++ b/handlers/message_parser.go
@@ -67,12 +67,23 @@ func SendResponse(client callapi.Client, err error, message *callapi.ActionMessa
// Default ID handling
response.Data.MessageID = 123
}
- // 映射str的GroupID到int
- GroupID64, errr := idmap.StoreIDv2(message.Params.GroupID.(string))
- if errr != nil {
- mylog.Errorf("failed to convert ChannelID to int: %v", err)
- return "", nil
+
+ var errr error
+ var GroupID64 int64
+ if config.GetIdmapPro() {
+ //将真实id转为int userid64
+ GroupID64, _, errr = idmap.StoreIDv2Pro(message.Params.GroupID.(string), message.Params.UserID.(string))
+ if errr != nil {
+ mylog.Fatalf("Error storing ID: %v", err)
+ }
+ } else {
+ // 映射str的GroupID到int
+ GroupID64, err = idmap.StoreIDv2(message.Params.GroupID.(string))
+ if err != nil {
+ mylog.Errorf("failed to convert GroupID64 to int: %v", err)
+ }
}
+
response.GroupID = GroupID64
response.Echo = message.Echo
if err != nil {
diff --git a/handlers/send_group_msg.go b/handlers/send_group_msg.go
index 2cfb59e9..b7207fdc 100644
--- a/handlers/send_group_msg.go
+++ b/handlers/send_group_msg.go
@@ -1314,6 +1314,17 @@ func auto_md(message callapi.ActionMessage, messageText string, richMediaMessage
Type: 2, // 所有人可操作
}
}
+ case strings.HasPrefix(whiteLabel, "^"):
+ // 分割whiteLabel来获取显示内容和URL
+ parts := strings.SplitN(whiteLabel[1:], " ", 2) // [1:] 用于去除白名单标签开头的'^'
+ if len(parts) == 2 {
+ whiteLabel = parts[0] // 显示内容
+ actiondata = parts[1] // 发送给服务端内容
+ actiontype = 1 // 回调类型
+ permission = &keyboard.Permission{
+ Type: 2, // 所有人可操作
+ }
+ }
default:
actiontype = 2 //帮用户输入指令 用户自己回车发送
actiondata = dataLabel //从虚拟前缀的二级指令组合md按钮
diff --git a/idmap/service.go b/idmap/service.go
index 844486d0..d14e5f71 100644
--- a/idmap/service.go
+++ b/idmap/service.go
@@ -140,22 +140,21 @@ func StoreID(id string) (int64, error) {
} else {
// 生成新的行号
var err error
- newRow, err = GenerateRowID(id, 9)
- if err != nil {
- return err
- }
- // 检查新生成的行号是否重复
- rowKey := fmt.Sprintf("row-%d", newRow)
- if b.Get([]byte(rowKey)) != nil {
- // 如果行号重复,使用10位数字生成行号
- newRow, err = GenerateRowID(id, 10)
+ maxDigits := 18 // int64的位数上限-1
+ for digits := 9; digits <= maxDigits; digits++ {
+ newRow, err = GenerateRowID(id, digits)
if err != nil {
return err
}
- rowKey = fmt.Sprintf("row-%d", newRow)
- // 再次检查重复性,如果还是重复,则返回错误
- if b.Get([]byte(rowKey)) != nil {
- return fmt.Errorf("unable to find a unique row ID")
+ // 检查新生成的行号是否重复
+ rowKey := fmt.Sprintf("row-%d", newRow)
+ if b.Get([]byte(rowKey)) == nil {
+ // 找到了一个唯一的行号,可以跳出循环
+ break
+ }
+ // 如果到达了最大尝试次数还没有找到唯一的行号,则返回错误
+ if digits == maxDigits {
+ return fmt.Errorf("unable to find a unique row ID after %d attempts", maxDigits-8)
}
}
}
From b3a8b7ff1c25cbd8d3c61401660e51ece3a0fc98 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Mon, 25 Mar 2024 20:23:20 +0800
Subject: [PATCH 20/33] beta355
---
handlers/message_parser.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/handlers/message_parser.go b/handlers/message_parser.go
index 6d106509..20884de2 100644
--- a/handlers/message_parser.go
+++ b/handlers/message_parser.go
@@ -78,12 +78,12 @@ func SendResponse(client callapi.Client, err error, message *callapi.ActionMessa
}
} else {
// 映射str的GroupID到int
- GroupID64, err = idmap.StoreIDv2(message.Params.GroupID.(string))
- if err != nil {
+ GroupID64, errr = idmap.StoreIDv2(message.Params.GroupID.(string))
+ if errr != nil {
mylog.Errorf("failed to convert GroupID64 to int: %v", err)
}
}
-
+ //mylog.Printf("convert GroupID64 to int: %v", GroupID64) 测试
response.GroupID = GroupID64
response.Echo = message.Echo
if err != nil {
From 0adfd26fc41b5dccf67bc892bd0db0b14c5dd90f Mon Sep 17 00:00:00 2001
From: cosmo
Date: Sun, 31 Mar 2024 18:03:56 +0800
Subject: [PATCH 21/33] beta356
---
botgo/dto/message_create.go | 67 +++++++++
botgo/openapi/iface.go | 2 +
botgo/openapi/v1/message.go | 21 +++
botgo/openapi/v2/message.go | 21 +++
handlers/send_private_msg_sse.go | 229 +++++++++++++++++++++++++++++++
httpapi/httpapi.go | 53 +++++++
6 files changed, 393 insertions(+)
create mode 100644 handlers/send_private_msg_sse.go
diff --git a/botgo/dto/message_create.go b/botgo/dto/message_create.go
index 0107c976..554fabea 100644
--- a/botgo/dto/message_create.go
+++ b/botgo/dto/message_create.go
@@ -117,3 +117,70 @@ type SettingGuide struct {
// 频道ID, 当通过私信发送设置引导消息时,需要指定guild_id
GuildID string `json:"guild_id"`
}
+
+// 仅供测试
+
+type MessageSSE struct {
+ MsgType int `json:"msg_type,omitempty"`
+ Markdown *MarkdownSSE `json:"markdown,omitempty"`
+ MsgID string `json:"msg_id,omitempty"`
+ MsgSeq int `json:"msg_seq,omitempty"`
+ Stream *StreamSSE `json:"stream,omitempty"`
+ PromptKeyboard *KeyboardSSE `json:"prompt_keyboard,omitempty"`
+ ActionButton *ActionButtonSSE `json:"action_button,omitempty"`
+}
+
+// GetEventID 事件ID
+func (msg MessageSSE) GetEventID() string {
+ return ""
+}
+
+// GetSendType 消息类型
+func (msg MessageSSE) GetSendType() SendType {
+ return 1
+}
+
+type MarkdownSSE struct {
+ Content string `json:"content"`
+}
+
+type StreamSSE struct {
+ State int `json:"state"`
+ Index int `json:"index"`
+ ID string `json:"id,omitempty"`
+}
+
+type KeyboardSSE struct {
+ KeyboardContentSSE `json:"keyboard"`
+}
+
+type KeyboardContentSSE struct {
+ Content ContentSSE `json:"content"`
+}
+
+type ContentSSE struct {
+ Rows []RowSSE `json:"rows"`
+}
+
+type RowSSE struct {
+ Buttons []ButtonSSE `json:"buttons"`
+}
+
+type ButtonSSE struct {
+ RenderData RenderDataSSE `json:"render_data"`
+ Action ActionSSE `json:"action"`
+}
+
+type RenderDataSSE struct {
+ Label string `json:"label"`
+ Style int `json:"style"`
+}
+
+type ActionSSE struct {
+ Type int `json:"type"`
+}
+
+type ActionButtonSSE struct {
+ TemplateID int `json:"template_id"`
+ CallbackData string `json:"callback_data"`
+}
diff --git a/botgo/openapi/iface.go b/botgo/openapi/iface.go
index 58bd24ec..7e843809 100644
--- a/botgo/openapi/iface.go
+++ b/botgo/openapi/iface.go
@@ -83,6 +83,8 @@ type MessageAPI interface {
PostGroupMessage(ctx context.Context, groupID string, msg dto.APIMessage) (*dto.GroupMessageResponse, error)
// PostC2CMessage 发送C2C消息
PostC2CMessage(ctx context.Context, userID string, msg dto.APIMessage) (*dto.C2CMessageResponse, error)
+ // PostC2CMessage 发送C2CSSE消息
+ PostC2CMessageSSE(ctx context.Context, userID string, msg dto.APIMessage) (*dto.C2CMessageResponse, error)
}
// GuildAPI guild 相关接口
diff --git a/botgo/openapi/v1/message.go b/botgo/openapi/v1/message.go
index 4285a823..6f77ab1a 100644
--- a/botgo/openapi/v1/message.go
+++ b/botgo/openapi/v1/message.go
@@ -300,3 +300,24 @@ func (o *openAPI) PostC2CMessage(ctx context.Context, userID string, msg dto.API
return result, nil
}
+
+// PostC2CMessage 回复C2CSSE消息
+func (o *openAPI) PostC2CMessageSSE(ctx context.Context, userID string, msg dto.APIMessage) (*dto.C2CMessageResponse, error) {
+ var resp *resty.Response
+ var err error
+
+ resp, err = o.request(ctx).
+ SetResult(dto.Message{}). // 设置为消息类型
+ SetPathParam("user_id", userID).
+ SetBody(msg).
+ Post(o.getURL("/v2/users/{user_id}/messages"))
+
+ if err != nil {
+ return nil, err
+ }
+
+ result := &dto.C2CMessageResponse{}
+ result.Message = resp.Result().(*dto.Message)
+
+ return result, nil
+}
diff --git a/botgo/openapi/v2/message.go b/botgo/openapi/v2/message.go
index d3e23707..7a29802c 100644
--- a/botgo/openapi/v2/message.go
+++ b/botgo/openapi/v2/message.go
@@ -315,3 +315,24 @@ func (o *openAPIv2) PostC2CMessage(ctx context.Context, userID string, msg dto.A
return result, nil
}
+
+// PostC2CMessage 回复C2CSSE消息
+func (o *openAPIv2) PostC2CMessageSSE(ctx context.Context, userID string, msg dto.APIMessage) (*dto.C2CMessageResponse, error) {
+ var resp *resty.Response
+ var err error
+
+ resp, err = o.request(ctx).
+ SetResult(dto.Message{}). // 设置为消息类型
+ SetPathParam("user_id", userID).
+ SetBody(msg).
+ Post(o.getURL("/v2/users/{user_id}/messages"))
+
+ if err != nil {
+ return nil, err
+ }
+
+ result := &dto.C2CMessageResponse{}
+ result.Message = resp.Result().(*dto.Message)
+
+ return result, nil
+}
diff --git a/handlers/send_private_msg_sse.go b/handlers/send_private_msg_sse.go
new file mode 100644
index 00000000..602ba965
--- /dev/null
+++ b/handlers/send_private_msg_sse.go
@@ -0,0 +1,229 @@
+package handlers
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+
+ "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/tencent-connect/botgo/dto"
+ "github.com/tencent-connect/botgo/openapi"
+)
+
+var msgIDToIndex = make(map[string]int)
+var msgIDToRelatedID = make(map[string]string)
+
+func init() {
+ callapi.RegisterHandler("send_private_msg_sse", HandleSendPrivateMsgSSE)
+}
+
+type InterfaceBody struct {
+ Content string `json:"content"`
+ State int `json:"state"`
+ PromptKeyboard []string `json:"prompt_keyboard,omitempty"`
+ ActionButton int `json:"action_button,omitempty"`
+ CallbackData string `json:"callback_data,omitempty"`
+}
+
+func incrementIndex(msgID string) int {
+ if _, exists := msgIDToIndex[msgID]; !exists {
+ msgIDToIndex[msgID] = 0 // 初始化为0
+ return 0
+ }
+ msgIDToIndex[msgID]++ // 递增Index
+ return msgIDToIndex[msgID]
+}
+
+// GetRelatedID 根据MessageID获取相关的ID
+func GetRelatedID(MessageID string) string {
+ if relatedID, exists := msgIDToRelatedID[MessageID]; exists {
+ return relatedID
+ }
+ // 如果没有找到转换关系,返回空字符串
+ return ""
+}
+
+// UpdateRelatedID 更新MessageID到respID的映射关系
+func UpdateRelatedID(MessageID, ID string) {
+ msgIDToRelatedID[MessageID] = ID
+}
+
+func HandleSendPrivateMsgSSE(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) (string, error) {
+ // 使用 message.Echo 作为key来获取消息类型
+ var retmsg string
+
+ // 检查UserID是否为0
+ checkZeroUserID := func(id interface{}) bool {
+ switch v := id.(type) {
+ case int:
+ return v != 0
+ case int64:
+ return v != 0
+ case string:
+ return v != "0" // 同样检查字符串形式的0
+ default:
+ return true // 如果不是int、int64或string,假定它不为0
+ }
+ }
+
+ // New checks for UserID and GroupID being nil or 0
+ if message.Params.UserID == nil || !checkZeroUserID(message.Params.UserID) {
+ mylog.Printf("send_group_msg_sse接收到错误action: %v", message)
+ return "", nil
+ }
+
+ var err error
+
+ var resp *dto.C2CMessageResponse
+
+ //私聊信息
+ var UserID string
+ if config.GetIdmapPro() {
+ //还原真实的userid
+ //mylog.Printf("group_private:%v", message.Params.UserID.(string))
+ _, UserID, err = idmap.RetrieveRowByIDv2Pro("690426430", message.Params.UserID.(string))
+ if err != nil {
+ mylog.Printf("Error reading config: %v", err)
+ return "", nil
+ }
+ mylog.Printf("测试,通过Proid获取的UserID:%v", UserID)
+ } else {
+ //还原真实的userid
+ UserID, err = idmap.RetrieveRowByIDv2(message.Params.UserID.(string))
+ if err != nil {
+ mylog.Printf("Error reading config: %v", err)
+ return "", nil
+ }
+ }
+
+ // 首先,将message.Params.Message序列化成JSON字符串
+ messageJSON, err := json.Marshal(message.Params.Message)
+ if err != nil {
+ fmt.Printf("Error marshalling message: %v\n", err)
+ return "", nil
+ }
+
+ // 然后,将这个JSON字符串反序列化到InterfaceBody类型的对象中
+ var messageBody InterfaceBody
+ err = json.Unmarshal(messageJSON, &messageBody)
+ if err != nil {
+ fmt.Printf("Error unmarshalling to InterfaceBody: %v\n", err)
+ return "", nil
+ }
+
+ // 输出反序列化后的对象,确认是否成功转换
+ fmt.Printf("Recovered InterfaceBody: %+v\n", messageBody)
+ // 使用 echo 获取消息ID
+ var messageID string
+ if config.GetLazyMessageId() {
+ //由于实现了Params的自定义unmarshell 所以可以类型安全的断言为string
+ messageID = echo.GetLazyMessagesId(UserID)
+ mylog.Printf("GetLazyMessagesId: %v", messageID)
+ }
+ if messageID == "" {
+ if echoStr, ok := message.Echo.(string); ok {
+ messageID = echo.GetMsgIDByKey(echoStr)
+ mylog.Println("echo取私聊发信息对应的message_id:", messageID)
+ }
+ }
+ // 如果messageID仍然为空,尝试使用config.GetAppID和UserID的组合来获取messageID
+ // 如果messageID为空,通过函数获取
+ if messageID == "" {
+ messageID = GetMessageIDByUseridOrGroupid(config.GetAppIDStr(), UserID)
+ mylog.Println("通过GetMessageIDByUserid函数获取的message_id:", messageID)
+ }
+ if messageID == "2000" {
+ messageID = ""
+ mylog.Println("通过lazymsgid发送群私聊主动信息,每月可发送1次")
+ }
+
+ // 获取并打印相关ID
+ relatedID := GetRelatedID(messageID)
+ fmt.Println("相关ID:", relatedID)
+ dtoSSE := generateMessageSSE(messageBody, messageID, relatedID)
+
+ mylog.Printf("私聊发信息sse:%v", dtoSSE)
+
+ resp, err = apiv2.PostC2CMessageSSE(context.TODO(), UserID, dtoSSE)
+ if err != nil {
+ mylog.Printf("发送文本私聊信息失败: %v", err)
+ //如果失败 防止进入递归
+ return "", nil
+ }
+
+ // 更新或刷新映射关系
+ UpdateRelatedID(messageID, resp.Message.ID)
+
+ //发送成功回执
+ retmsg, _ = SendC2CResponse(client, err, &message, resp)
+
+ return retmsg, nil
+}
+
+func generateMessageSSE(body InterfaceBody, msgID, ID string) *dto.MessageSSE {
+ index := incrementIndex(msgID) // 获取并递增Index
+
+ // 将InterfaceBody的PromptKeyboard转换为MessageSSE的结构
+ var rows []dto.RowSSE
+ for _, label := range body.PromptKeyboard {
+ row := dto.RowSSE{
+ Buttons: []dto.ButtonSSE{
+ {
+ RenderData: dto.RenderDataSSE{Label: label, Style: 2},
+ Action: dto.ActionSSE{Type: 2},
+ },
+ },
+ }
+ rows = append(rows, row)
+ }
+
+ var msgsse dto.MessageSSE
+
+ if body.Content != "" {
+ // 确保Markdown已经初始化
+ msgsse.Markdown = &dto.MarkdownSSE{}
+ msgsse.Markdown.Content = body.Content
+ }
+
+ if len(rows) > 0 {
+ // 确保PromptKeyboard及其嵌套结构已经初始化
+ msgsse.PromptKeyboard = &dto.KeyboardSSE{
+ KeyboardContentSSE: dto.KeyboardContentSSE{
+ Content: dto.ContentSSE{
+ Rows: []dto.RowSSE{}, // 初始化空切片,避免nil切片赋值
+ },
+ },
+ }
+ msgsse.PromptKeyboard.KeyboardContentSSE.Content.Rows = rows
+ }
+
+ // 剩余字段赋值
+ msgsse.MsgType = 2
+ msgsse.MsgSeq = index + 3
+ msgsse.Stream = &dto.StreamSSE{
+ State: body.State,
+ Index: index,
+ }
+
+ if ID != "" {
+ msgsse.Stream.ID = ID
+ }
+ if msgID != "" {
+ msgsse.MsgID = msgID
+ }
+
+ // 初始化ActionButtonSSE,如果CallbackData有值
+ if body.CallbackData != "" {
+ msgsse.ActionButton = &dto.ActionButtonSSE{
+ TemplateID: body.ActionButton,
+ CallbackData: body.CallbackData,
+ }
+ }
+
+ return &msgsse
+
+}
diff --git a/httpapi/httpapi.go b/httpapi/httpapi.go
index 5f95d4f2..e3dad08c 100644
--- a/httpapi/httpapi.go
+++ b/httpapi/httpapi.go
@@ -38,6 +38,10 @@ func CombinedMiddleware(api openapi.OpenAPI, apiV2 openapi.OpenAPI) gin.HandlerF
handleSendPrivateMessage(c, api, apiV2)
return
}
+ if c.Request.URL.Path == "/send_private_msg_sse" {
+ handleSendPrivateMessageSSE(c, api, apiV2)
+ return
+ }
if c.Request.URL.Path == "/send_guild_channel_msg" {
handleSendGuildChannelMessage(c, api, apiV2)
return
@@ -210,6 +214,55 @@ func handleSendPrivateMessage(c *gin.Context, api openapi.OpenAPI, apiV2 openapi
c.String(http.StatusOK, retmsg)
}
+// handleSendPrivateMessageSSE 处理发送私聊SSE消息的请求
+func handleSendPrivateMessageSSE(c *gin.Context, api openapi.OpenAPI, apiV2 openapi.OpenAPI) {
+ var retmsg string
+ var req struct {
+ GroupID int64 `json:"group_id" form:"group_id"`
+ UserID int64 `json:"user_id" form:"user_id"`
+ Message interface{} `json:"message" form:"message"`
+ AutoEscape bool `json:"auto_escape" form:"auto_escape"`
+ }
+
+ // 根据请求方法解析参数
+ if c.Request.Method == http.MethodGet {
+ // 从URL查询参数解析
+ if err := c.ShouldBindQuery(&req); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+ } else {
+ // 从JSON或表单数据解析
+ if err := c.ShouldBind(&req); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+ }
+
+ // 使用解析后的参数处理请求
+ // 例如:api.SendGroupMessage(req.GroupID, req.Message, req.AutoEscape)
+ client := &HttpAPIClient{}
+ // 创建 ActionMessage 实例
+ message := callapi.ActionMessage{
+ Action: "send_private_msg_sse",
+ Params: callapi.ParamsContent{
+ GroupID: strconv.FormatInt(req.GroupID, 10), // 注意这里需要转换类型,因为 GroupID 是 int64
+ UserID: strconv.FormatInt(req.UserID, 10),
+ Message: req.Message,
+ },
+ }
+ // 调用处理函数
+ retmsg, err := handlers.HandleSendPrivateMsgSSE(client, api, apiV2, message)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
+ return
+ }
+
+ // 返回处理结果
+ c.Header("Content-Type", "application/json")
+ c.String(http.StatusOK, retmsg)
+}
+
// handleSendGuildChannelMessage 处理发送消频道息的请求
func handleSendGuildChannelMessage(c *gin.Context, api openapi.OpenAPI, apiV2 openapi.OpenAPI) {
var retmsg string
From afdf12e80c7483a9f68c375a08e0af76606e154b Mon Sep 17 00:00:00 2001
From: cosmo
Date: Sun, 7 Apr 2024 20:23:07 +0800
Subject: [PATCH 22/33] beta357
---
Processor/ProcessGroupMessage.go | 8 ++-
Processor/Processor.go | 2 +
go.mod | 2 +-
go.sum | 6 ++-
idmap/service.go | 42 +++++++--------
images/upload_api.go | 89 ++++++++++++++++++++++++++++++++
server/uploadpic.go | 24 ++++++---
url/shorturl.go | 14 ++---
webui/cookie.go | 12 ++---
9 files changed, 151 insertions(+), 48 deletions(-)
diff --git a/Processor/ProcessGroupMessage.go b/Processor/ProcessGroupMessage.go
index 4cacbfab..620c8c5f 100644
--- a/Processor/ProcessGroupMessage.go
+++ b/Processor/ProcessGroupMessage.go
@@ -122,11 +122,9 @@ func (p *Processors) ProcessGroupMessage(data *dto.WSGroupATMessageData) error {
groupMsg.RealMessageType = "group"
groupMsg.IsBindedUserId = IsBindedUserId
groupMsg.IsBindedGroupId = IsBindedGroupId
- if IsBindedUserId {
- groupMsg.Avatar, _ = GenerateAvatarURL(userid64)
- } else {
- groupMsg.Avatar, _ = GenerateAvatarURLV2(data.Author.ID)
- }
+ groupMsg.RealGroupID = data.GroupID
+ groupMsg.RealUserID = data.Author.ID
+ groupMsg.Avatar, _ = GenerateAvatarURLV2(data.Author.ID)
}
//根据条件判断是否增加nick和card
var CaN = config.GetCardAndNick()
diff --git a/Processor/Processor.go b/Processor/Processor.go
index 297cffef..71f23ed0 100644
--- a/Processor/Processor.go
+++ b/Processor/Processor.go
@@ -91,6 +91,8 @@ type OnebotGroupMessage struct {
Font int `json:"font"`
UserID int64 `json:"user_id"`
RealMessageType string `json:"real_message_type,omitempty"` //当前信息的真实类型 group group_private guild guild_private
+ RealUserID string `json:"real_user_id,omitempty"` //当前真实uid
+ RealGroupID string `json:"real_group_id,omitempty"` //当前真实gid
IsBindedGroupId bool `json:"is_binded_group_id,omitempty"` //当前群号是否是binded后的
IsBindedUserId bool `json:"is_binded_user_id,omitempty"` //当前用户号号是否是binded后的
}
diff --git a/go.mod b/go.mod
index e64ad884..c41d3ff0 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,6 @@ require (
github.com/aliyun/alibaba-cloud-sdk-go v1.62.645
github.com/aliyun/aliyun-oss-go-sdk v3.0.1+incompatible
github.com/baidubce/bce-sdk-go v0.9.161
- github.com/boltdb/bolt v1.3.1
github.com/fatih/color v1.15.0
github.com/gin-gonic/gin v1.9.1
github.com/google/uuid v1.4.0
@@ -16,6 +15,7 @@ require (
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/tencent-connect/botgo v0.1.6
github.com/tencentyun/cos-go-sdk-v5 v0.7.45
+ go.etcd.io/bbolt v1.3.9
gopkg.in/yaml.v3 v3.0.1
)
diff --git a/go.sum b/go.sum
index bf141ce6..401b1c22 100644
--- a/go.sum
+++ b/go.sum
@@ -11,8 +11,6 @@ github.com/aliyun/aliyun-oss-go-sdk v3.0.1+incompatible h1:so4m5rRA32Tc5GgKg/5gK
github.com/aliyun/aliyun-oss-go-sdk v3.0.1+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/baidubce/bce-sdk-go v0.9.161 h1:dNf2K7clz167h7XOffqPsBg0GPntUp7EYGHd6yOFSJw=
github.com/baidubce/bce-sdk-go v0.9.161/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
-github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
-github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
@@ -186,6 +184,8 @@ github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
+go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
@@ -220,6 +220,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
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.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
+golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/idmap/service.go b/idmap/service.go
index d14e5f71..69590765 100644
--- a/idmap/service.go
+++ b/idmap/service.go
@@ -16,9 +16,9 @@ import (
"strings"
"sync"
- "github.com/boltdb/bolt"
"github.com/hoshinonyaruko/gensokyo/config"
"github.com/hoshinonyaruko/gensokyo/mylog"
+ "go.etcd.io/bbolt"
)
var (
@@ -35,18 +35,18 @@ const (
CounterKey = "currentRow"
)
-var db *bolt.DB
+var db *bbolt.DB
var ErrKeyNotFound = errors.New("key not found")
func InitializeDB() {
var err error
- db, err = bolt.Open(DBName, 0600, nil)
+ db, err = bbolt.Open(DBName, 0600, nil)
if err != nil {
log.Fatalf("Error opening DB: %v", err)
}
- db.Update(func(tx *bolt.Tx) error {
+ db.Update(func(tx *bbolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(BucketName))
return err
})
@@ -118,7 +118,7 @@ func CheckValuev2(value int64) bool {
func StoreID(id string) (int64, error) {
var newRow int64
- err := db.Update(func(tx *bolt.Tx) error {
+ err := db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(BucketName))
// 检查ID是否已经存在
@@ -180,7 +180,7 @@ func StoreID(id string) (int64, error) {
func SimplifiedStoreID(id string) (int64, error) {
var newRow int64
- err := db.Update(func(tx *bolt.Tx) error {
+ err := db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(BucketName))
// 生成新的行号
@@ -261,7 +261,7 @@ func StoreIDPro(id string, subid string) (int64, int64, error) {
var newRowID, newSubRowID int64
var err error
- err = db.Update(func(tx *bolt.Tx) error {
+ err = db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(BucketName))
// 生成正向键
@@ -394,7 +394,7 @@ func StoreIDv2Pro(id string, subid string) (int64, int64, error) {
// 根据b得到a
func RetrieveRowByID(rowid string) (string, error) {
var id string
- err := db.View(func(tx *bolt.Tx) error {
+ err := db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(BucketName))
// 根据行号检索ID
@@ -461,7 +461,7 @@ func RetrieveRowByIDv2Pro(newRowID string, newSubRowID string) (string, string,
func RetrieveRowByIDPro(newRowID, newSubRowID string) (string, string, error) {
var id, subid string
- err := db.View(func(tx *bolt.Tx) error {
+ err := db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(BucketName))
// 根据新的行号和子行号检索ID和SubID
@@ -529,7 +529,7 @@ func RetrieveRowByIDv2(rowid string) (string, error) {
// 根据a 以b为类别 储存c
func WriteConfig(sectionName, keyName, value string) error {
- return db.Update(func(tx *bolt.Tx) error {
+ return db.Update(func(tx *bbolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte(ConfigBucket))
if err != nil {
mylog.Printf("Error creating or accessing bucket: %v", err)
@@ -590,7 +590,7 @@ func WriteConfigv2(sectionName, keyName, value string) error {
// 根据a和b取出c
func ReadConfig(sectionName, keyName string) (string, error) {
var result string
- err := db.View(func(tx *bolt.Tx) error {
+ err := db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(ConfigBucket))
if b == nil {
return fmt.Errorf("bucket not found")
@@ -611,7 +611,7 @@ func ReadConfig(sectionName, keyName string) (string, error) {
// DeleteConfig根据sectionName和keyName删除指定的键值对
func DeleteConfig(sectionName, keyName string) error {
- return db.Update(func(tx *bolt.Tx) error {
+ return db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(ConfigBucket))
if b == nil {
return fmt.Errorf("bucket %s does not exist", ConfigBucket)
@@ -727,7 +727,7 @@ func joinSectionAndKey(sectionName, keyName string) []byte {
// UpdateVirtualValue 更新旧的虚拟值到新的虚拟值的映射
func UpdateVirtualValue(oldRowValue, newRowValue int64) error {
- return db.Update(func(tx *bolt.Tx) error {
+ return db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(BucketName))
// 查找旧虚拟值对应的真实值
@@ -766,7 +766,7 @@ func UpdateVirtualValue(oldRowValue, newRowValue int64) error {
// RetrieveRealValue 根据虚拟值获取真实值,并返回虚拟值及其对应的真实值
func RetrieveRealValue(virtualValue int64) (string, string, error) {
var realValue string
- err := db.View(func(tx *bolt.Tx) error {
+ err := db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(BucketName))
// 构造键,根据虚拟值查找
@@ -791,7 +791,7 @@ func RetrieveRealValue(virtualValue int64) (string, string, error) {
// RetrieveVirtualValue 根据真实值获取虚拟值,并返回真实值及其对应的虚拟值
func RetrieveVirtualValue(realValue string) (string, string, error) {
var virtualValue int64
- err := db.View(func(tx *bolt.Tx) error {
+ err := db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(BucketName))
// 根据真实值查找虚拟值
@@ -967,7 +967,7 @@ func RetrieveVirtualValuev2Pro(realValue string, realValueSub string) (string, s
func RetrieveVirtualValuePro(realValue string, realValueSub string) (string, string, error) {
var newRowID, newSubRowID string
- err := db.View(func(tx *bolt.Tx) error {
+ err := db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(BucketName))
// 构建正向键
@@ -1001,7 +1001,7 @@ func RetrieveVirtualValuePro(realValue string, realValueSub string) (string, str
func RetrieveRealValuePro(virtualValue1, virtualValue2 int64) (string, string, error) {
var realValue1, realValue2 string
- err := db.View(func(tx *bolt.Tx) error {
+ err := db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(BucketName))
// 根据两个虚拟值构造键
@@ -1079,7 +1079,7 @@ func RetrieveRealValuesv2Pro(virtualValue int64, virtualValueSub int64) (string,
// UpdateVirtualValuePro 更新一对旧虚拟值到新虚拟值的映射 旧群号 新群号 旧用户 新用户
func UpdateVirtualValuePro(oldVirtualValue1, newVirtualValue1, oldVirtualValue2, newVirtualValue2 int64) error {
- return db.Update(func(tx *bolt.Tx) error {
+ return db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(BucketName))
// 构造旧和新的复合键
oldCompositeKey := fmt.Sprintf("%d:%d", oldVirtualValue1, oldVirtualValue2)
@@ -1147,7 +1147,7 @@ func UpdateVirtualValuev2Pro(oldVirtualValue1, newVirtualValue1, oldVirtualValue
func FindKeysBySubAndType(sub string, typeSuffix string) ([]string, error) {
var ids []string
- err := db.View(func(tx *bolt.Tx) error {
+ err := db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(ConfigBucket))
if b == nil {
return fmt.Errorf("bucket %s not found", ConfigBucket)
@@ -1178,7 +1178,7 @@ func FindKeysBySubAndType(sub string, typeSuffix string) ([]string, error) {
func FindSubKeysById(id string) ([]string, error) {
var subKeys []string
- err := db.View(func(tx *bolt.Tx) error {
+ err := db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte("ids"))
if b == nil {
return fmt.Errorf("bucket %s not found", "ids")
@@ -1257,7 +1257,7 @@ func FindSubKeysByIdPro(id string) ([]string, error) {
// 场景: xxx:yyy zzz:bbb zzz:bbb xxx:yyy 把xxx(id)替换为newID 比如更换群号(会卡住)
func UpdateKeysWithNewID(id, newID string) error {
- return db.Update(func(tx *bolt.Tx) error {
+ return db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(BucketName))
if b == nil {
return fmt.Errorf("bucket %s not found", BucketName)
diff --git a/images/upload_api.go b/images/upload_api.go
index 6c5a983e..c55c586c 100644
--- a/images/upload_api.go
+++ b/images/upload_api.go
@@ -194,6 +194,95 @@ func UploadBase64ImageToServer(msgid string, base64Image string, groupID string,
return picURL, 0, 0, 0, nil
}
+// TransferUrlToServerUrlr 将url转化为ntv2链接
+func TransferUrlToServerUrl(msgid string, url string, groupID string, apiv2 openapi.OpenAPI) (string, uint64, uint32, uint32, error) {
+ var err error
+
+ if isNumeric(groupID) {
+ //用转换前的群号获取msgid
+ if msgid == "" {
+ msgid = echo.GetLazyMessagesId(groupID)
+ }
+ // 检查groupID是否为纯数字构成 RetrieveRowByIDv2是通用逻辑,也可以将userid还原为32位数originaluserid
+ // 但没有私信权限,故没有测试
+ originalGroupID, err := idmap.RetrieveRowByIDv2(groupID)
+ if err != nil {
+ log.Printf("Error retrieving original GroupID: %v", err)
+ return url, 0, 0, 0, nil
+ }
+ log.Printf("通过idmap获取的originalGroupID: %v", originalGroupID)
+
+ // 用originalGroupID更新groupID
+ groupID = originalGroupID
+ } else {
+ // 映射str的GroupID到int
+ GroupID64, err := idmap.StoreIDv2(groupID)
+ if err != nil {
+ log.Printf("failed to convert ChannelID to int: %v", err)
+ return url, 0, 0, 0, nil
+ }
+ groupIDTemp := strconv.FormatInt(GroupID64, 10)
+ //用数字的群号获取msgid
+ if msgid == "" {
+ msgid = echo.GetLazyMessagesId(groupIDTemp)
+ }
+ }
+
+ richMediaMessage := &dto.RichMediaMessage{
+ EventID: msgid,
+ FileType: 1, // 1代表图片
+ URL: url,
+ Content: "", // 这个字段文档没有了
+ SrvSendMsg: false,
+ }
+
+ var fileInfo string
+ //尝试群聊发图
+ fileInfo, err = uploadMedia(context.TODO(), groupID, richMediaMessage, apiv2)
+ if err != nil {
+ //尝试私信发图
+ fileInfo, err = uploadMediaPrivate(context.TODO(), groupID, richMediaMessage, apiv2)
+ if err != nil {
+ //返回原始图片url
+ return url, 0, 0, 0, nil
+ }
+ }
+
+ // 将Base64字符串解码为二进制
+ fileInfoBytes, err := base64.StdEncoding.DecodeString(fileInfo)
+ if err != nil {
+ log.Fatalf("Failed to decode Base64 string: %v", err)
+ }
+
+ // 初始化Proto消息类型
+ var mainMessage protobuf.Main
+
+ // 解析二进制数据到Proto消息
+ err = proto.Unmarshal(fileInfoBytes, &mainMessage)
+ if err != nil {
+ log.Fatalf("Failed to unmarshal Proto message: %v", err)
+ }
+
+ // 从Proto消息中读取值
+ realGroupID := mainMessage.GetA().GetB().GetInfo().GetDetail().GetGroupInfo().GetGroupNumber()
+ downloadURL := mainMessage.GetA().GetImageData().GetImageInfo().GetUrl()
+ //https的地址不能放到md里
+ //downloadURL = "https://multimedia.nt.qq.com.cn" + downloadURL
+ // 将 downloadURL 中的所有下划线 "_" 替换为 "%5f"
+ downloadURL = strings.Replace(downloadURL, "_", "%5f", -1)
+ downloadURL = "http://multimedia.nt.qq.com" + downloadURL
+ width := mainMessage.GetA().GetImageData().GetWidth()
+ height := mainMessage.GetA().GetImageData().GetHeight()
+
+ // 打印读取的值
+ log.Printf("RealGroup ID: %d\n", realGroupID)
+ log.Printf("Download URL: %s, Width: %d, Height: %d\n", downloadURL, width, height)
+
+ // 根据需要返回适当的值
+ return downloadURL, realGroupID, width, height, nil
+
+}
+
// 将base64语音通过lotus转换成url
func UploadBase64RecordToServer(base64Record string) (string, error) {
extraPicAuditingType := config.GetOssType()
diff --git a/server/uploadpic.go b/server/uploadpic.go
index c60cc337..e8dce780 100644
--- a/server/uploadpic.go
+++ b/server/uploadpic.go
@@ -126,7 +126,6 @@ func UploadBase64ImageHandler(rateLimiter *RateLimiter) gin.HandlerFunc {
}
}
-
func UploadBase64ImageHandlerV2(rateLimiter *RateLimiter, apiv2 openapi.OpenAPI) gin.HandlerFunc {
return func(c *gin.Context) {
ipAddress := c.ClientIP()
@@ -137,18 +136,31 @@ func UploadBase64ImageHandlerV2(rateLimiter *RateLimiter, apiv2 openapi.OpenAPI)
// 从请求中获取必要的参数
base64Image := c.PostForm("base64Image")
- msgid := c.DefaultPostForm("msgid", "") // msgid可以为空
- groupID := c.PostForm("groupID") // groupID是必需的
+ imageUrl := c.PostForm("url") // 新增的url参数
+ msgid := c.DefaultPostForm("msgid", "")
+ groupID := c.PostForm("groupID")
if groupID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "groupID is required"})
return
}
- // 调用函数上传图片
- imageURL, groupid, width, height, err := images.UploadBase64ImageToServer(msgid, base64Image, groupID, apiv2)
+ var imageURL string
+ var groupid uint64
+ var width, height uint32
+ var err error
+
+ // 根据参数调用不同的处理逻辑
+ if base64Image != "" {
+ imageURL, groupid, width, height, err = images.UploadBase64ImageToServer(msgid, base64Image, groupID, apiv2)
+ } else if imageUrl != "" {
+ imageURL, groupid, width, height, err = images.TransferUrlToServerUrl(msgid, imageUrl, groupID, apiv2)
+ } else {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "either base64Image or url is required"})
+ return
+ }
+
if err != nil {
- // 根据错误类型返回合适的HTTP状态码和错误信息
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
diff --git a/url/shorturl.go b/url/shorturl.go
index 36c70048..0d8381ad 100644
--- a/url/shorturl.go
+++ b/url/shorturl.go
@@ -14,10 +14,10 @@ import (
"strings"
"time"
- "github.com/boltdb/bolt"
"github.com/gin-gonic/gin"
"github.com/hoshinonyaruko/gensokyo/config"
"github.com/hoshinonyaruko/gensokyo/mylog"
+ "go.etcd.io/bbolt"
)
const (
@@ -25,7 +25,7 @@ const (
)
var (
- db *bolt.DB
+ db *bbolt.DB
)
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
@@ -48,13 +48,13 @@ func generateHashedString(url string) string {
// 这里的数据库是在init创建的
func init() {
var err error
- db, err = bolt.Open("gensokyo.db", 0600, nil)
+ db, err = bbolt.Open("gensokyo.db", 0600, nil)
if err != nil {
panic(err)
}
// Ensure bucket exists
- err = db.Update(func(tx *bolt.Tx) error {
+ err = db.Update(func(tx *bbolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(bucketName))
if err != nil {
return fmt.Errorf("failed to create or get the bucket: %v", err)
@@ -222,7 +222,7 @@ func GenerateShortURL(longURL string) string {
func existsInDB(shortURL string) (bool, error) {
exists := false
- err := db.View(func(tx *bolt.Tx) error {
+ err := db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(bucketName))
v := b.Get([]byte(shortURL))
if v != nil {
@@ -269,7 +269,7 @@ func getLongURLFromDB(shortURL string) (string, error) {
return response["longURL"].(string), nil
} else {
var longURL string
- err := db.View(func(tx *bolt.Tx) error {
+ err := db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(bucketName))
v := b.Get([]byte(shortURL))
if v == nil {
@@ -284,7 +284,7 @@ func getLongURLFromDB(shortURL string) (string, error) {
// storeURL 存储长URL和对应的短URL
func storeURL(shortURL, longURL string) error {
- return db.Update(func(tx *bolt.Tx) error {
+ return db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(bucketName))
return b.Put([]byte(shortURL), []byte(longURL))
})
diff --git a/webui/cookie.go b/webui/cookie.go
index bbafa277..a858639c 100644
--- a/webui/cookie.go
+++ b/webui/cookie.go
@@ -6,8 +6,8 @@ import (
"log"
"time"
- "github.com/boltdb/bolt"
"github.com/google/uuid"
+ "go.etcd.io/bbolt"
)
const (
@@ -17,18 +17,18 @@ const (
ExpirationHours = 24 // Cookie 有效期为24小时
)
-var db *bolt.DB
+var db *bbolt.DB
var ErrCookieNotFound = errors.New("cookie not found")
var ErrCookieExpired = errors.New("cookie has expired")
func InitializeDB() {
var err error
- db, err = bolt.Open(DBName, 0600, nil)
+ db, err = bbolt.Open(DBName, 0600, nil)
if err != nil {
log.Fatalf("Error opening DB: %v", err)
}
- db.Update(func(tx *bolt.Tx) error {
+ db.Update(func(tx *bbolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(CookieBucket))
return err
})
@@ -42,7 +42,7 @@ func GenerateCookie() (string, error) {
cookie := uuid.New().String()
expiration := time.Now().Add(ExpirationHours * time.Hour).Unix()
- err := db.Update(func(tx *bolt.Tx) error {
+ err := db.Update(func(tx *bbolt.Tx) error {
bucket := tx.Bucket([]byte(CookieBucket))
if err := bucket.Put([]byte(cookie), intToBytes(expiration)); err != nil {
return err
@@ -59,7 +59,7 @@ func GenerateCookie() (string, error) {
func ValidateCookie(cookie string) (bool, error) {
isValid := false
- err := db.View(func(tx *bolt.Tx) error {
+ err := db.View(func(tx *bbolt.Tx) error {
bucket := tx.Bucket([]byte(CookieBucket))
expBytes := bucket.Get([]byte(cookie))
if expBytes == nil {
From 78ab73775e339835b0848803303a3506adcb7303 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Mon, 8 Apr 2024 17:18:26 +0800
Subject: [PATCH 23/33] beta358
---
httpapi/httpapi.go | 76 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 76 insertions(+)
diff --git a/httpapi/httpapi.go b/httpapi/httpapi.go
index e3dad08c..96dd7dc9 100644
--- a/httpapi/httpapi.go
+++ b/httpapi/httpapi.go
@@ -1,7 +1,9 @@
package httpapi
import (
+ "fmt"
"net/http"
+ "reflect"
"strconv"
"strings"
@@ -54,6 +56,10 @@ func CombinedMiddleware(api openapi.OpenAPI, apiV2 openapi.OpenAPI) gin.HandlerF
handlePutInteraction(c, api, apiV2)
return
}
+ if c.Request.URL.Path == "/delete_msg" {
+ handleDeleteMsg(c, api, apiV2)
+ return
+ }
// 调用c.Next()以继续处理请求链
c.Next()
@@ -392,3 +398,73 @@ func handlePutInteraction(c *gin.Context, api openapi.OpenAPI, apiV2 openapi.Ope
c.Header("Content-Type", "application/json")
c.String(http.StatusOK, retmsg)
}
+
+// 类型转换函数,将interface{}转换为string
+func convertToString(value interface{}) string {
+ switch v := value.(type) {
+ case int:
+ return strconv.Itoa(v)
+ case int64:
+ return strconv.FormatInt(v, 10)
+ case float64:
+ return strconv.FormatFloat(v, 'f', -1, 64)
+ case string:
+ return v
+ default:
+ fmt.Println("Unexpected type:", reflect.TypeOf(value))
+ return ""
+ }
+}
+
+func handleDeleteMsg(c *gin.Context, api openapi.OpenAPI, apiV2 openapi.OpenAPI) {
+ // 使用interface{}以适应不同类型的输入,接受动态参数类型
+ var req struct {
+ UserID interface{} `json:"user_id,omitempty" form:"user_id"`
+ GroupID interface{} `json:"group_id,omitempty" form:"group_id"`
+ ChannelID interface{} `json:"channel_id,omitempty" form:"channel_id"`
+ GuildID interface{} `json:"guild_id,omitempty" form:"guild_id"`
+ MessageID interface{} `json:"message_id" form:"message_id"`
+ }
+
+ // 解析请求参数
+ if err := c.ShouldBind(&req); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+
+ // 构造参数内容,只包括实际有值的字段
+ params := callapi.ParamsContent{}
+
+ if req.UserID != nil {
+ params.UserID = convertToString(req.UserID)
+ }
+ if req.GroupID != nil {
+ params.GroupID = convertToString(req.GroupID)
+ }
+ if req.ChannelID != nil {
+ params.ChannelID = convertToString(req.ChannelID)
+ }
+ if req.GuildID != nil {
+ params.GuildID = convertToString(req.GuildID)
+ }
+ if req.MessageID != nil {
+ params.MessageID = convertToString(req.MessageID)
+ }
+
+ // 创建 ActionMessage 实例
+ message := callapi.ActionMessage{
+ Action: "delete_msg",
+ Params: params,
+ }
+
+ // 调用处理函数,假设 handlers.DeleteMsg 已经实现并且适合处理消息删除的操作
+ client := &HttpAPIClient{}
+ retmsg, err := handlers.DeleteMsg(client, api, apiV2, message)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
+ return
+ }
+
+ // 返回处理结果
+ c.JSON(http.StatusOK, gin.H{"message": retmsg})
+}
From 1af000b83a5487e07e2323df8bd8b85f1211380b Mon Sep 17 00:00:00 2001
From: cosmo
Date: Fri, 12 Apr 2024 11:25:38 +0800
Subject: [PATCH 24/33] beta359
---
handlers/send_group_msg.go | 38 +++++++++++++++++++++-------------
handlers/send_group_msg_raw.go | 34 ++++++++++++++++++------------
handlers/send_msg.go | 36 +++++++++++++++++++-------------
handlers/send_private_msg.go | 37 ++++++++++++++++++++-------------
4 files changed, 90 insertions(+), 55 deletions(-)
diff --git a/handlers/send_group_msg.go b/handlers/send_group_msg.go
index b7207fdc..23c5d30d 100644
--- a/handlers/send_group_msg.go
+++ b/handlers/send_group_msg.go
@@ -105,6 +105,9 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
echo.AddMsgType(config.GetAppIDStr(), idInt64, "group_private")
retmsg, _ = HandleSendGroupMsg(client, api, apiv2, messageCopy)
}
+ } else {
+ // 特殊值代表不递归
+ echo.AddMapping(idInt64, 10)
}
switch msgType {
@@ -514,21 +517,28 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
default:
mylog.Printf("Unknown message type: %s", msgType)
}
- //重置递归类型
- if echo.GetMapping(idInt64) <= 0 {
- echo.AddMsgType(config.GetAppIDStr(), idInt64, "")
- }
- echo.AddMapping(idInt64, echo.GetMapping(idInt64)-1)
-
- //递归3次枚举类型
- if echo.GetMapping(idInt64) > 0 {
- tryMessageTypes := []string{"group", "guild", "guild_private"}
- messageCopy := message // 创建message的副本
- echo.AddMsgType(config.GetAppIDStr(), idInt64, tryMessageTypes[echo.GetMapping(idInt64)-1])
- delay := config.GetSendDelay()
- time.Sleep(time.Duration(delay) * time.Millisecond)
- retmsg, _ = HandleSendGroupMsg(client, api, apiv2, messageCopy)
+
+ // 如果递归id不是10(不递归特殊值)
+ if echo.GetMapping(idInt64) != 10 {
+ //重置递归类型 递归结束重置类型,避免下一次同样id,不同类型的请求被使用上一次类型
+ if echo.GetMapping(idInt64) <= 0 {
+ echo.AddMsgType(config.GetAppIDStr(), idInt64, "")
+ }
+
+ //减少递归计数器
+ echo.AddMapping(idInt64, echo.GetMapping(idInt64)-1)
+
+ //递归3次枚举类型
+ if echo.GetMapping(idInt64) > 0 {
+ tryMessageTypes := []string{"group", "guild", "guild_private"}
+ messageCopy := message // 创建message的副本
+ echo.AddMsgType(config.GetAppIDStr(), idInt64, tryMessageTypes[echo.GetMapping(idInt64)-1])
+ delay := config.GetSendDelay()
+ time.Sleep(time.Duration(delay) * time.Millisecond)
+ retmsg, _ = HandleSendGroupMsg(client, api, apiv2, messageCopy)
+ }
}
+
return retmsg, nil
}
diff --git a/handlers/send_group_msg_raw.go b/handlers/send_group_msg_raw.go
index e3ecb263..f08ac062 100644
--- a/handlers/send_group_msg_raw.go
+++ b/handlers/send_group_msg_raw.go
@@ -96,6 +96,9 @@ func HandleSendGroupMsgRaw(client callapi.Client, api openapi.OpenAPI, apiv2 ope
echo.AddMsgType(config.GetAppIDStr(), idInt64, "group_private")
retmsg, _ = HandleSendGroupMsg(client, api, apiv2, messageCopy)
}
+ } else {
+ // 特殊值代表不递归
+ echo.AddMapping(idInt64, 10)
}
switch msgType {
@@ -474,20 +477,25 @@ func HandleSendGroupMsgRaw(client callapi.Client, api openapi.OpenAPI, apiv2 ope
default:
mylog.Printf("Unknown message type: %s", msgType)
}
- //重置递归类型
- if echo.GetMapping(idInt64) <= 0 {
- echo.AddMsgType(config.GetAppIDStr(), idInt64, "")
- }
- echo.AddMapping(idInt64, echo.GetMapping(idInt64)-1)
- //递归3次枚举类型
- if echo.GetMapping(idInt64) > 0 {
- tryMessageTypes := []string{"group", "guild", "guild_private"}
- messageCopy := message // 创建message的副本
- echo.AddMsgType(config.GetAppIDStr(), idInt64, tryMessageTypes[echo.GetMapping(idInt64)-1])
- delay := config.GetSendDelay()
- time.Sleep(time.Duration(delay) * time.Millisecond)
- retmsg, _ = HandleSendGroupMsg(client, api, apiv2, messageCopy)
+ // 如果递归id不是10(不递归特殊值)
+ if echo.GetMapping(idInt64) != 10 {
+ //重置递归类型
+ if echo.GetMapping(idInt64) <= 0 {
+ echo.AddMsgType(config.GetAppIDStr(), idInt64, "")
+ }
+ echo.AddMapping(idInt64, echo.GetMapping(idInt64)-1)
+
+ //递归3次枚举类型
+ if echo.GetMapping(idInt64) > 0 {
+ tryMessageTypes := []string{"group", "guild", "guild_private"}
+ messageCopy := message // 创建message的副本
+ echo.AddMsgType(config.GetAppIDStr(), idInt64, tryMessageTypes[echo.GetMapping(idInt64)-1])
+ delay := config.GetSendDelay()
+ time.Sleep(time.Duration(delay) * time.Millisecond)
+ retmsg, _ = HandleSendGroupMsg(client, api, apiv2, messageCopy)
+ }
}
+
return retmsg, nil
}
diff --git a/handlers/send_msg.go b/handlers/send_msg.go
index 5a4137e8..61a01597 100644
--- a/handlers/send_msg.go
+++ b/handlers/send_msg.go
@@ -111,6 +111,9 @@ func HandleSendMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.Ope
echo.AddMsgType(config.GetAppIDStr(), idInt64, "group_private")
retmsg, _ = HandleSendMsg(client, api, apiv2, messageCopy)
}
+ } else {
+ // 特殊值代表不递归
+ echo.AddMapping(idInt64, 10)
}
switch msgType {
@@ -163,22 +166,27 @@ func HandleSendMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.Ope
default:
mylog.Printf("1Unknown message type: %s", msgType)
}
- //重置递归类型
- if echo.GetMapping(idInt64) <= 0 {
- echo.AddMsgType(config.GetAppIDStr(), idInt64, "")
- echo.AddMsgType(config.GetAppIDStr(), idInt642, "")
- }
- echo.AddMapping(idInt64, echo.GetMapping(idInt64)-1)
- //递归3次枚举类型
- if echo.GetMapping(idInt64) > 0 {
- tryMessageTypes := []string{"group", "guild", "guild_private"}
- messageCopy := message // 创建message的副本
- echo.AddMsgType(config.GetAppIDStr(), idInt64, tryMessageTypes[echo.GetMapping(idInt64)-1])
- delay := config.GetSendDelay()
- time.Sleep(time.Duration(delay) * time.Millisecond)
- retmsg, _ = HandleSendMsg(client, api, apiv2, messageCopy)
+ // 如果递归id不是10(不递归特殊值)
+ if echo.GetMapping(idInt64) != 10 {
+ //重置递归类型
+ if echo.GetMapping(idInt64) <= 0 {
+ echo.AddMsgType(config.GetAppIDStr(), idInt64, "")
+ echo.AddMsgType(config.GetAppIDStr(), idInt642, "")
+ }
+ echo.AddMapping(idInt64, echo.GetMapping(idInt64)-1)
+
+ //递归3次枚举类型
+ if echo.GetMapping(idInt64) > 0 {
+ tryMessageTypes := []string{"group", "guild", "guild_private"}
+ messageCopy := message // 创建message的副本
+ echo.AddMsgType(config.GetAppIDStr(), idInt64, tryMessageTypes[echo.GetMapping(idInt64)-1])
+ delay := config.GetSendDelay()
+ time.Sleep(time.Duration(delay) * time.Millisecond)
+ retmsg, _ = HandleSendMsg(client, api, apiv2, messageCopy)
+ }
}
+
return retmsg, nil
}
diff --git a/handlers/send_private_msg.go b/handlers/send_private_msg.go
index be98f276..dc9c801f 100644
--- a/handlers/send_private_msg.go
+++ b/handlers/send_private_msg.go
@@ -95,7 +95,11 @@ func HandleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open
echo.AddMsgType(config.GetAppIDStr(), idInt64, "group_private")
HandleSendPrivateMsg(client, api, apiv2, messageCopy)
}
+ } else {
+ // 特殊值代表不递归
+ echo.AddMapping(idInt64, 10)
}
+
var resp *dto.C2CMessageResponse
switch msgType {
//这里是pr上来的,我也不明白为什么私聊会出现group类型 猜测是为了匹配包含了groupid的私聊?
@@ -310,21 +314,26 @@ func HandleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open
default:
mylog.Printf("Unknown message type: %s", msgType)
}
- //重置递归类型
- if echo.GetMapping(idInt64) <= 0 {
- echo.AddMsgType(config.GetAppIDStr(), idInt64, "")
- }
- echo.AddMapping(idInt64, echo.GetMapping(idInt64)-1)
-
- //递归3次枚举类型
- if echo.GetMapping(idInt64) > 0 {
- tryMessageTypes := []string{"group", "guild", "guild_private"}
- messageCopy := message // 创建message的副本
- echo.AddMsgType(config.GetAppIDStr(), idInt64, tryMessageTypes[echo.GetMapping(idInt64)-1])
- delay := config.GetSendDelay()
- time.Sleep(time.Duration(delay) * time.Millisecond)
- retmsg, _ = HandleSendPrivateMsg(client, api, apiv2, messageCopy)
+
+ // 如果递归id不是10(不递归特殊值)
+ if echo.GetMapping(idInt64) != 10 {
+ //重置递归类型
+ if echo.GetMapping(idInt64) <= 0 {
+ echo.AddMsgType(config.GetAppIDStr(), idInt64, "")
+ }
+ echo.AddMapping(idInt64, echo.GetMapping(idInt64)-1)
+
+ //递归3次枚举类型
+ if echo.GetMapping(idInt64) > 0 {
+ tryMessageTypes := []string{"group", "guild", "guild_private"}
+ messageCopy := message // 创建message的副本
+ echo.AddMsgType(config.GetAppIDStr(), idInt64, tryMessageTypes[echo.GetMapping(idInt64)-1])
+ delay := config.GetSendDelay()
+ time.Sleep(time.Duration(delay) * time.Millisecond)
+ retmsg, _ = HandleSendPrivateMsg(client, api, apiv2, messageCopy)
+ }
}
+
return retmsg, nil
}
From 40f832c2180fbd8f487c135c12124317ae636b8a Mon Sep 17 00:00:00 2001
From: cosmo
Date: Mon, 15 Apr 2024 13:57:56 +0800
Subject: [PATCH 25/33] beta360
---
botstats/botstats.go | 123 ++++++++++++++++++++++
config/config.go | 37 +++++++
handlers/get_status.go | 27 +++--
handlers/message_parser.go | 152 ++++++++++++++++++++++++---
handlers/send_group_forward_msg.go | 2 +-
handlers/send_group_msg.go | 23 +++-
handlers/send_group_msg_raw.go | 8 +-
handlers/send_guild_channel_forum.go | 2 +-
httpapi/httpapi.go | 2 +-
main.go | 11 ++
template/config_template.go | 5 +-
wsclient/ws.go | 13 ++-
12 files changed, 362 insertions(+), 43 deletions(-)
create mode 100644 botstats/botstats.go
diff --git a/botstats/botstats.go b/botstats/botstats.go
new file mode 100644
index 00000000..b4af3c47
--- /dev/null
+++ b/botstats/botstats.go
@@ -0,0 +1,123 @@
+package botstats
+
+import (
+ "log"
+ "strconv"
+ "strings"
+ "time"
+
+ "go.etcd.io/bbolt"
+)
+
+var db *bbolt.DB
+
+const (
+ bucketName = "stats"
+)
+
+func InitializeDB() {
+ var err error
+ db, err = bbolt.Open("botstats.db", 0600, nil)
+ if err != nil {
+ log.Fatalf("Failed to open database: %v", err)
+ }
+
+ db.Update(func(tx *bbolt.Tx) error {
+ _, err := tx.CreateBucketIfNotExists([]byte(bucketName))
+ if err != nil {
+ return err
+ }
+ return nil
+ })
+}
+
+const (
+ messageReceivedKey = "messageReceived"
+ messageSentKey = "messageSent"
+ lastMessageTimeKey = "lastMessageTime"
+)
+
+func RecordMessageReceived() {
+ recordStats(1, 0)
+}
+
+func RecordMessageSent() {
+ recordStats(0, 1)
+}
+
+// 收到增量 发出增量
+func recordStats(receivedIncrement int, sentIncrement int) {
+ db.Update(func(tx *bbolt.Tx) error {
+ b := tx.Bucket([]byte(bucketName))
+ now := time.Now()
+ today := now.Format("2006-01-02")
+
+ // Reset stats if not the current day
+ lastTimeBytes := b.Get([]byte(lastMessageTimeKey))
+ if lastTimeBytes != nil && !strings.HasPrefix(string(lastTimeBytes), today) {
+ b.Put([]byte(messageReceivedKey), []byte("0"))
+ b.Put([]byte(messageSentKey), []byte("0"))
+ }
+
+ updateCounter(b, messageReceivedKey, receivedIncrement)
+ updateCounter(b, messageSentKey, sentIncrement)
+ b.Put([]byte(lastMessageTimeKey), []byte(today+" "+now.Format(time.RFC3339)))
+
+ return nil
+ })
+}
+
+func updateCounter(b *bbolt.Bucket, key string, increment int) {
+ currentValueBytes := b.Get([]byte(key))
+ currentValue := 0
+ if currentValueBytes != nil {
+ currentValue, _ = strconv.Atoi(string(currentValueBytes))
+ }
+ newValue := currentValue + increment
+ b.Put([]byte(key), []byte(strconv.Itoa(newValue)))
+}
+
+// 获取 收到 发出 上次收到Time 错误
+func GetStats() (int, int, int64, error) {
+ var messageReceived, messageSent int
+ var lastMessageTime int64
+ err := db.View(func(tx *bbolt.Tx) error {
+ b := tx.Bucket([]byte(bucketName))
+ messageReceived = getInt(b, messageReceivedKey)
+ messageSent = getInt(b, messageSentKey)
+ lastMessageTime = getLastMessageTime(b)
+ return nil
+ })
+ return messageReceived, messageSent, lastMessageTime, err
+}
+
+func getInt(b *bbolt.Bucket, key string) int {
+ valueBytes := b.Get([]byte(key))
+ value, _ := strconv.Atoi(string(valueBytes))
+ return value
+}
+
+func getLastMessageTime(b *bbolt.Bucket) int64 {
+ lastTimeBytes := b.Get([]byte("lastMessageTimeKey")) // 确保使用正确的键
+ if lastTimeBytes == nil {
+ return 0 // 如果键不存在或值为空,直接返回0
+ }
+
+ // 将字节切片转换为字符串,并尝试按空格分割
+ splitResult := strings.Split(string(lastTimeBytes), " ")
+ if len(splitResult) < 2 {
+ return 0 // 如果没有足够的分割结果,返回0
+ }
+
+ // 安全地解析时间
+ lastTime, err := time.Parse(time.RFC3339, splitResult[1])
+ if err != nil {
+ return 0 // 如果解析时间出错,返回0
+ }
+
+ return lastTime.Unix() // 返回Unix时间戳
+}
+
+func CloseDB() {
+ db.Close()
+}
diff --git a/config/config.go b/config/config.go
index d10feda5..a3420674 100644
--- a/config/config.go
+++ b/config/config.go
@@ -111,7 +111,10 @@ type Settings struct {
BlackPrefixs []string `yaml:"black_prefixs"`
Alias []string `yaml:"alias"`
Enters []string `yaml:"enters"`
+ EntersExcept []string `yaml:"enters_except"`
VisualPrefixs []VisualPrefixConfig `yaml:"visual_prefixs"`
+ AutoWithdraw []string `yaml:"auto_withdraw"`
+ AutoWithdrawTime int `yaml:"auto_withdraw_time"`
//开发增强类
DevlopAcDir string `yaml:"develop_access_token_dir"`
DevBotid string `yaml:"develop_bot_id"`
@@ -1955,6 +1958,16 @@ func GetEnters() []string {
return nil // 返回nil,如果instance为nil
}
+// 获取EntersExcept
+func GetEntersExcept() []string {
+ mu.Lock()
+ defer mu.Unlock()
+ if instance != nil {
+ return instance.Settings.EntersExcept
+ }
+ return nil // 返回nil,如果instance为nil
+}
+
// 获取 LinkPrefix
func GetLinkPrefix() string {
mu.Lock()
@@ -2216,3 +2229,27 @@ func GetUploadPicV2Base64() bool {
}
return instance.Settings.UploadPicV2Base64
}
+
+// 获取 AutoWithdraw 数组
+func GetAutoWithdraw() []string {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to get AutoWithdraw.")
+ return nil
+ }
+ return instance.Settings.AutoWithdraw
+}
+
+// 获取 GetAutoWithdrawTime 数量
+func GetAutoWithdrawTime() int {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to get AutoWithdrawTime.")
+ return 0
+ }
+ return instance.Settings.AutoWithdrawTime
+}
diff --git a/handlers/get_status.go b/handlers/get_status.go
index b668d3e6..86483276 100644
--- a/handlers/get_status.go
+++ b/handlers/get_status.go
@@ -3,6 +3,7 @@ package handlers
import (
"encoding/json"
+ "github.com/hoshinonyaruko/gensokyo/botstats"
"github.com/hoshinonyaruko/gensokyo/callapi"
"github.com/hoshinonyaruko/gensokyo/mylog"
"github.com/tencent-connect/botgo/openapi"
@@ -30,8 +31,8 @@ type Statistics struct {
PacketReceived uint64 `json:"packet_received"`
PacketSent uint64 `json:"packet_sent"`
PacketLost uint32 `json:"packet_lost"`
- MessageReceived uint64 `json:"message_received"`
- MessageSent uint64 `json:"message_sent"`
+ MessageReceived int `json:"message_received"`
+ MessageSent int `json:"message_sent"`
DisconnectTimes uint32 `json:"disconnect_times"`
LostTimes uint32 `json:"lost_times"`
LastMessageTime int64 `json:"last_message_time"`
@@ -45,6 +46,10 @@ func GetStatus(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI
var response GetStatusResponse
+ messageReceived, messageSent, lastMessageTime, err := botstats.GetStats()
+ if err != nil {
+ mylog.Printf("get_status错误,获取机器人发信状态错误:%v", err)
+ }
response.Data = StatusData{
AppInitialized: true,
AppEnabled: true,
@@ -53,14 +58,14 @@ func GetStatus(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI
Online: true, //测试数据
Good: true, //测试数据
Stat: Statistics{
- PacketReceived: 1000, //测试数据
- PacketSent: 950, //测试数据
- PacketLost: 50, //测试数据
- MessageReceived: 500, //测试数据
- MessageSent: 490, //测试数据
- DisconnectTimes: 5, //测试数据
- LostTimes: 2, //测试数据
- LastMessageTime: 1677721600, //测试数据
+ PacketReceived: 1000, //测试数据
+ PacketSent: 950, //测试数据
+ PacketLost: 50, //测试数据
+ MessageReceived: messageReceived, //实际数据
+ MessageSent: messageSent, //实际数据
+ DisconnectTimes: 5, //测试数据
+ LostTimes: 2, //测试数据
+ LastMessageTime: lastMessageTime, //实际数据
},
}
response.Message = ""
@@ -72,7 +77,7 @@ func GetStatus(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI
mylog.Printf("get_status: %+v\n", outputMap)
- err := client.SendMessage(outputMap)
+ err = client.SendMessage(outputMap)
if err != nil {
mylog.Printf("Error sending message via client: %v", err)
}
diff --git a/handlers/message_parser.go b/handlers/message_parser.go
index 20884de2..5fcae8c3 100644
--- a/handlers/message_parser.go
+++ b/handlers/message_parser.go
@@ -17,6 +17,7 @@ import (
"strings"
"time"
+ "github.com/hoshinonyaruko/gensokyo/botstats"
"github.com/hoshinonyaruko/gensokyo/callapi"
"github.com/hoshinonyaruko/gensokyo/config"
"github.com/hoshinonyaruko/gensokyo/echo"
@@ -50,10 +51,96 @@ type ServerResponse struct {
Echo interface{} `json:"echo"`
}
+// 定义了一个符合 Client 接口的 HttpAPIClient 结构体
+type HttpAPIClient struct {
+ // 可添加所需字段
+}
+
+// 实现 Client 接口的 SendMessage 方法
+// 假client中不执行任何操作,只是返回 nil 来符合接口要求
+func (c *HttpAPIClient) SendMessage(message map[string]interface{}) error {
+ // 不实际发送消息
+ // log.Printf("SendMessage called with: %v", message)
+
+ // 返回nil占位符
+ return nil
+}
+
// 发送成功回执 todo 返回可互转的messageid 实现群撤回api
-func SendResponse(client callapi.Client, err error, message *callapi.ActionMessage, resp *dto.GroupMessageResponse) (string, error) {
+func SendResponse(client callapi.Client, err error, message *callapi.ActionMessage, resp *dto.GroupMessageResponse, api openapi.OpenAPI, apiv2 openapi.OpenAPI) (string, error) {
var messageID64 int64
var mapErr error
+
+ // 转换群号
+ var errr error
+ var GroupID64 int64
+ if groupID, ok := message.Params.GroupID.(string); ok && groupID != "" {
+ if config.GetIdmapPro() {
+ //将真实id转为int userid64
+ GroupID64, _, errr = idmap.StoreIDv2Pro(message.Params.GroupID.(string), message.Params.UserID.(string))
+ if errr != nil {
+ mylog.Fatalf("Error storing ID: %v", err)
+ }
+ } else {
+ // 映射str的GroupID到int
+ GroupID64, errr = idmap.StoreIDv2(message.Params.GroupID.(string))
+ if errr != nil {
+ mylog.Errorf("failed to convert GroupID64 to int: %v", err)
+ }
+ }
+ }
+
+ var channelID64 int64
+ if channelID, ok := message.Params.ChannelID.(string); ok && channelID != "" {
+ if config.GetIdmapPro() {
+ //将真实id转为int userid64
+ channelID64, _, errr = idmap.StoreIDv2Pro(message.Params.ChannelID.(string), message.Params.UserID.(string))
+ if errr != nil {
+ mylog.Fatalf("Error storing ID: %v", err)
+ }
+ } else {
+ // 映射str的GroupID到int
+ channelID64, errr = idmap.StoreIDv2(message.Params.ChannelID.(string))
+ if errr != nil {
+ mylog.Errorf("failed to convert GroupID64 to int: %v", err)
+ }
+ }
+ }
+
+ var guildID64 int64
+ if guildID, ok := message.Params.GuildID.(string); ok && guildID != "" {
+ if config.GetIdmapPro() {
+ //将真实id转为int userid64
+ guildID64, _, errr = idmap.StoreIDv2Pro(message.Params.GuildID.(string), message.Params.UserID.(string))
+ if errr != nil {
+ mylog.Fatalf("Error storing ID: %v", err)
+ }
+ } else {
+ // 映射str的GroupID到int
+ guildID64, errr = idmap.StoreIDv2(message.Params.GuildID.(string))
+ if errr != nil {
+ mylog.Errorf("failed to convert GroupID64 to int: %v", err)
+ }
+ }
+ }
+
+ var userID64 int64
+ if userID, ok := message.Params.UserID.(string); ok && userID != "" {
+ if config.GetIdmapPro() {
+ //将真实id转为int userid64
+ userID64, _, errr = idmap.StoreIDv2Pro("group_private", message.Params.UserID.(string))
+ if errr != nil {
+ mylog.Fatalf("Error storing ID: %v", err)
+ }
+ } else {
+ // 映射str的GroupID到int
+ userID64, errr = idmap.StoreIDv2(message.Params.UserID.(string))
+ if errr != nil {
+ mylog.Errorf("failed to convert GroupID64 to int: %v", err)
+ }
+ }
+ }
+
// 设置响应值
response := ServerResponse{}
if resp != nil {
@@ -63,27 +150,60 @@ func SendResponse(client callapi.Client, err error, message *callapi.ActionMessa
return "", nil
}
response.Data.MessageID = int(messageID64)
+ // 发送成功 增加今日发信息数
+ botstats.RecordMessageSent()
+ // 是否自动撤回
+ if echoStr, ok := message.Echo.(string); ok {
+ msg_on_touch := echo.GetMsgIDv3(config.GetAppIDStr(), echoStr)
+ // 检查是否需要自动撤回
+ autoWithdrawPrefixes := config.GetAutoWithdraw()
+ if len(autoWithdrawPrefixes) > 0 {
+ for _, prefix := range autoWithdrawPrefixes {
+ if strings.HasPrefix(msg_on_touch, prefix) {
+ go func() {
+ delay := config.GetAutoWithdrawTime() // 获取延迟时间
+ time.Sleep(time.Duration(delay) * time.Second)
+
+ // 构建参数
+ var params callapi.ParamsContent
+ if groupID, ok := message.Params.GroupID.(string); ok && groupID != "" {
+ params.GroupID = strconv.FormatInt(GroupID64, 10)
+ } else if channelID, ok := message.Params.ChannelID.(string); ok && channelID != "" {
+ params.ChannelID = strconv.FormatInt(channelID64, 10)
+ } else if guildID, ok := message.Params.GuildID.(string); ok && guildID != "" {
+ params.GuildID = strconv.FormatInt(guildID64, 10)
+ } else if userID, ok := message.Params.UserID.(string); ok && userID != "" {
+ params.UserID = strconv.FormatInt(userID64, 10)
+ } else {
+ return // 如果没有有效的参数,则退出
+ }
+ params.MessageID = strconv.FormatInt(messageID64, 10)
+
+ // 创建撤回消息的请求
+ deleteMessage := callapi.ActionMessage{
+ Action: "delete_msg",
+ Params: params,
+ }
+
+ // 调用删除消息函数
+ client := &HttpAPIClient{}
+ _, err := DeleteMsg(client, api, apiv2, deleteMessage)
+ if err != nil {
+ mylog.Printf("Error DeleteMsg: %v", err)
+ }
+ }()
+ break
+ }
+ }
+ }
+ }
} else {
// Default ID handling
response.Data.MessageID = 123
}
- var errr error
- var GroupID64 int64
- if config.GetIdmapPro() {
- //将真实id转为int userid64
- GroupID64, _, errr = idmap.StoreIDv2Pro(message.Params.GroupID.(string), message.Params.UserID.(string))
- if errr != nil {
- mylog.Fatalf("Error storing ID: %v", err)
- }
- } else {
- // 映射str的GroupID到int
- GroupID64, errr = idmap.StoreIDv2(message.Params.GroupID.(string))
- if errr != nil {
- mylog.Errorf("failed to convert GroupID64 to int: %v", err)
- }
- }
//mylog.Printf("convert GroupID64 to int: %v", GroupID64) 测试
+ // TODO: 改为动态参数 不是固定GroupID 但应用端不支持.会报错.暂时统一从group取id,自己判断类型发撤回请求.
response.GroupID = GroupID64
response.Echo = message.Echo
if err != nil {
diff --git a/handlers/send_group_forward_msg.go b/handlers/send_group_forward_msg.go
index 6795e931..f89fa9f0 100644
--- a/handlers/send_group_forward_msg.go
+++ b/handlers/send_group_forward_msg.go
@@ -66,6 +66,6 @@ func HandleSendGroupForwardMsg(client callapi.Client, api openapi.OpenAPI, apiv2
count++
time.Sleep(500 * time.Millisecond) // 每条消息之间的延时
}
- retmsg, _ = SendResponse(client, nil, &message, nil)
+ retmsg, _ = SendResponse(client, nil, &message, nil, api, apiv2)
return retmsg, nil
}
diff --git a/handlers/send_group_msg.go b/handlers/send_group_msg.go
index 23c5d30d..b99b26a0 100644
--- a/handlers/send_group_msg.go
+++ b/handlers/send_group_msg.go
@@ -313,7 +313,7 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
}
// 发送成功回执
- retmsg, _ = SendResponse(client, err, &message, resp)
+ retmsg, _ = SendResponse(client, err, &message, resp, api, apiv2)
delete(foundItems, imageType) // 从foundItems中删除已处理的图片项
messageText = ""
@@ -346,7 +346,7 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
echo.PushGlobalStack(pair)
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message, resp)
+ retmsg, _ = SendResponse(client, err, &message, resp, api, apiv2)
}
var resp *dto.GroupMessageResponse
// 遍历foundItems并发送每种信息
@@ -382,7 +382,7 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
echo.PushGlobalStack(pair)
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message, resp)
+ retmsg, _ = SendResponse(client, err, &message, resp, api, apiv2)
}
continue // 跳过这个项,继续下一个
}
@@ -442,7 +442,7 @@ func HandleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap
}
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message, resp)
+ retmsg, _ = SendResponse(client, err, &message, resp, api, apiv2)
}
}
case "guild":
@@ -1278,6 +1278,10 @@ func auto_md(message callapi.ActionMessage, messageText string, richMediaMessage
var actiondata string
//检查是否设置了enter数组
enter := checkDataLabelPrefix(dataLabel)
+ //例外规则
+ if checkDataLabelPrefixExcept(whiteLabel) {
+ enter = false
+ }
switch {
case strings.HasPrefix(whiteLabel, "邀请机器人"): //默认是群
@@ -1419,3 +1423,14 @@ func checkDataLabelPrefix(dataLabel string) bool {
}
return false
}
+
+// 检查whiteLabel是否以config中getentersexcept返回的任一字符串开头
+func checkDataLabelPrefixExcept(whiteLabel string) bool {
+ enters := config.GetEntersExcept()
+ for _, enter := range enters {
+ if enter != "" && strings.HasPrefix(whiteLabel, enter) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/handlers/send_group_msg_raw.go b/handlers/send_group_msg_raw.go
index f08ac062..893839cf 100644
--- a/handlers/send_group_msg_raw.go
+++ b/handlers/send_group_msg_raw.go
@@ -273,7 +273,7 @@ func HandleSendGroupMsgRaw(client callapi.Client, api openapi.OpenAPI, apiv2 ope
}
// 发送成功回执
- retmsg, _ = SendResponse(client, err, &message, resp)
+ retmsg, _ = SendResponse(client, err, &message, resp, api, apiv2)
delete(foundItems, imageType) // 从foundItems中删除已处理的图片项
messageText = ""
@@ -306,7 +306,7 @@ func HandleSendGroupMsgRaw(client callapi.Client, api openapi.OpenAPI, apiv2 ope
echo.PushGlobalStack(pair)
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message, resp)
+ retmsg, _ = SendResponse(client, err, &message, resp, api, apiv2)
}
var resp *dto.GroupMessageResponse
// 遍历foundItems并发送每种信息
@@ -342,7 +342,7 @@ func HandleSendGroupMsgRaw(client callapi.Client, api openapi.OpenAPI, apiv2 ope
echo.PushGlobalStack(pair)
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message, resp)
+ retmsg, _ = SendResponse(client, err, &message, resp, api, apiv2)
}
continue // 跳过这个项,继续下一个
}
@@ -402,7 +402,7 @@ func HandleSendGroupMsgRaw(client callapi.Client, api openapi.OpenAPI, apiv2 ope
}
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message, resp)
+ retmsg, _ = SendResponse(client, err, &message, resp, api, apiv2)
}
}
case "guild":
diff --git a/handlers/send_guild_channel_forum.go b/handlers/send_guild_channel_forum.go
index fd686c48..b4ed7720 100644
--- a/handlers/send_guild_channel_forum.go
+++ b/handlers/send_guild_channel_forum.go
@@ -101,7 +101,7 @@ func HandleSendGuildChannelForum(client callapi.Client, api openapi.OpenAPI, api
}
//发送成功回执
- retmsg, _ = SendResponse(client, err, &message, nil)
+ retmsg, _ = SendResponse(client, err, &message, nil, api, apiv2)
default:
mylog.Printf("2Unknown message type: %s", msgType)
diff --git a/httpapi/httpapi.go b/httpapi/httpapi.go
index 96dd7dc9..9bbb8642 100644
--- a/httpapi/httpapi.go
+++ b/httpapi/httpapi.go
@@ -8,10 +8,10 @@ import (
"strings"
"github.com/hoshinonyaruko/gensokyo/config"
+ "github.com/hoshinonyaruko/gensokyo/handlers"
"github.com/gin-gonic/gin"
"github.com/hoshinonyaruko/gensokyo/callapi"
- "github.com/hoshinonyaruko/gensokyo/handlers"
"github.com/tencent-connect/botgo/openapi"
)
diff --git a/main.go b/main.go
index 6dd281e0..11258e74 100644
--- a/main.go
+++ b/main.go
@@ -17,6 +17,7 @@ import (
"github.com/fatih/color"
"github.com/hoshinonyaruko/gensokyo/Processor"
+ "github.com/hoshinonyaruko/gensokyo/botstats"
"github.com/hoshinonyaruko/gensokyo/config"
"github.com/hoshinonyaruko/gensokyo/handlers"
"github.com/hoshinonyaruko/gensokyo/httpapi"
@@ -298,9 +299,14 @@ func main() {
//创建idmap服务器 数据库
idmap.InitializeDB()
+ //创建botstats数据库
+ botstats.InitializeDB()
//创建webui数据库
webui.InitializeDB()
+
+ //关闭时候释放数据库
defer idmap.CloseDB()
+ defer botstats.CloseDB()
defer webui.CloseDB()
//图片上传 调用次数限制
@@ -519,6 +525,7 @@ func ErrorNotifyHandler() event.ErrorNotifyHandler {
// ATMessageEventHandler 实现处理 频道at 消息的回调
func ATMessageEventHandler() event.ATMessageEventHandler {
return func(event *dto.WSPayload, data *dto.WSATMessageData) error {
+ botstats.RecordMessageReceived()
return p.ProcessGuildATMessage(data)
}
}
@@ -550,6 +557,7 @@ func MemberEventHandler() event.GuildMemberEventHandler {
// DirectMessageHandler 处理私信事件
func DirectMessageHandler() event.DirectMessageEventHandler {
return func(event *dto.WSPayload, data *dto.WSDirectMessageData) error {
+ botstats.RecordMessageReceived()
return p.ProcessChannelDirectMessage(data)
}
}
@@ -557,6 +565,7 @@ func DirectMessageHandler() event.DirectMessageEventHandler {
// CreateMessageHandler 处理消息事件 私域的事件 不at信息
func CreateMessageHandler() event.MessageEventHandler {
return func(event *dto.WSPayload, data *dto.WSMessageData) error {
+ botstats.RecordMessageReceived()
return p.ProcessGuildNormalMessage(data)
}
}
@@ -580,6 +589,7 @@ func ThreadEventHandler() event.ThreadEventHandler {
// GroupATMessageEventHandler 实现处理 群at 消息的回调
func GroupATMessageEventHandler() event.GroupATMessageEventHandler {
return func(event *dto.WSPayload, data *dto.WSGroupATMessageData) error {
+ botstats.RecordMessageReceived()
return p.ProcessGroupMessage(data)
}
}
@@ -587,6 +597,7 @@ func GroupATMessageEventHandler() event.GroupATMessageEventHandler {
// C2CMessageEventHandler 实现处理 群私聊 消息的回调
func C2CMessageEventHandler() event.C2CMessageEventHandler {
return func(event *dto.WSPayload, data *dto.WSC2CMessageData) error {
+ botstats.RecordMessageReceived()
return p.ProcessC2CMessage(data)
}
}
diff --git a/template/config_template.go b/template/config_template.go
index 76c9fc7f..10cbda4e 100644
--- a/template/config_template.go
+++ b/template/config_template.go
@@ -7,7 +7,7 @@ settings:
ws_address: ["ws://:"] # WebSocket服务的地址 支持多个["","",""]
ws_token: ["","",""] #连接wss地址时服务器所需的token,按顺序一一对应,如果是ws地址,没有密钥,请留空.
reconnect_times : 100 #反向ws连接失败后的重试次数,希望一直重试,可设置9999
- heart_beat_interval : 10 #反向ws心跳间隔 单位秒 推荐5-10
+ heart_beat_interval : 5 #反向ws心跳间隔 单位秒 推荐5-10
launch_reconnect_times : 1 #启动时尝试反向ws连接次数,建议先打开应用端再开启gensokyo,因为启动时连接会阻塞webui启动,默认只连接一次,可自行增大
#基础设置
@@ -107,6 +107,9 @@ settings:
black_prefixs : [""] #可设置多个 比如设置 查询 则查询开头的信息均被拦截 防止审核失败
alias : ["",""] #两两成对,指令替换,"a","b","c","d"代表将a开头替换为b开头,c开头替换为d开头.
enters : ["",""] #自动md卡片点击直接触发,小众功能,满足以下条件:应用端支持双向echo+设置了visual_prefixs和whiteList
+ enters_except : ["",""] #自动md卡片点击直接触发,例外,对子按钮生效.
+ auto_withdraw : [] #仅当应用端实现了双向echo可用.实现不难,可以去找对应开发者去提需求.
+ auto_withdraw_time : 30 #30秒
visual_prefixs : #虚拟前缀 与white_prefixs配合使用 处理流程自动忽略该前缀 remove_prefix remove_at 需为true时生效
- prefix: "" #虚拟前缀开头 例 你有3个指令 帮助 测试 查询 将 prefix 设置为 工具类 后 则可通过 工具类 帮助 触发机器人
diff --git a/wsclient/ws.go b/wsclient/ws.go
index 5227ffa2..318c8350 100644
--- a/wsclient/ws.go
+++ b/wsclient/ws.go
@@ -10,6 +10,7 @@ import (
"time"
"github.com/gorilla/websocket"
+ "github.com/hoshinonyaruko/gensokyo/botstats"
"github.com/hoshinonyaruko/gensokyo/callapi"
"github.com/hoshinonyaruko/gensokyo/config"
"github.com/hoshinonyaruko/gensokyo/mylog"
@@ -214,6 +215,10 @@ func (client *WebSocketClient) sendHeartbeat(ctx context.Context, botID uint64,
case <-ctx.Done():
return
case <-time.After(time.Duration(heartbeatinterval) * time.Second):
+ messageReceived, messageSent, lastMessageTime, err := botstats.GetStats()
+ if err != nil {
+ mylog.Printf("心跳错误,获取机器人发信状态错误:%v", err)
+ }
message := map[string]interface{}{
"post_type": "meta_event",
"meta_event_type": "heartbeat",
@@ -230,14 +235,14 @@ func (client *WebSocketClient) sendHeartbeat(ctx context.Context, botID uint64,
"packet_received": 34933,
"packet_sent": 8513,
"packet_lost": 0,
- "message_received": 24674,
- "message_sent": 1663,
+ "message_received": messageReceived,
+ "message_sent": messageSent,
"disconnect_times": 0,
"lost_times": 0,
- "last_message_time": int(time.Now().Unix()) - 10, // 假设最后一条消息是10秒前收到的
+ "last_message_time": int(lastMessageTime),
},
},
- "interval": 10000, // 以毫秒为单位
+ "interval": 5000, // 以毫秒为单位
}
client.SendMessage(message)
// 重发失败的消息
From a9afc91f349b545729a2fa28938e671d8a08f52c Mon Sep 17 00:00:00 2001
From: cosmo
Date: Tue, 16 Apr 2024 20:30:57 +0800
Subject: [PATCH 26/33] beta361
---
handlers/message_parser.go | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/handlers/message_parser.go b/handlers/message_parser.go
index 5fcae8c3..c9f67183 100644
--- a/handlers/message_parser.go
+++ b/handlers/message_parser.go
@@ -250,6 +250,8 @@ func SendGuildResponse(client callapi.Client, err error, message *callapi.Action
return "", nil
}
response.Data.MessageID = int(messageID64)
+ // 发送成功 增加今日发信息数
+ botstats.RecordMessageSent()
} else {
// Default ID handling
response.Data.MessageID = 123
@@ -306,6 +308,8 @@ func SendC2CResponse(client callapi.Client, err error, message *callapi.ActionMe
return "", nil
}
response.Data.MessageID = int(messageID64)
+ // 发送成功 增加今日发信息数
+ botstats.RecordMessageSent()
} else {
// Default ID handling
response.Data.MessageID = 123
From 16cef02a503517ae070bc5a2260362c888e3809e Mon Sep 17 00:00:00 2001
From: cosmo
Date: Tue, 16 Apr 2024 21:10:30 +0800
Subject: [PATCH 27/33] beta362
---
botstats/botstats.go | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/botstats/botstats.go b/botstats/botstats.go
index b4af3c47..c62b376d 100644
--- a/botstats/botstats.go
+++ b/botstats/botstats.go
@@ -61,7 +61,8 @@ func recordStats(receivedIncrement int, sentIncrement int) {
updateCounter(b, messageReceivedKey, receivedIncrement)
updateCounter(b, messageSentKey, sentIncrement)
- b.Put([]byte(lastMessageTimeKey), []byte(today+" "+now.Format(time.RFC3339)))
+ // Ensure the time format is RFC3339 and only store date and time
+ b.Put([]byte(lastMessageTimeKey), []byte(now.Format(time.RFC3339)))
return nil
})
@@ -98,19 +99,13 @@ func getInt(b *bbolt.Bucket, key string) int {
}
func getLastMessageTime(b *bbolt.Bucket) int64 {
- lastTimeBytes := b.Get([]byte("lastMessageTimeKey")) // 确保使用正确的键
+ lastTimeBytes := b.Get([]byte("lastMessageTime")) // 确保使用正确的键
if lastTimeBytes == nil {
return 0 // 如果键不存在或值为空,直接返回0
}
- // 将字节切片转换为字符串,并尝试按空格分割
- splitResult := strings.Split(string(lastTimeBytes), " ")
- if len(splitResult) < 2 {
- return 0 // 如果没有足够的分割结果,返回0
- }
-
// 安全地解析时间
- lastTime, err := time.Parse(time.RFC3339, splitResult[1])
+ lastTime, err := time.Parse(time.RFC3339, string(lastTimeBytes))
if err != nil {
return 0 // 如果解析时间出错,返回0
}
From 48aa4c7e353c87d90b7d06434cf5d064607a5532 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Wed, 17 Apr 2024 18:44:51 +0800
Subject: [PATCH 28/33] beta363
---
botstats/botstats.go | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/botstats/botstats.go b/botstats/botstats.go
index c62b376d..23429e05 100644
--- a/botstats/botstats.go
+++ b/botstats/botstats.go
@@ -1,11 +1,14 @@
package botstats
import (
+ "errors"
+ "fmt"
"log"
"strconv"
"strings"
"time"
+ "github.com/hoshinonyaruko/gensokyo/mylog"
"go.etcd.io/bbolt"
)
@@ -47,6 +50,10 @@ func RecordMessageSent() {
// 收到增量 发出增量
func recordStats(receivedIncrement int, sentIncrement int) {
+ if db == nil {
+ mylog.Printf("recordStats db is nil")
+ return
+ }
db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(bucketName))
now := time.Now()
@@ -82,14 +89,23 @@ func updateCounter(b *bbolt.Bucket, key string, increment int) {
func GetStats() (int, int, int64, error) {
var messageReceived, messageSent int
var lastMessageTime int64
+ if db == nil {
+ return 0, 0, 0, errors.New("database is not initialized")
+ }
err := db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(bucketName))
+ if b == nil {
+ return fmt.Errorf("bucket %s not found", bucketName)
+ }
messageReceived = getInt(b, messageReceivedKey)
messageSent = getInt(b, messageSentKey)
lastMessageTime = getLastMessageTime(b)
return nil
})
- return messageReceived, messageSent, lastMessageTime, err
+ if err != nil {
+ return 0, 0, 0, err
+ }
+ return messageReceived, messageSent, lastMessageTime, nil
}
func getInt(b *bbolt.Bucket, key string) int {
From f30fe85605c6d36ed44cf9d533bb0989ac726bc5 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Thu, 18 Apr 2024 11:51:02 +0800
Subject: [PATCH 29/33] beta365
---
Processor/ProcessC2CMessage.go | 11 ++++++++---
Processor/ProcessChannelDirectMessage.go | 23 +++++++++++++++--------
Processor/ProcessGroupMessage.go | 8 ++++++--
Processor/ProcessGuildATMessage.go | 17 +++++++++++++----
Processor/ProcessGuildNormalMessage.go | 12 ++++++++----
Processor/ProcessThreadMessage.go | 18 ++++++++++++------
6 files changed, 62 insertions(+), 27 deletions(-)
diff --git a/Processor/ProcessC2CMessage.go b/Processor/ProcessC2CMessage.go
index 465ae443..d23c6b29 100644
--- a/Processor/ProcessC2CMessage.go
+++ b/Processor/ProcessC2CMessage.go
@@ -34,7 +34,10 @@ func (p *Processors) ProcessC2CMessage(data *dto.WSC2CMessageData) error {
//转换appidstring
AppIDString := strconv.FormatUint(p.Settings.AppID, 10)
- echostr := AppIDString + "_" + strconv.FormatInt(s, 10)
+ // 获取当前时间的13位毫秒级时间戳
+ currentTimeMillis := time.Now().UnixNano() / 1e6
+ // 构造echostr,包括AppID,原始的s变量和当前时间戳
+ echostr := fmt.Sprintf("%s_%d_%d", AppIDString, s, currentTimeMillis)
var userid64 int64
var err error
if config.GetIdmapPro() {
@@ -148,8 +151,10 @@ func (p *Processors) ProcessC2CMessage(data *dto.WSC2CMessageData) error {
//转换appid
AppIDString := strconv.FormatUint(p.Settings.AppID, 10)
- //构造echo
- echostr := AppIDString + "_" + strconv.FormatInt(s, 10)
+ // 获取当前时间的13位毫秒级时间戳
+ currentTimeMillis := time.Now().UnixNano() / 1e6
+ // 构造echostr,包括AppID,原始的s变量和当前时间戳
+ echostr := fmt.Sprintf("%s_%d_%d", AppIDString, s, currentTimeMillis)
//把userid作为群号
//映射str的userid到int
var userid64 int64
diff --git a/Processor/ProcessChannelDirectMessage.go b/Processor/ProcessChannelDirectMessage.go
index e27faa94..6c705e33 100644
--- a/Processor/ProcessChannelDirectMessage.go
+++ b/Processor/ProcessChannelDirectMessage.go
@@ -35,7 +35,10 @@ func (p *Processors) ProcessChannelDirectMessage(data *dto.WSDirectMessageData)
//转换appidstring
AppIDString := strconv.FormatUint(p.Settings.AppID, 10)
- echostr := AppIDString + "_" + strconv.FormatInt(s, 10)
+ // 获取当前时间的13位毫秒级时间戳
+ currentTimeMillis := time.Now().UnixNano() / 1e6
+ // 构造echostr,包括AppID,原始的s变量和当前时间戳
+ echostr := fmt.Sprintf("%s_%d_%d", AppIDString, s, currentTimeMillis)
var userid64 int64
var ChannelID64 int64
@@ -183,8 +186,10 @@ func (p *Processors) ProcessChannelDirectMessage(data *dto.WSDirectMessageData)
p.HandleFrameworkCommand(messageText, data, "guild_private")
//转换appid
AppIDString := strconv.FormatUint(p.Settings.AppID, 10)
- //构造echo
- echostr := AppIDString + "_" + strconv.FormatInt(s, 10)
+ // 获取当前时间的13位毫秒级时间戳
+ currentTimeMillis := time.Now().UnixNano() / 1e6
+ // 构造echostr,包括AppID,原始的s变量和当前时间戳
+ echostr := fmt.Sprintf("%s_%d_%d", AppIDString, s, currentTimeMillis)
//映射str的userid到int
userid64, err := idmap.StoreIDv2(data.Author.ID)
if err != nil {
@@ -271,16 +276,16 @@ func (p *Processors) ProcessChannelDirectMessage(data *dto.WSDirectMessageData)
var err error
if config.GetIdmapPro() {
//将真实id转为int userid64
- _, _, err = idmap.StoreIDv2Pro(data.ChannelID, data.Author.ID)
+ ChannelID64, userid64, err = idmap.StoreIDv2Pro(data.ChannelID, data.Author.ID)
if err != nil {
mylog.Fatalf("Error storing ID: %v", err)
}
//将真实id转为int userid64
- userid64, err = idmap.StoreIDv2(data.Author.ID)
+ _, err = idmap.StoreIDv2(data.Author.ID)
if err != nil {
mylog.Fatalf("Error storing ID: %v", err)
}
- ChannelID64, err = idmap.StoreIDv2(data.ChannelID)
+ _, err = idmap.StoreIDv2(data.ChannelID)
if err != nil {
mylog.Printf("Error storing ID: %v", err)
return nil
@@ -319,8 +324,10 @@ func (p *Processors) ProcessChannelDirectMessage(data *dto.WSDirectMessageData)
p.HandleFrameworkCommand(messageText, data, "guild_private")
//转换appid
AppIDString := strconv.FormatUint(p.Settings.AppID, 10)
- //构造echo
- echostr := AppIDString + "_" + strconv.FormatInt(s, 10)
+ // 获取当前时间的13位毫秒级时间戳
+ currentTimeMillis := time.Now().UnixNano() / 1e6
+ // 构造echostr,包括AppID,原始的s变量和当前时间戳
+ echostr := fmt.Sprintf("%s_%d_%d", AppIDString, s, currentTimeMillis)
//userid := int(userid64)
//映射str的messageID到int
diff --git a/Processor/ProcessGroupMessage.go b/Processor/ProcessGroupMessage.go
index 620c8c5f..4631ab20 100644
--- a/Processor/ProcessGroupMessage.go
+++ b/Processor/ProcessGroupMessage.go
@@ -24,8 +24,12 @@ func (p *Processors) ProcessGroupMessage(data *dto.WSGroupATMessageData) error {
// 转换appid
AppIDString := strconv.FormatUint(p.Settings.AppID, 10)
- // 构造echo
- echostr := AppIDString + "_" + strconv.FormatInt(s, 10)
+ // 获取当前时间的13位毫秒级时间戳
+ currentTimeMillis := time.Now().UnixNano() / 1e6
+
+ // 构造echostr,包括AppID,原始的s变量和当前时间戳
+ echostr := fmt.Sprintf("%s_%d_%d", AppIDString, s, currentTimeMillis)
+
var userid64 int64
var GroupID64 int64
var err error
diff --git a/Processor/ProcessGuildATMessage.go b/Processor/ProcessGuildATMessage.go
index 1ccf0bdb..563da6d0 100644
--- a/Processor/ProcessGuildATMessage.go
+++ b/Processor/ProcessGuildATMessage.go
@@ -37,8 +37,12 @@ func (p *Processors) ProcessGuildATMessage(data *dto.WSATMessageData) error {
p.HandleFrameworkCommand(messageText, data, "guild")
//转换appid
AppIDString = strconv.FormatUint(p.Settings.AppID, 10)
- //构造echo
- echostr := AppIDString + "_" + strconv.FormatInt(s, 10)
+
+ // 获取当前时间的13位毫秒级时间戳
+ currentTimeMillis := time.Now().UnixNano() / 1e6
+ // 构造echostr,包括AppID,原始的s变量和当前时间戳
+ echostr := fmt.Sprintf("%s_%d_%d", AppIDString, s, currentTimeMillis)
+
//映射str的userid到int
userid64, err := idmap.StoreIDv2(data.Author.ID)
if err != nil {
@@ -177,8 +181,13 @@ func (p *Processors) ProcessGuildATMessage(data *dto.WSATMessageData) error {
p.HandleFrameworkCommand(messageText, data, "guild")
//转换appid
AppIDString := strconv.FormatUint(p.Settings.AppID, 10)
- //构造echo
- echostr := AppIDString + "_" + strconv.FormatInt(s, 10)
+
+ // 获取当前时间的13位毫秒级时间戳
+ currentTimeMillis := time.Now().UnixNano() / 1e6
+
+ // 构造echostr,包括AppID,原始的s变量和当前时间戳
+ echostr := fmt.Sprintf("%s_%d_%d", AppIDString, s, currentTimeMillis)
+
//映射str的messageID到int
messageID64, err := idmap.StoreIDv2(data.ID)
if err != nil {
diff --git a/Processor/ProcessGuildNormalMessage.go b/Processor/ProcessGuildNormalMessage.go
index 06a787aa..f3f01942 100644
--- a/Processor/ProcessGuildNormalMessage.go
+++ b/Processor/ProcessGuildNormalMessage.go
@@ -36,8 +36,10 @@ func (p *Processors) ProcessGuildNormalMessage(data *dto.WSMessageData) error {
p.HandleFrameworkCommand(messageText, data, "guild")
//转换appid
AppIDString = strconv.FormatUint(p.Settings.AppID, 10)
- //构造echo
- echostr := AppIDString + "_" + strconv.FormatInt(s, 10)
+ // 获取当前时间的13位毫秒级时间戳
+ currentTimeMillis := time.Now().UnixNano() / 1e6
+ // 构造echostr,包括AppID,原始的s变量和当前时间戳
+ echostr := fmt.Sprintf("%s_%d_%d", AppIDString, s, currentTimeMillis)
//映射str的userid到int
userid64, err := idmap.StoreIDv2(data.Author.ID)
if err != nil {
@@ -177,8 +179,10 @@ func (p *Processors) ProcessGuildNormalMessage(data *dto.WSMessageData) error {
p.HandleFrameworkCommand(messageText, data, "guild")
//转换appid
AppIDString := strconv.FormatUint(p.Settings.AppID, 10)
- //构造echo
- echostr := AppIDString + "_" + strconv.FormatInt(s, 10)
+ // 获取当前时间的13位毫秒级时间戳
+ currentTimeMillis := time.Now().UnixNano() / 1e6
+ // 构造echostr,包括AppID,原始的s变量和当前时间戳
+ echostr := fmt.Sprintf("%s_%d_%d", AppIDString, s, currentTimeMillis)
//映射str的messageID到int
messageID64, err := idmap.StoreIDv2(data.ID)
if err != nil {
diff --git a/Processor/ProcessThreadMessage.go b/Processor/ProcessThreadMessage.go
index c72934c0..9f61c27c 100644
--- a/Processor/ProcessThreadMessage.go
+++ b/Processor/ProcessThreadMessage.go
@@ -38,8 +38,10 @@ func (p *Processors) ProcessThreadMessage(data *dto.WSThreadData) error {
//帖子不需要
//转换appid
AppIDString := strconv.FormatUint(p.Settings.AppID, 10)
- //构造echo
- echostr := AppIDString + "_" + strconv.FormatInt(s, 10)
+ // 获取当前时间的13位毫秒级时间戳
+ currentTimeMillis := time.Now().UnixNano() / 1e6
+ // 构造echostr,包括AppID,原始的s变量和当前时间戳
+ echostr := fmt.Sprintf("%s_%d_%d", AppIDString, s, currentTimeMillis)
//映射str的userid到int
userid64, err := idmap.StoreIDv2(data.AuthorID)
if err != nil {
@@ -147,8 +149,10 @@ func (p *Processors) ProcessThreadMessage(data *dto.WSThreadData) error {
//帖子不需要
//转换appid
AppIDString := strconv.FormatUint(p.Settings.AppID, 10)
- //构造echo
- echostr := AppIDString + "_" + strconv.FormatInt(s, 10)
+ // 获取当前时间的13位毫秒级时间戳
+ currentTimeMillis := time.Now().UnixNano() / 1e6
+ // 构造echostr,包括AppID,原始的s变量和当前时间戳
+ echostr := fmt.Sprintf("%s_%d_%d", AppIDString, s, currentTimeMillis)
//映射str的userid到int
userid64, err := idmap.StoreIDv2(data.AuthorID)
if err != nil {
@@ -287,8 +291,10 @@ func (p *Processors) ProcessThreadMessage(data *dto.WSThreadData) error {
if err != nil {
mylog.Printf("Error parseContent Forum: %v", err)
}
- //构造echo
- echostr := AppIDString + "_" + strconv.FormatInt(s, 10)
+ // 获取当前时间的13位毫秒级时间戳
+ currentTimeMillis := time.Now().UnixNano() / 1e6
+ // 构造echostr,包括AppID,原始的s变量和当前时间戳
+ echostr := fmt.Sprintf("%s_%d_%d", AppIDString, s, currentTimeMillis)
//映射str的messageID到int
messageID64, err := idmap.StoreIDv2(data.ID)
if err != nil {
From a6c503dfe1c58ec73a4c2426df3a5df70701a14b Mon Sep 17 00:00:00 2001
From: cosmo
Date: Fri, 19 Apr 2024 15:32:53 +0800
Subject: [PATCH 30/33] beta366
---
Processor/ProcessC2CMessage.go | 21 ++++++++
handlers/get_friend_list.go | 34 ++++++------
httpapi/httpapi.go | 27 ++++++++++
idmap/service.go | 95 +++++++++++++++++++++++++++++-----
structs/structs.go | 7 +++
5 files changed, 152 insertions(+), 32 deletions(-)
create mode 100644 structs/structs.go
diff --git a/Processor/ProcessC2CMessage.go b/Processor/ProcessC2CMessage.go
index d23c6b29..69f69456 100644
--- a/Processor/ProcessC2CMessage.go
+++ b/Processor/ProcessC2CMessage.go
@@ -12,6 +12,7 @@ import (
"github.com/hoshinonyaruko/gensokyo/handlers"
"github.com/hoshinonyaruko/gensokyo/idmap"
"github.com/hoshinonyaruko/gensokyo/mylog"
+ "github.com/hoshinonyaruko/gensokyo/structs"
"github.com/tencent-connect/botgo/dto"
"github.com/tencent-connect/botgo/websocket/client"
)
@@ -146,6 +147,15 @@ func (p *Processors) ProcessC2CMessage(data *dto.WSC2CMessageData) error {
privateMsgMap := structToMap(privateMsg)
//上报信息到onebotv11应用端(正反ws)
p.BroadcastMessageToAll(privateMsgMap)
+ //组合FriendData
+ struserid := strconv.FormatInt(userid64, 10)
+ userdata := structs.FriendData{
+ Nickname: "",
+ Remark: "",
+ UserID: struserid,
+ }
+ //缓存私信好友列表
+ idmap.StoreUserInfo(data.Author.ID, userdata)
} else {
//将私聊信息转化为群信息(特殊需求情况下)
@@ -267,6 +277,17 @@ func (p *Processors) ProcessC2CMessage(data *dto.WSC2CMessageData) error {
groupMsgMap := structToMap(groupMsg)
//上报信息到onebotv11应用端(正反ws)
p.BroadcastMessageToAll(groupMsgMap)
+
+ //组合FriendData
+ struserid := strconv.FormatInt(userid64, 10)
+ userdata := structs.FriendData{
+ Nickname: "",
+ Remark: "",
+ UserID: struserid,
+ }
+ //缓存私信好友列表
+ idmap.StoreUserInfo(data.Author.ID, userdata)
}
+
return nil
}
diff --git a/handlers/get_friend_list.go b/handlers/get_friend_list.go
index e21f4ac7..d11a6370 100644
--- a/handlers/get_friend_list.go
+++ b/handlers/get_friend_list.go
@@ -4,7 +4,9 @@ import (
"encoding/json"
"github.com/hoshinonyaruko/gensokyo/callapi"
+ "github.com/hoshinonyaruko/gensokyo/idmap"
"github.com/hoshinonyaruko/gensokyo/mylog"
+ "github.com/hoshinonyaruko/gensokyo/structs"
"github.com/tencent-connect/botgo/openapi"
)
@@ -13,31 +15,25 @@ func init() {
}
type APIOutput struct {
- Data []FriendData `json:"data"`
- Message string `json:"message"`
- RetCode int `json:"retcode"`
- Status string `json:"status"`
- Echo interface{} `json:"echo"`
-}
-
-type FriendData struct {
- Nickname string `json:"nickname"`
- Remark string `json:"remark"`
- UserID string `json:"user_id"`
+ Data []structs.FriendData `json:"data"`
+ Message string `json:"message"`
+ RetCode int `json:"retcode"`
+ Status string `json:"status"`
+ Echo interface{} `json:"echo"`
}
func HandleGetFriendList(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) (string, error) {
var output APIOutput
- for i := 0; i < 10; i++ { // Assume we want to loop 10 times to create friend data
- data := FriendData{
- Nickname: "小狐狸",
- Remark: "",
- UserID: "2022717137",
- }
- output.Data = append(output.Data, data)
+ // 从数据库获取所有用户信息
+ users, err := idmap.ListAllUsers()
+ if err != nil {
+ mylog.Fatalf("Failed to list users: %v", err)
}
+ // 添加数据库中读取的用户数据到output.Data
+ output.Data = append(output.Data, users...)
+
output.Message = ""
output.RetCode = 0
output.Status = "ok"
@@ -48,7 +44,7 @@ func HandleGetFriendList(client callapi.Client, api openapi.OpenAPI, apiv2 opena
outputMap := structToMap(output)
// Send the map
- err := client.SendMessage(outputMap) //发回去
+ err = client.SendMessage(outputMap) //发回去
if err != nil {
mylog.Printf("error sending friend list via wsclient: %v", err)
}
diff --git a/httpapi/httpapi.go b/httpapi/httpapi.go
index 9bbb8642..cd5fe1d7 100644
--- a/httpapi/httpapi.go
+++ b/httpapi/httpapi.go
@@ -52,6 +52,10 @@ func CombinedMiddleware(api openapi.OpenAPI, apiV2 openapi.OpenAPI) gin.HandlerF
handleGetGroupList(c, api, apiV2)
return
}
+ if c.Request.URL.Path == "/get_friend_list" {
+ handleGetFriendList(c, api, apiV2)
+ return
+ }
if c.Request.URL.Path == "/put_interaction" {
handlePutInteraction(c, api, apiV2)
return
@@ -357,6 +361,29 @@ func handleGetGroupList(c *gin.Context, api openapi.OpenAPI, apiV2 openapi.OpenA
c.String(http.StatusOK, retmsg)
}
+// handleGetFriendList 处理获取好友列表
+func handleGetFriendList(c *gin.Context, api openapi.OpenAPI, apiV2 openapi.OpenAPI) {
+ var retmsg string
+
+ // 使用解析后的参数处理请求
+ client := &HttpAPIClient{}
+ // 创建 ActionMessage 实例
+ message := callapi.ActionMessage{
+ Action: "get_friend_list",
+ }
+
+ // 调用处理函数
+ retmsg, err := handlers.HandleGetFriendList(client, api, apiV2, message)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
+ return
+ }
+
+ // 返回处理结果
+ c.Header("Content-Type", "application/json")
+ c.String(http.StatusOK, retmsg)
+}
+
// handlePutInteraction 处理put_interaction的请求
func handlePutInteraction(c *gin.Context, api openapi.OpenAPI, apiV2 openapi.OpenAPI) {
var req struct {
diff --git a/idmap/service.go b/idmap/service.go
index 69590765..c080f83f 100644
--- a/idmap/service.go
+++ b/idmap/service.go
@@ -18,6 +18,7 @@ import (
"github.com/hoshinonyaruko/gensokyo/config"
"github.com/hoshinonyaruko/gensokyo/mylog"
+ "github.com/hoshinonyaruko/gensokyo/structs"
"go.etcd.io/bbolt"
)
@@ -29,10 +30,11 @@ var (
)
const (
- DBName = "idmap.db"
- BucketName = "ids"
- ConfigBucket = "config"
- CounterKey = "currentRow"
+ DBName = "idmap.db"
+ BucketName = "ids"
+ ConfigBucket = "config"
+ UserInfoBucket = "UserInfo"
+ CounterKey = "currentRow"
)
var db *bbolt.DB
@@ -41,15 +43,32 @@ var ErrKeyNotFound = errors.New("key not found")
func InitializeDB() {
var err error
+ // 打开数据库文件
db, err = bbolt.Open(DBName, 0600, nil)
if err != nil {
log.Fatalf("Error opening DB: %v", err)
}
- db.Update(func(tx *bbolt.Tx) error {
- _, err := tx.CreateBucketIfNotExists([]byte(BucketName))
- return err
+ // 在数据库中创建必要的buckets
+ err = db.Update(func(tx *bbolt.Tx) error {
+ // 创建默认的Bucket
+ if _, err := tx.CreateBucketIfNotExists([]byte(BucketName)); err != nil {
+ return err
+ }
+ // 创建存储用户信息的Bucket
+ if _, err := tx.CreateBucketIfNotExists([]byte(UserInfoBucket)); err != nil {
+ return err
+ }
+ // 创建配置数据的Bucket
+ if _, err := tx.CreateBucketIfNotExists([]byte(ConfigBucket)); err != nil {
+ return err
+ }
+ return nil
})
+
+ if err != nil {
+ log.Fatalf("Error setting up buckets: %v", err)
+ }
}
func CloseDB() {
@@ -530,19 +549,19 @@ func RetrieveRowByIDv2(rowid string) (string, error) {
// 根据a 以b为类别 储存c
func WriteConfig(sectionName, keyName, value string) error {
return db.Update(func(tx *bbolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte(ConfigBucket))
- if err != nil {
- mylog.Printf("Error creating or accessing bucket: %v", err)
- return fmt.Errorf("failed to access or create bucket %s: %w", ConfigBucket, err)
+ b := tx.Bucket([]byte(ConfigBucket)) // 直接获取bucket
+ if b == nil {
+ mylog.Printf("Bucket %s not found", ConfigBucket)
+ return fmt.Errorf("bucket %s not found", ConfigBucket)
}
key := joinSectionAndKey(sectionName, keyName)
- err = b.Put(key, []byte(value))
+ err := b.Put(key, []byte(value))
if err != nil {
mylog.Printf("Error putting data into bucket with key %s: %v", key, err)
return fmt.Errorf("failed to put data into bucket with key %s: %w", key, err)
}
- //mylog.Printf("Data saved successfully with key %s,value %s", key, value)
+ //log.Printf("Data saved successfully with key %s, value %s", key, value)
return nil
})
}
@@ -1311,3 +1330,53 @@ func UpdateKeysWithNewID(id, newID string) error {
return nil
})
}
+
+// StoreUserInfo 存储用户信息
+func StoreUserInfo(rawID string, userInfo structs.FriendData) error {
+ return db.Update(func(tx *bbolt.Tx) error {
+ b := tx.Bucket([]byte(UserInfoBucket))
+ key := fmt.Sprintf("%s:%s", rawID, userInfo.UserID) // 创建复合键
+ if v := b.Get([]byte(key)); v != nil {
+ return fmt.Errorf("duplicate key: %s", key)
+ }
+
+ // 序列化用户信息作为值
+ value, err := json.Marshal(userInfo)
+ if err != nil {
+ return fmt.Errorf("could not encode user info: %s", err)
+ }
+
+ // 存储键值对
+ if err := b.Put([]byte(key), value); err != nil {
+ return fmt.Errorf("could not store user info: %s", err)
+ }
+ return nil
+ })
+}
+
+// ListAllUsers 返回数据库中所有用户的信息
+func ListAllUsers() ([]structs.FriendData, error) {
+ var users []structs.FriendData
+ err := db.View(func(tx *bbolt.Tx) error {
+ b := tx.Bucket([]byte(UserInfoBucket))
+ if b == nil {
+ return fmt.Errorf("bucket %s not found", UserInfoBucket)
+ }
+
+ // 遍历bucket中的所有键值对
+ err := b.ForEach(func(key, value []byte) error {
+ var user structs.FriendData
+ if err := json.Unmarshal(value, &user); err != nil {
+ log.Printf("Error unmarshaling user data: %v", err)
+ return err
+ }
+ users = append(users, user)
+ return nil
+ })
+ return err
+ })
+ if err != nil {
+ return nil, err
+ }
+ return users, nil
+}
diff --git a/structs/structs.go b/structs/structs.go
new file mode 100644
index 00000000..9af3ed9a
--- /dev/null
+++ b/structs/structs.go
@@ -0,0 +1,7 @@
+package structs
+
+type FriendData struct {
+ Nickname string `json:"nickname"`
+ Remark string `json:"remark"`
+ UserID string `json:"user_id"`
+}
From 4976b9af788c68002bf9a085041d29cda98f04e7 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Mon, 22 Apr 2024 13:44:19 +0800
Subject: [PATCH 31/33] beta367
---
handlers/message_parser.go | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/handlers/message_parser.go b/handlers/message_parser.go
index c9f67183..dc2c388f 100644
--- a/handlers/message_parser.go
+++ b/handlers/message_parser.go
@@ -958,7 +958,11 @@ func RevertTransformedText(data interface{}, msgtype string, api openapi.OpenAPI
//如果二级指令白名单全部是*(忽略自身,那么不判断二级白名单是否匹配)
if allStarPrefixed {
- matched = true
+ if len(messageText) == len(matchedPrefix.Prefix) {
+ matched = true
+ } else {
+ matched = false
+ }
} else {
// 遍历白名单数组,检查是否有匹配项
for _, prefix := range allPrefixes {
@@ -975,6 +979,11 @@ func RevertTransformedText(data interface{}, msgtype string, api openapi.OpenAPI
// 从trimmedPrefix中去除前后空格(可能会有bug)
trimmedPrefix = strings.TrimSpace(trimmedPrefix)
+ if trimmedPrefix == "" {
+ matched = false
+ break
+ }
+
if strings.HasPrefix(messageText, trimmedPrefix) {
matched = true
break
From f4d67a0dc2590ca1c4f28598b8c4f017c8684717 Mon Sep 17 00:00:00 2001
From: cosmo
Date: Mon, 22 Apr 2024 20:07:05 +0800
Subject: [PATCH 32/33] beta368
---
handlers/message_parser.go | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/handlers/message_parser.go b/handlers/message_parser.go
index dc2c388f..70f9c62b 100644
--- a/handlers/message_parser.go
+++ b/handlers/message_parser.go
@@ -978,13 +978,8 @@ func RevertTransformedText(data interface{}, msgtype string, api openapi.OpenAPI
// 从trimmedPrefix中去除前后空格(可能会有bug)
trimmedPrefix = strings.TrimSpace(trimmedPrefix)
-
- if trimmedPrefix == "" {
- matched = false
- break
- }
-
- if strings.HasPrefix(messageText, trimmedPrefix) {
+ // trimmedPrefix如果是""就会导致任意内容都是true,所以不能是""
+ if strings.HasPrefix(messageText, trimmedPrefix) && trimmedPrefix != "" {
matched = true
break
}
From 8dec46c83797ac87499dfe36de90001b6fe6220a Mon Sep 17 00:00:00 2001
From: cosmo
Date: Thu, 25 Apr 2024 15:51:39 +0800
Subject: [PATCH 33/33] beta382
---
Processor/ProcessC2CMessage.go | 20 ++++++-
Processor/ProcessChannelDirectMessage.go | 27 ++++++++-
Processor/ProcessGroupAddBot.go | 14 ++++-
Processor/ProcessGroupDelBot.go | 9 ++-
Processor/ProcessGroupMessage.go | 9 ++-
Processor/ProcessGuildATMessage.go | 16 +++++-
Processor/ProcessGuildNormalMessage.go | 19 +++++-
Processor/ProcessInlineSearch.go | 26 +++++++--
Processor/ProcessThreadMessage.go | 28 ++++++++-
Processor/Processor.go | 8 ++-
config/config.go | 73 ++++++++++++++++++------
handlers/message_parser.go | 11 ++++
main.go | 8 ++-
server/wsserver.go | 8 ++-
template/config_template.go | 2 +
wsclient/ws.go | 6 +-
16 files changed, 238 insertions(+), 46 deletions(-)
diff --git a/Processor/ProcessC2CMessage.go b/Processor/ProcessC2CMessage.go
index 69f69456..c9945915 100644
--- a/Processor/ProcessC2CMessage.go
+++ b/Processor/ProcessC2CMessage.go
@@ -97,13 +97,21 @@ func (p *Processors) ProcessC2CMessage(data *dto.WSC2CMessageData) error {
} else {
IsBindedUserId = idmap.CheckValuev2(userid64)
}
+
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
+
privateMsg := OnebotPrivateMessage{
RawMessage: messageText,
Message: segmentedMessages,
MessageID: messageID,
MessageType: "private",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
Sender: PrivateSender{
Nickname: "", //这个不支持,但加机器人好友,会收到一个事件,可以对应储存获取,用idmaps可以做到.
@@ -205,6 +213,14 @@ func (p *Processors) ProcessC2CMessage(data *dto.WSC2CMessageData) error {
messageID := int(messageID64)
//todo 判断array模式 然后对Message处理成array格式
IsBindedUserId := idmap.CheckValue(data.Author.ID, userid64)
+
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
+
groupMsg := OnebotGroupMessage{
RawMessage: messageText,
Message: messageText,
@@ -212,7 +228,7 @@ func (p *Processors) ProcessC2CMessage(data *dto.WSC2CMessageData) error {
GroupID: userid64,
MessageType: "group",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
Sender: Sender{
UserID: userid64,
diff --git a/Processor/ProcessChannelDirectMessage.go b/Processor/ProcessChannelDirectMessage.go
index 6c705e33..94d73567 100644
--- a/Processor/ProcessChannelDirectMessage.go
+++ b/Processor/ProcessChannelDirectMessage.go
@@ -120,13 +120,20 @@ func (p *Processors) ProcessChannelDirectMessage(data *dto.WSDirectMessageData)
IsBindedUserId = idmap.CheckValuev2(userid64)
}
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
+
privateMsg := OnebotPrivateMessage{
RawMessage: messageText,
Message: segmentedMessages,
MessageID: messageID,
MessageType: "private",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
Sender: PrivateSender{
Nickname: data.Member.Nick,
@@ -196,6 +203,12 @@ func (p *Processors) ProcessChannelDirectMessage(data *dto.WSDirectMessageData)
mylog.Printf("Error storing ID: %v", err)
return nil
}
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
//OnebotChannelMessage
onebotMsg := OnebotChannelMessage{
ChannelID: data.ChannelID,
@@ -205,7 +218,7 @@ func (p *Processors) ProcessChannelDirectMessage(data *dto.WSDirectMessageData)
MessageID: data.ID,
MessageType: "guild",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
SelfTinyID: "",
Sender: Sender{
@@ -348,6 +361,14 @@ func (p *Processors) ProcessChannelDirectMessage(data *dto.WSDirectMessageData)
} else {
IsBindedUserId = idmap.CheckValuev2(userid64)
}
+
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
+
groupMsg := OnebotGroupMessage{
RawMessage: messageText,
Message: segmentedMessages,
@@ -355,7 +376,7 @@ func (p *Processors) ProcessChannelDirectMessage(data *dto.WSDirectMessageData)
GroupID: ChannelID64,
MessageType: "group",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
Sender: Sender{
Nickname: data.Member.Nick,
diff --git a/Processor/ProcessGroupAddBot.go b/Processor/ProcessGroupAddBot.go
index 5fd4863f..eeef7f5e 100644
--- a/Processor/ProcessGroupAddBot.go
+++ b/Processor/ProcessGroupAddBot.go
@@ -93,15 +93,23 @@ func (p *Processors) ProcessGroupAddBot(data *dto.GroupAddBotEvent) error {
mylog.Printf("Invalid type for timestamp: %T", v)
return nil
}
-
+
mylog.Printf("Bot被[%v]邀请进入群[%v]", userid64, GroupID64)
+
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
+
Request = GroupRequestEvent{
Comment: "",
Flag: "",
GroupID: GroupID64,
PostType: "request",
RequestType: "group",
- SelfID: int64(config.GetAppID()),
+ SelfID: selfid64,
SubType: "invite",
Time: timestampInt64,
UserID: userid64,
@@ -111,7 +119,7 @@ func (p *Processors) ProcessGroupAddBot(data *dto.GroupAddBotEvent) error {
NoticeType: "group_increase",
OperatorID: 0,
PostType: "notice",
- SelfID: int64(config.GetAppID()),
+ SelfID: selfid64,
SubType: "invite",
Time: timestampInt64,
UserID: userid64,
diff --git a/Processor/ProcessGroupDelBot.go b/Processor/ProcessGroupDelBot.go
index 5dfe2e65..44d1287e 100644
--- a/Processor/ProcessGroupDelBot.go
+++ b/Processor/ProcessGroupDelBot.go
@@ -53,12 +53,19 @@ func (p *Processors) ProcessGroupDelBot(data *dto.GroupAddBotEvent) error {
mylog.Printf("Bot被[%v]从群[%v]移出", userid64, GroupID64)
//从数据库删除群数据(仅删除类型缓存,再次加入会刷新)
idmap.DeleteConfigv2(fmt.Sprint(GroupID64), "type")
+
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
Notice = GroupNoticeEvent{
GroupID: GroupID64,
NoticeType: "group_decrease",
OperatorID: 0,
PostType: "notice",
- SelfID: int64(config.GetAppID()),
+ SelfID: selfid64,
SubType: "kick_me",
Time: timestampInt64,
UserID: userid64,
diff --git a/Processor/ProcessGroupMessage.go b/Processor/ProcessGroupMessage.go
index 4631ab20..5cdcf065 100644
--- a/Processor/ProcessGroupMessage.go
+++ b/Processor/ProcessGroupMessage.go
@@ -102,6 +102,13 @@ func (p *Processors) ProcessGroupMessage(data *dto.WSGroupATMessageData) error {
IsBindedUserId = idmap.CheckValuev2(userid64)
IsBindedGroupId = idmap.CheckValuev2(GroupID64)
}
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
+
groupMsg := OnebotGroupMessage{
RawMessage: messageText,
Message: segmentedMessages,
@@ -109,7 +116,7 @@ func (p *Processors) ProcessGroupMessage(data *dto.WSGroupATMessageData) error {
GroupID: GroupID64,
MessageType: "group",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
Sender: Sender{
UserID: userid64,
diff --git a/Processor/ProcessGuildATMessage.go b/Processor/ProcessGuildATMessage.go
index 563da6d0..aef11d04 100644
--- a/Processor/ProcessGuildATMessage.go
+++ b/Processor/ProcessGuildATMessage.go
@@ -54,6 +54,12 @@ func (p *Processors) ProcessGuildATMessage(data *dto.WSATMessageData) error {
if config.GetArrayValue() {
segmentedMessages = handlers.ConvertToSegmentedMessage(data)
}
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
// 处理onebot_channel_message逻辑
onebotMsg := OnebotChannelMessage{
ChannelID: data.ChannelID,
@@ -63,7 +69,7 @@ func (p *Processors) ProcessGuildATMessage(data *dto.WSATMessageData) error {
MessageID: data.ID,
MessageType: "guild",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
SelfTinyID: "0",
Sender: Sender{
@@ -208,6 +214,12 @@ func (p *Processors) ProcessGuildATMessage(data *dto.WSATMessageData) error {
IsBindedUserId = idmap.CheckValuev2(userid64)
IsBindedGroupId = idmap.CheckValuev2(ChannelID64)
}
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
groupMsg := OnebotGroupMessage{
RawMessage: messageText,
Message: segmentedMessages,
@@ -215,7 +227,7 @@ func (p *Processors) ProcessGuildATMessage(data *dto.WSATMessageData) error {
GroupID: ChannelID64,
MessageType: "group",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
Sender: Sender{
Nickname: data.Member.Nick,
diff --git a/Processor/ProcessGuildNormalMessage.go b/Processor/ProcessGuildNormalMessage.go
index f3f01942..36b9a32a 100644
--- a/Processor/ProcessGuildNormalMessage.go
+++ b/Processor/ProcessGuildNormalMessage.go
@@ -51,6 +51,13 @@ func (p *Processors) ProcessGuildNormalMessage(data *dto.WSMessageData) error {
if config.GetArrayValue() {
segmentedMessages = handlers.ConvertToSegmentedMessage(data)
}
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
+
// 处理onebot_channel_message逻辑
onebotMsg := OnebotChannelMessage{
ChannelID: data.ChannelID,
@@ -60,7 +67,7 @@ func (p *Processors) ProcessGuildNormalMessage(data *dto.WSMessageData) error {
MessageID: data.ID,
MessageType: "guild",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
SelfTinyID: "0",
Sender: Sender{
@@ -203,6 +210,14 @@ func (p *Processors) ProcessGuildNormalMessage(data *dto.WSMessageData) error {
IsBindedUserId = idmap.CheckValuev2(userid64)
IsBindedGroupId = idmap.CheckValuev2(ChannelID64)
}
+
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
+
groupMsg := OnebotGroupMessage{
RawMessage: messageText,
Message: segmentedMessages,
@@ -210,7 +225,7 @@ func (p *Processors) ProcessGuildNormalMessage(data *dto.WSMessageData) error {
GroupID: ChannelID64,
MessageType: "group",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
Sender: Sender{
Nickname: data.Member.Nick,
diff --git a/Processor/ProcessInlineSearch.go b/Processor/ProcessInlineSearch.go
index fa03d10f..4c205b08 100644
--- a/Processor/ProcessInlineSearch.go
+++ b/Processor/ProcessInlineSearch.go
@@ -64,12 +64,19 @@ func (p *Processors) ProcessInlineSearch(data *dto.WSInteractionData) error {
return nil
}
}
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
+
if !config.GetGlobalInteractionToMessage() {
notice := &OnebotInteractionNotice{
GroupID: GroupID64,
NoticeType: "interaction",
PostType: "notice",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
SubType: "create",
Time: time.Now().Unix(),
UserID: userid64,
@@ -95,6 +102,12 @@ func (p *Processors) ProcessInlineSearch(data *dto.WSInteractionData) error {
return nil
}
messageID := int(messageID64)
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
groupMsg := OnebotGroupMessage{
RawMessage: data.Data.Resolved.ButtonData,
Message: segmentedMessages,
@@ -102,7 +115,7 @@ func (p *Processors) ProcessInlineSearch(data *dto.WSInteractionData) error {
GroupID: GroupID64,
MessageType: "group",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
Sender: Sender{
UserID: userid64,
@@ -131,7 +144,12 @@ func (p *Processors) ProcessInlineSearch(data *dto.WSInteractionData) error {
//群回调
newdata := ConvertInteractionToMessage(data)
segmentedMessages := handlers.ConvertToSegmentedMessage(newdata)
-
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
onebotMsg := OnebotChannelMessage{
ChannelID: data.ChannelID,
GuildID: data.GuildID,
@@ -140,7 +158,7 @@ func (p *Processors) ProcessInlineSearch(data *dto.WSInteractionData) error {
MessageID: data.ID,
MessageType: "guild",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
SelfTinyID: "0",
Sender: Sender{
diff --git a/Processor/ProcessThreadMessage.go b/Processor/ProcessThreadMessage.go
index 9f61c27c..833ec72d 100644
--- a/Processor/ProcessThreadMessage.go
+++ b/Processor/ProcessThreadMessage.go
@@ -57,6 +57,14 @@ func (p *Processors) ProcessThreadMessage(data *dto.WSThreadData) error {
if err != nil {
mylog.Printf("Error parseContent Forum: %v", err)
}
+
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
+
// 处理onebot_channel_message逻辑
onebotMsg := OnebotChannelMessage{
ChannelID: data.ChannelID,
@@ -66,7 +74,7 @@ func (p *Processors) ProcessThreadMessage(data *dto.WSThreadData) error {
MessageID: data.ID,
MessageType: "guild",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
SelfTinyID: "0",
Sender: Sender{
@@ -168,6 +176,14 @@ func (p *Processors) ProcessThreadMessage(data *dto.WSThreadData) error {
if err != nil {
mylog.Printf("Error parseContent Forum: %v", err)
}
+
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
+
// 处理onebot_channel_message逻辑
onebotMsg := OnebotChannelMessage{
ChannelID: data.ChannelID,
@@ -177,7 +193,7 @@ func (p *Processors) ProcessThreadMessage(data *dto.WSThreadData) error {
MessageID: data.ID,
MessageType: "guild",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
SelfTinyID: "0",
Sender: Sender{
@@ -315,6 +331,12 @@ func (p *Processors) ProcessThreadMessage(data *dto.WSThreadData) error {
IsBindedUserId = idmap.CheckValuev2(userid64)
IsBindedGroupId = idmap.CheckValuev2(ChannelID64)
}
+ var selfid64 int64
+ if config.GetUseUin() {
+ selfid64 = config.GetUinint64()
+ } else {
+ selfid64 = int64(p.Settings.AppID)
+ }
groupMsg := OnebotGroupMessage{
RawMessage: messageText,
Message: segmentedMessages,
@@ -322,7 +344,7 @@ func (p *Processors) ProcessThreadMessage(data *dto.WSThreadData) error {
GroupID: ChannelID64,
MessageType: "group",
PostType: "message",
- SelfID: int64(p.Settings.AppID),
+ SelfID: selfid64,
UserID: userid64,
Sender: Sender{
Nickname: "发帖人昵称",
diff --git a/Processor/Processor.go b/Processor/Processor.go
index 71f23ed0..3ac94aab 100644
--- a/Processor/Processor.go
+++ b/Processor/Processor.go
@@ -275,7 +275,13 @@ func PostMessageToUrls(message map[string]interface{}) {
// 设置请求头
req.Header.Set("Content-Type", "application/json")
// 设置 X-Self-ID
- selfid := config.GetAppIDStr()
+ var selfid string
+ if config.GetUseUin() {
+ selfid = config.GetUinStr()
+ } else {
+ selfid = config.GetAppIDStr()
+ }
+
req.Header.Set("X-Self-ID", selfid)
// 发送请求
diff --git a/config/config.go b/config/config.go
index a3420674..70e5d415 100644
--- a/config/config.go
+++ b/config/config.go
@@ -45,6 +45,7 @@ type Settings struct {
ClientSecret string `yaml:"client_secret"`
ShardCount int `yaml:"shard_count"`
ShardID int `yaml:"shard_id"`
+ UseUin bool `yaml:"use_uin"`
//事件订阅类
TextIntent []string `yaml:"text_intent"`
//转换类
@@ -96,25 +97,26 @@ type Settings struct {
Username string `yaml:"server_user_name"`
Password string `yaml:"server_user_password"`
//指令魔法类
- RemovePrefix bool `yaml:"remove_prefix"`
- RemoveAt bool `yaml:"remove_at"`
- RemoveBotAtGroup bool `yaml:"remove_bot_at_group"`
- AddAtGroup bool `yaml:"add_at_group"`
- WhitePrefixMode bool `yaml:"white_prefix_mode"`
- VwhitePrefixMode bool `yaml:"v_white_prefix_mode"`
- WhitePrefixs []string `yaml:"white_prefixs"`
- WhiteBypass []int64 `yaml:"white_bypass"`
- WhiteEnable []bool `yaml:"white_enable"`
- WhiteBypassRevers bool `yaml:"white_bypass_reverse"`
- NoWhiteResponse string `yaml:"No_White_Response"`
- BlackPrefixMode bool `yaml:"black_prefix_mode"`
- BlackPrefixs []string `yaml:"black_prefixs"`
- Alias []string `yaml:"alias"`
- Enters []string `yaml:"enters"`
- EntersExcept []string `yaml:"enters_except"`
- VisualPrefixs []VisualPrefixConfig `yaml:"visual_prefixs"`
- AutoWithdraw []string `yaml:"auto_withdraw"`
- AutoWithdrawTime int `yaml:"auto_withdraw_time"`
+ RemovePrefix bool `yaml:"remove_prefix"`
+ RemoveAt bool `yaml:"remove_at"`
+ RemoveBotAtGroup bool `yaml:"remove_bot_at_group"`
+ AddAtGroup bool `yaml:"add_at_group"`
+ WhitePrefixMode bool `yaml:"white_prefix_mode"`
+ VwhitePrefixMode bool `yaml:"v_white_prefix_mode"`
+ WhitePrefixs []string `yaml:"white_prefixs"`
+ WhiteBypass []int64 `yaml:"white_bypass"`
+ WhiteEnable []bool `yaml:"white_enable"`
+ WhiteBypassRevers bool `yaml:"white_bypass_reverse"`
+ NoWhiteResponse string `yaml:"No_White_Response"`
+ BlackPrefixMode bool `yaml:"black_prefix_mode"`
+ BlackPrefixs []string `yaml:"black_prefixs"`
+ Alias []string `yaml:"alias"`
+ Enters []string `yaml:"enters"`
+ EntersExcept []string `yaml:"enters_except"`
+ VisualPrefixs []VisualPrefixConfig `yaml:"visual_prefixs"`
+ AutoWithdraw []string `yaml:"auto_withdraw"`
+ AutoWithdrawTime int `yaml:"auto_withdraw_time"`
+ VisualPrefixsBypass []string `yaml:"visual_prefixs_bypass"`
//开发增强类
DevlopAcDir string `yaml:"develop_access_token_dir"`
DevBotid string `yaml:"develop_bot_id"`
@@ -1497,6 +1499,18 @@ func GetPostSecret() []string {
return instance.Settings.PostSecret
}
+// 获取 VisualPrefixsBypass
+func GetVisualPrefixsBypass() []string {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to getVisualPrefixsBypass.")
+ return nil
+ }
+ return instance.Settings.VisualPrefixsBypass
+}
+
// 获取 POST 最大重试次数数组
func GetPostMaxRetries() []int {
mu.Lock()
@@ -1557,6 +1571,17 @@ func GetUrlToQrimage() bool {
return instance.Settings.UrlToQrimage
}
+func GetUseUin() bool {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if instance == nil {
+ mylog.Println("Warning: instance is nil when trying to UseUin value.")
+ return false
+ }
+ return instance.Settings.UseUin
+}
+
// 获取GetQrSize的值
func GetQrSize() int {
mu.Lock()
@@ -1926,6 +1951,16 @@ func GetKeyBoardID() string {
return instance.Settings.KeyBoardID
}
+// 获取Uin int64
+func GetUinint64() int64 {
+ mu.Lock()
+ defer mu.Unlock()
+ if instance != nil {
+ return instance.Settings.Uin
+ }
+ return 0
+}
+
// 获取Uin String
func GetUinStr() string {
mu.Lock()
diff --git a/handlers/message_parser.go b/handlers/message_parser.go
index 70f9c62b..84c1d361 100644
--- a/handlers/message_parser.go
+++ b/handlers/message_parser.go
@@ -740,6 +740,7 @@ func RevertTransformedText(data interface{}, msgtype string, api openapi.OpenAPI
//处理前 先去前后空
messageText = strings.TrimSpace(msg.Content)
}
+ var originmessageText = messageText
//mylog.Printf("1[%v]", messageText)
// 将messageText里的BotID替换成AppID
@@ -962,6 +963,15 @@ func RevertTransformedText(data interface{}, msgtype string, api openapi.OpenAPI
matched = true
} else {
matched = false
+ // 调用 GetVisualPrefixsBypass 获取前缀数组
+ visualPrefixes := config.GetVisualPrefixsBypass()
+ // 判断 messageText 是否以数组中的任一前缀开头
+ for _, prefix := range visualPrefixes {
+ if strings.HasPrefix(originmessageText, prefix) {
+ matched = true
+ break
+ }
+ }
}
} else {
// 遍历白名单数组,检查是否有匹配项
@@ -990,6 +1000,7 @@ func RevertTransformedText(data interface{}, msgtype string, api openapi.OpenAPI
if !matched {
messageText = ""
SendMessage(matchedPrefix.NoWhiteResponse, data, msgtype, api, apiv2)
+ return messageText //2024-4-25新增,可能会有bug.观察
}
}
}
diff --git a/main.go b/main.go
index 11258e74..27026ae1 100644
--- a/main.go
+++ b/main.go
@@ -255,7 +255,13 @@ func main() {
attemptedConnections++ // 增加尝试连接的计数
go func(address string) {
retry := config.GetLaunchReconectTimes()
- wsClient, err := wsclient.NewWebSocketClient(address, conf.Settings.AppID, api, apiV2, retry)
+ var BotID uint64
+ if config.GetUseUin() {
+ BotID = uint64(config.GetUinint64())
+ } else {
+ BotID = conf.Settings.AppID
+ }
+ wsClient, err := wsclient.NewWebSocketClient(address, BotID, api, apiV2, retry)
if err != nil {
log.Printf("Error creating WebSocketClient for address(连接到反向ws失败) %s: %v\n", address, err)
errorChan <- err
diff --git a/server/wsserver.go b/server/wsserver.go
index fb223d22..5bd2b366 100644
--- a/server/wsserver.go
+++ b/server/wsserver.go
@@ -93,7 +93,13 @@ func wsHandler(api openapi.OpenAPI, apiV2 openapi.OpenAPI, p *Processor.Processo
p.WsServerClients = append(p.WsServerClients, client)
// 获取botID
- botID := config.GetAppID()
+
+ var botID uint64
+ if config.GetUseUin() {
+ botID = uint64(config.GetUinint64())
+ } else {
+ botID = config.GetAppID()
+ }
// 发送连接成功的消息
message := map[string]interface{}{
diff --git a/template/config_template.go b/template/config_template.go
index 10cbda4e..e8ce50d4 100644
--- a/template/config_template.go
+++ b/template/config_template.go
@@ -13,6 +13,7 @@ settings:
#基础设置
app_id: 12345 # 你的应用ID
uin : 0 # 你的机器人QQ号,点击机器人资料卡查看
+ use_uin : false # false=使用appid作为机器人id,true=使用机器人QQ号,需设置正确的uin
token: "" # 你的应用令牌
client_secret: "" # 你的客户端密钥
shard_count: 1 #分片数量 默认1
@@ -110,6 +111,7 @@ settings:
enters_except : ["",""] #自动md卡片点击直接触发,例外,对子按钮生效.
auto_withdraw : [] #仅当应用端实现了双向echo可用.实现不难,可以去找对应开发者去提需求.
auto_withdraw_time : 30 #30秒
+ visual_prefixs_bypass : [] #要绕过二级指令白名单的指令,比如需要用户回答自定义内容的指令.
visual_prefixs : #虚拟前缀 与white_prefixs配合使用 处理流程自动忽略该前缀 remove_prefix remove_at 需为true时生效
- prefix: "" #虚拟前缀开头 例 你有3个指令 帮助 测试 查询 将 prefix 设置为 工具类 后 则可通过 工具类 帮助 触发机器人
diff --git a/wsclient/ws.go b/wsclient/ws.go
index 318c8350..3435e87c 100644
--- a/wsclient/ws.go
+++ b/wsclient/ws.go
@@ -53,7 +53,7 @@ func (client *WebSocketClient) SendMessage(message map[string]interface{}) error
}
// 处理onebotv11应用端发来的信息
-func (client *WebSocketClient) handleIncomingMessages(ctx context.Context, cancel context.CancelFunc) {
+func (client *WebSocketClient) handleIncomingMessages(cancel context.CancelFunc) {
for {
_, msg, err := client.conn.ReadMessage()
if err != nil {
@@ -155,7 +155,7 @@ func (client *WebSocketClient) Reconnect() {
client.cancel = cancel
heartbeatinterval := config.GetHeartBeatInterval()
go client.sendHeartbeat(ctx, client.botID, heartbeatinterval)
- go client.handleIncomingMessages(ctx, cancel)
+ go client.handleIncomingMessages(cancel)
defer func() {
client.isReconnecting = false
@@ -337,7 +337,7 @@ func NewWebSocketClient(urlStr string, botID uint64, api openapi.OpenAPI, apiv2
client.cancel = cancel
heartbeatinterval := config.GetHeartBeatInterval()
go client.sendHeartbeat(ctx, botID, heartbeatinterval)
- go client.handleIncomingMessages(ctx, cancel)
+ go client.handleIncomingMessages(cancel)
return client, nil
}