From 0400d3bbea8d5deeeebd65311b334e2c6038534f Mon Sep 17 00:00:00 2001 From: SanaeFox <36219542+Hoshinonyaruko@users.noreply.github.com> Date: Thu, 26 Oct 2023 13:04:04 +0800 Subject: [PATCH] Test4 (#11) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Compiled main.go and pushed changes * test * 适配了频道私聊,用bolt数据库取代ini * 适配了nonebot2 * add license * add a lot * trss support --- Processor/ProcessC2CMessage.go | 157 +++++++++++++++++++++++ Processor/ProcessChannelDirectMessage.go | 24 +++- Processor/ProcessGroupMessage.go | 13 +- Processor/ProcessGuildATMessage.go | 28 ++-- Processor/ProcessGuildNormalMessage.go | 28 ++-- Processor/Processor.go | 47 +++---- botgo/token/authtoken.go | 98 +++++++------- botgo/token/token.go | 14 +- callapi/callapi.go | 24 +++- config/config.go | 22 ++++ config_template.go | 2 +- config_template.yml | 2 +- handlers/get_friend_list.go | 63 +++++++++ handlers/get_group_info.go | 2 +- handlers/get_group_list.go | 154 ++++++++++++++++++++++ handlers/get_group_member_list.go | 96 ++++++++++++++ handlers/get_guild_channel_list.go | 41 ++++++ handlers/get_guild_list.go | 58 +++++++++ handlers/get_guild_service_profile.go | 51 ++++++++ handlers/get_login_info.go | 59 +++++++++ handlers/get_online_clients.go | 51 ++++++++ handlers/get_version_info.go | 73 +++++++++++ handlers/message_parser.go | 76 +++++++++++ handlers/send_group_msg.go | 22 +--- handlers/send_guild_channel_msg.go | 4 +- handlers/send_msg.go | 65 ++++++++-- handlers/send_private_msg.go | 38 +++--- handlers/set_group_ban.go | 65 ++++++++++ handlers/set_group_whole_ban.go | 60 +++++++++ idmap/service.go | 32 ++--- main.go | 23 ++-- wsclient/ws.go | 15 ++- 32 files changed, 1302 insertions(+), 205 deletions(-) create mode 100644 Processor/ProcessC2CMessage.go create mode 100644 handlers/get_friend_list.go create mode 100644 handlers/get_group_list.go create mode 100644 handlers/get_group_member_list.go create mode 100644 handlers/get_guild_channel_list.go create mode 100644 handlers/get_guild_list.go create mode 100644 handlers/get_guild_service_profile.go create mode 100644 handlers/get_login_info.go create mode 100644 handlers/get_online_clients.go create mode 100644 handlers/get_version_info.go create mode 100644 handlers/set_group_ban.go create mode 100644 handlers/set_group_whole_ban.go diff --git a/Processor/ProcessC2CMessage.go b/Processor/ProcessC2CMessage.go new file mode 100644 index 00000000..72eeda07 --- /dev/null +++ b/Processor/ProcessC2CMessage.go @@ -0,0 +1,157 @@ +// 处理收到的信息事件 +package Processor + +import ( + "fmt" + "log" + "strconv" + "time" + + "github.com/hoshinonyaruko/gensokyo/config" + "github.com/hoshinonyaruko/gensokyo/echo" + "github.com/hoshinonyaruko/gensokyo/handlers" + "github.com/hoshinonyaruko/gensokyo/idmap" + "github.com/tencent-connect/botgo/dto" + "github.com/tencent-connect/botgo/websocket/client" +) + +// ProcessC2CMessage 处理C2C消息 群私聊 +func (p *Processor) ProcessC2CMessage(data *dto.WSC2CMessageData) error { + // 打印data结构体 + PrintStructWithFieldNames(data) + + // 从私信中提取必要的信息 这是测试回复需要用到 + //recipientID := data.Author.ID + //ChannelID := data.ChannelID + //sourece是源头频道 + //GuildID := data.GuildID + + //获取当前的s值 当前ws连接所收到的信息条数 + s := client.GetGlobalS() + if !p.Settings.GlobalPrivateToChannel { + // 直接转换成ob11私信 + + //转换appidstring + AppIDString := strconv.FormatUint(p.Settings.AppID, 10) + echostr := AppIDString + "_" + strconv.FormatInt(s, 10) + + //将真实id转为int userid64 + userid64, err := idmap.StoreIDv2(data.Author.ID) + if err != nil { + log.Fatalf("Error storing ID: %v", err) + } + + //收到私聊信息调用的具体还原步骤 + //1,idmap还原真实userid, + //发信息使用的是userid + + messageID64, err := idmap.StoreIDv2(data.ID) + if err != nil { + log.Fatalf("Error storing ID: %v", err) + } + messageID := int(messageID64) + messageText := data.Content + // 如果在Array模式下, 则处理Message为Segment格式 + var segmentedMessages interface{} = messageText + if config.GetArrayValue() { + segmentedMessages = handlers.ConvertToSegmentedMessage(data) + } + privateMsg := OnebotPrivateMessage{ + RawMessage: messageText, + Message: segmentedMessages, + MessageID: messageID, + MessageType: "private", + PostType: "message", + SelfID: int64(p.Settings.AppID), + UserID: userid64, + Sender: PrivateSender{ + Nickname: "", //这个不支持,但加机器人好友,会收到一个事件,可以对应储存获取,用idmaps可以做到. + UserID: userid64, + }, + SubType: "friend", + Time: time.Now().Unix(), + Avatar: "", //todo 同上 + Echo: echostr, + } + + // 将当前s和appid和message进行映射 + echo.AddMsgID(AppIDString, s, data.ID) + echo.AddMsgType(AppIDString, s, "group_private") + //其实不需要用AppIDString,因为gensokyo是单机器人框架 + //可以试着开发一个,会很棒的 + echo.AddMsgID(AppIDString, userid64, data.ID) + echo.AddMsgType(AppIDString, userid64, "group_private") + //储存当前群或频道号的类型 私信不需要 + //idmap.WriteConfigv2(data.ChannelID, "type", "group_private") + + // 调试 + PrintStructWithFieldNames(privateMsg) + + // Convert OnebotGroupMessage to map and send + privateMsgMap := structToMap(privateMsg) + err = p.Wsclient.SendMessage(privateMsgMap) + if err != nil { + return fmt.Errorf("error sending group message via wsclient: %v", err) + } + } else { + //将私聊信息转化为群信息(特殊需求情况下) + + //转换at + messageText := handlers.RevertTransformedText(data.Content) + //转换appid + AppIDString := strconv.FormatUint(p.Settings.AppID, 10) + //构造echo + echostr := AppIDString + "_" + strconv.FormatInt(s, 10) + //把userid作为群号 + //映射str的userid到int + userid64, err := idmap.StoreIDv2(data.Author.ID) + if err != nil { + log.Printf("Error storing ID: %v", err) + return nil + } + //映射str的messageID到int + messageID64, err := idmap.StoreIDv2(data.ID) + if err != nil { + log.Printf("Error storing ID: %v", err) + return nil + } + messageID := int(messageID64) + //todo 判断array模式 然后对Message处理成array格式 + groupMsg := OnebotGroupMessage{ + RawMessage: messageText, + Message: messageText, + MessageID: messageID, + GroupID: userid64, + MessageType: "group", + PostType: "message", + SelfID: int64(p.Settings.AppID), + UserID: userid64, + Sender: Sender{ + Nickname: "", + UserID: userid64, + }, + SubType: "normal", + Time: time.Now().Unix(), + Avatar: "", + Echo: echostr, + } + //将当前s和appid和message进行映射 + echo.AddMsgID(AppIDString, s, data.ID) + echo.AddMsgType(AppIDString, s, "group_private") + //为不支持双向echo的ob服务端映射 + echo.AddMsgID(AppIDString, userid64, data.ID) + echo.AddMsgType(AppIDString, userid64, "group_private") + + //调试 + PrintStructWithFieldNames(groupMsg) + + // Convert OnebotGroupMessage to map and send + groupMsgMap := structToMap(groupMsg) + err = p.Wsclient.SendMessage(groupMsgMap) + if err != nil { + return fmt.Errorf("error sending group message via wsclient: %v", err) + } + } + + return nil +} diff --git a/Processor/ProcessChannelDirectMessage.go b/Processor/ProcessChannelDirectMessage.go index e2418474..51181ffd 100644 --- a/Processor/ProcessChannelDirectMessage.go +++ b/Processor/ProcessChannelDirectMessage.go @@ -7,6 +7,7 @@ import ( "strconv" "time" + "github.com/hoshinonyaruko/gensokyo/config" "github.com/hoshinonyaruko/gensokyo/echo" "github.com/hoshinonyaruko/gensokyo/handlers" "github.com/hoshinonyaruko/gensokyo/idmap" @@ -56,10 +57,15 @@ func (p *Processor) ProcessChannelDirectMessage(data *dto.WSDirectMessageData) e log.Fatalf("Error storing ID: %v", err) } messageID := int(messageID64) - + messageText := data.Content + // 如果在Array模式下, 则处理Message为Segment格式 + var segmentedMessages interface{} = messageText + if config.GetArrayValue() { + segmentedMessages = handlers.ConvertToSegmentedMessage(data) + } privateMsg := OnebotPrivateMessage{ - RawMessage: data.Content, - Message: data.Content, + RawMessage: messageText, + Message: segmentedMessages, MessageID: messageID, MessageType: "private", PostType: "message", @@ -144,6 +150,8 @@ func (p *Processor) ProcessChannelDirectMessage(data *dto.WSDirectMessageData) e //为不支持双向echo的ob服务端映射 echo.AddMsgID(AppIDString, userid64, data.ID) echo.AddMsgType(AppIDString, userid64, "guild_private") + //储存当前群或频道号的类型 + idmap.WriteConfigv2(data.ChannelID, "type", "guild_private") //调试 PrintStructWithFieldNames(onebotMsg) @@ -186,10 +194,14 @@ func (p *Processor) ProcessChannelDirectMessage(data *dto.WSDirectMessageData) e return nil } messageID := int(messageID64) - //todo 判断array模式 然后对Message处理成array格式 + // 如果在Array模式下, 则处理Message为Segment格式 + var segmentedMessages interface{} = messageText + if config.GetArrayValue() { + segmentedMessages = handlers.ConvertToSegmentedMessage(data) + } groupMsg := OnebotGroupMessage{ RawMessage: messageText, - Message: messageText, + Message: segmentedMessages, MessageID: messageID, GroupID: int64(channelIDInt), MessageType: "group", @@ -211,6 +223,8 @@ func (p *Processor) ProcessChannelDirectMessage(data *dto.WSDirectMessageData) e //为不支持双向echo的ob服务端映射 echo.AddMsgID(AppIDString, userid64, data.ID) echo.AddMsgType(AppIDString, userid64, "guild_private") + //储存当前群或频道号的类型 + idmap.WriteConfigv2(data.ChannelID, "type", "guild_private") //调试 PrintStructWithFieldNames(groupMsg) diff --git a/Processor/ProcessGroupMessage.go b/Processor/ProcessGroupMessage.go index 0c823e80..5610b493 100644 --- a/Processor/ProcessGroupMessage.go +++ b/Processor/ProcessGroupMessage.go @@ -7,6 +7,7 @@ import ( "strconv" "time" + "github.com/hoshinonyaruko/gensokyo/config" "github.com/hoshinonyaruko/gensokyo/echo" "github.com/hoshinonyaruko/gensokyo/handlers" "github.com/hoshinonyaruko/gensokyo/idmap" @@ -43,7 +44,7 @@ func (p *Processor) ProcessGroupMessage(data *dto.WSGroupATMessageData) error { log.Printf("Error storing ID: %v", err) return nil } - //userid := int(userid64) + //映射str的messageID到int messageID64, err := idmap.StoreIDv2(data.ID) if err != nil { @@ -51,10 +52,14 @@ func (p *Processor) ProcessGroupMessage(data *dto.WSGroupATMessageData) error { return nil } messageID := int(messageID64) - // todo 判断array模式 然后对Message处理成array格式 + // 如果在Array模式下, 则处理Message为Segment格式 + var segmentedMessages interface{} = messageText + if config.GetArrayValue() { + segmentedMessages = handlers.ConvertToSegmentedMessage(data) + } groupMsg := OnebotGroupMessage{ RawMessage: messageText, - Message: messageText, + Message: segmentedMessages, MessageID: messageID, GroupID: GroupID64, MessageType: "group", @@ -77,6 +82,8 @@ func (p *Processor) ProcessGroupMessage(data *dto.WSGroupATMessageData) error { //为不支持双向echo的ob服务端映射 echo.AddMsgID(AppIDString, GroupID64, data.ID) echo.AddMsgType(AppIDString, GroupID64, "group") + //储存当前群或频道号的类型 + idmap.WriteConfigv2(data.GroupID, "type", "group") // 调试 PrintStructWithFieldNames(groupMsg) diff --git a/Processor/ProcessGuildATMessage.go b/Processor/ProcessGuildATMessage.go index 68a8ed27..c3de90c5 100644 --- a/Processor/ProcessGuildATMessage.go +++ b/Processor/ProcessGuildATMessage.go @@ -7,6 +7,7 @@ import ( "strconv" "time" + "github.com/hoshinonyaruko/gensokyo/config" "github.com/hoshinonyaruko/gensokyo/echo" "github.com/hoshinonyaruko/gensokyo/handlers" "github.com/hoshinonyaruko/gensokyo/idmap" @@ -37,19 +38,16 @@ func (p *Processor) ProcessGuildATMessage(data *dto.WSATMessageData) error { log.Printf("Error storing ID: %v", err) return nil } - //映射str的messageID到int - //可以是string - // messageID64, err := idmap.StoreIDv2(data.ID) - // if err != nil { - // log.Printf("Error storing ID: %v", err) - // return nil - // } - // messageID := int(messageID64) + // 如果在Array模式下, 则处理Message为Segment格式 + var segmentedMessages interface{} = messageText + if config.GetArrayValue() { + segmentedMessages = handlers.ConvertToSegmentedMessage(data) + } // 处理onebot_channel_message逻辑 onebotMsg := OnebotChannelMessage{ ChannelID: data.ChannelID, GuildID: data.GuildID, - Message: messageText, + Message: segmentedMessages, RawMessage: messageText, MessageID: data.ID, MessageType: "guild", @@ -74,6 +72,8 @@ func (p *Processor) ProcessGuildATMessage(data *dto.WSATMessageData) error { //为不支持双向echo的ob11服务端映射 echo.AddMsgID(AppIDString, userid64, data.ID) echo.AddMsgType(AppIDString, userid64, "guild") + //储存当前群或频道号的类型 + idmap.WriteConfigv2(data.ChannelID, "type", "guild") //调试 PrintStructWithFieldNames(onebotMsg) @@ -120,10 +120,14 @@ func (p *Processor) ProcessGuildATMessage(data *dto.WSATMessageData) error { return nil } messageID := int(messageID64) - //todo 判断array模式 然后对Message处理成array格式 + // 如果在Array模式下, 则处理Message为Segment格式 + var segmentedMessages interface{} = messageText + if config.GetArrayValue() { + segmentedMessages = handlers.ConvertToSegmentedMessage(data) + } groupMsg := OnebotGroupMessage{ RawMessage: messageText, - Message: messageText, + Message: segmentedMessages, MessageID: messageID, GroupID: int64(channelIDInt), MessageType: "group", @@ -145,6 +149,8 @@ func (p *Processor) ProcessGuildATMessage(data *dto.WSATMessageData) error { //为不支持双向echo的ob服务端映射 echo.AddMsgID(AppIDString, int64(channelIDInt), data.ID) echo.AddMsgType(AppIDString, int64(channelIDInt), "guild") + //储存当前群或频道号的类型 + idmap.WriteConfigv2(data.ChannelID, "type", "guild") //调试 PrintStructWithFieldNames(groupMsg) diff --git a/Processor/ProcessGuildNormalMessage.go b/Processor/ProcessGuildNormalMessage.go index cba53ac2..931b02ac 100644 --- a/Processor/ProcessGuildNormalMessage.go +++ b/Processor/ProcessGuildNormalMessage.go @@ -7,6 +7,7 @@ import ( "strconv" "time" + "github.com/hoshinonyaruko/gensokyo/config" "github.com/hoshinonyaruko/gensokyo/echo" "github.com/hoshinonyaruko/gensokyo/handlers" "github.com/hoshinonyaruko/gensokyo/idmap" @@ -36,19 +37,16 @@ func (p *Processor) ProcessGuildNormalMessage(data *dto.WSMessageData) error { log.Printf("Error storing ID: %v", err) return nil } - //映射str的messageID到int - //可以是string - // messageID64, err := idmap.StoreIDv2(data.ID) - // if err != nil { - // log.Printf("Error storing ID: %v", err) - // return nil - // } - // messageID := int(messageID64) + // 如果在Array模式下, 则处理Message为Segment格式 + var segmentedMessages interface{} = messageText + if config.GetArrayValue() { + segmentedMessages = handlers.ConvertToSegmentedMessage(data) + } // 处理onebot_channel_message逻辑 onebotMsg := OnebotChannelMessage{ ChannelID: data.ChannelID, GuildID: data.GuildID, - Message: messageText, + Message: segmentedMessages, RawMessage: messageText, MessageID: data.ID, MessageType: "guild", @@ -73,6 +71,8 @@ func (p *Processor) ProcessGuildNormalMessage(data *dto.WSMessageData) error { //为不支持双向echo的ob11服务端映射 echo.AddMsgID(AppIDString, userid64, data.ID) echo.AddMsgType(AppIDString, userid64, "guild") + //储存当前群或频道号的类型 + idmap.WriteConfigv2(data.ChannelID, "type", "guild") //调试 PrintStructWithFieldNames(onebotMsg) @@ -119,10 +119,14 @@ func (p *Processor) ProcessGuildNormalMessage(data *dto.WSMessageData) error { return nil } messageID := int(messageID64) - //todo 判断array模式 然后对Message处理成array格式 + // 如果在Array模式下, 则处理Message为Segment格式 + var segmentedMessages interface{} = messageText + if config.GetArrayValue() { + segmentedMessages = handlers.ConvertToSegmentedMessage(data) + } groupMsg := OnebotGroupMessage{ RawMessage: messageText, - Message: messageText, + Message: segmentedMessages, MessageID: messageID, GroupID: int64(channelIDInt), MessageType: "group", @@ -144,6 +148,8 @@ func (p *Processor) ProcessGuildNormalMessage(data *dto.WSMessageData) error { //为不支持双向echo的ob服务端映射 echo.AddMsgID(AppIDString, int64(channelIDInt), data.ID) echo.AddMsgType(AppIDString, int64(channelIDInt), "guild") + //储存当前群或频道号的类型 + idmap.WriteConfigv2(data.ChannelID, "type", "guild") //调试 PrintStructWithFieldNames(groupMsg) diff --git a/Processor/Processor.go b/Processor/Processor.go index 2a197cfa..5e2064cc 100644 --- a/Processor/Processor.go +++ b/Processor/Processor.go @@ -30,21 +30,21 @@ type Sender struct { // 频道信息事件 type OnebotChannelMessage struct { - ChannelID string `json:"channel_id"` - GuildID string `json:"guild_id"` - Message string `json:"message"` - MessageID string `json:"message_id"` - MessageType string `json:"message_type"` - PostType string `json:"post_type"` - SelfID int64 `json:"self_id"` - SelfTinyID string `json:"self_tiny_id"` - Sender Sender `json:"sender"` - SubType string `json:"sub_type"` - Time int64 `json:"time"` - Avatar string `json:"avatar"` - UserID int64 `json:"user_id"` - RawMessage string `json:"raw_message"` - Echo string `json:"echo"` + ChannelID string `json:"channel_id"` + GuildID string `json:"guild_id"` + Message interface{} `json:"message"` + MessageID string `json:"message_id"` + MessageType string `json:"message_type"` + PostType string `json:"post_type"` + SelfID int64 `json:"self_id"` + SelfTinyID string `json:"self_tiny_id"` + Sender Sender `json:"sender"` + SubType string `json:"sub_type"` + Time int64 `json:"time"` + Avatar string `json:"avatar"` + UserID int64 `json:"user_id"` + RawMessage string `json:"raw_message"` + Echo string `json:"echo"` } // 群信息事件 @@ -140,23 +140,6 @@ func (p *Processor) ProcessInlineSearch(data *dto.WSInteractionData) error { // return nil // } -// ProcessC2CMessage 处理C2C消息 群私聊 -func (p *Processor) ProcessC2CMessage(rawMessage string, data *dto.WSC2CMessageData) error { - // ctx := context.Background() // 或从更高级别传递一个上下文 - - // // 在这里处理C2C消息 - // // ... - - // // 示例:直接回复收到的消息 - // response := fmt.Sprintf("Received your message: %s", rawMessage) // 创建响应消息 - // err := p.api.PostC2CMessage(ctx, response) // 替换为您的OpenAPI方法 - // if err != nil { - // return err - // } - - return nil -} - // 打印结构体的函数 func PrintStructWithFieldNames(v interface{}) { val := reflect.ValueOf(v) diff --git a/botgo/token/authtoken.go b/botgo/token/authtoken.go index 303b302d..013aa77e 100644 --- a/botgo/token/authtoken.go +++ b/botgo/token/authtoken.go @@ -54,59 +54,59 @@ func (atoken *AuthTokenInfo) ForceUpToken(ctx context.Context, reason string) er // StartRefreshAccessToken 启动获取AccessToken的后台刷新 // 该函数首先会立即查询一次AccessToken,并保存。 // 然后它将在后台启动一个goroutine,定期(根据token的有效期)刷新AccessToken。 -// func (atoken *AuthTokenInfo) StartRefreshAccessToken(ctx context.Context, tokenURL, appID, clientSecrent string) (err error) { -// // 首先,立即获取一次AccessToken -// tokenInfo, err := queryAccessToken(ctx, tokenURL, appID, clientSecrent) -// if err != nil { -// return err -// } -// atoken.setAuthToken(tokenInfo) -// fmt.Printf("获取到的token是: %s\n", tokenInfo.Token) // 输出获取到的token - -// // 获取token的有效期(通常以秒为单位) -// tokenTTL := tokenInfo.ExpiresIn -// // 使用sync.Once保证仅启动一个goroutine进行定时刷新 -// atoken.once.Do(func() { -// go func() { // 启动一个新的goroutine -// for { -// // 如果tokenTTL为0或负数,将其设置为1 -// if tokenTTL <= 0 { -// tokenTTL = 1 -// } -// select { -// case <-time.NewTimer(time.Duration(tokenTTL) * time.Second).C: // 当token过期时 -// case upToken := <-atoken.forceUpToken: // 接收强制更新token的信号 -// log.Warnf("recv uptoken info:%v", upToken) -// case <-ctx.Done(): // 当上下文结束时,退出goroutine -// log.Warnf("recv ctx:%v exit refreshAccessToken", ctx.Err()) -// return -// } -// // 查询并获取新的AccessToken -// tokenInfo, err := queryAccessToken(ctx, tokenURL, appID, clientSecrent) -// if err == nil { -// atoken.setAuthToken(tokenInfo) -// fmt.Printf("获取到的token是: %s\n", tokenInfo.Token) // 输出获取到的token -// tokenTTL = tokenInfo.ExpiresIn -// } else { -// log.Errorf("queryAccessToken err:%v", err) -// } -// } -// }() -// }) -// return -// } - -// 测试用 func (atoken *AuthTokenInfo) StartRefreshAccessToken(ctx context.Context, tokenURL, appID, clientSecrent string) (err error) { - // 创建一个固定的token信息 - fixedTokenInfo := AccessTokenInfo{ - Token: "PpAPgoel0-gTeaxy-ydak0kUKxJrCSlbLcwtuPt99jCPVrahkqh3WSiIy9s63tCZnTEp4asw035u", - ExpiresIn: 3600, // 这里假设token的有效时间是3600秒,你可以根据需要调整 + // 首先,立即获取一次AccessToken + tokenInfo, err := queryAccessToken(ctx, tokenURL, appID, clientSecrent) + if err != nil { + return err } - atoken.setAuthToken(fixedTokenInfo) - return nil + atoken.setAuthToken(tokenInfo) + fmt.Printf("获取到的token是: %s\n", tokenInfo.Token) // 输出获取到的token + + // 获取token的有效期(通常以秒为单位) + tokenTTL := tokenInfo.ExpiresIn + // 使用sync.Once保证仅启动一个goroutine进行定时刷新 + atoken.once.Do(func() { + go func() { // 启动一个新的goroutine + for { + // 如果tokenTTL为0或负数,将其设置为1 + if tokenTTL <= 0 { + tokenTTL = 1 + } + select { + case <-time.NewTimer(time.Duration(tokenTTL) * time.Second).C: // 当token过期时 + case upToken := <-atoken.forceUpToken: // 接收强制更新token的信号 + log.Warnf("recv uptoken info:%v", upToken) + case <-ctx.Done(): // 当上下文结束时,退出goroutine + log.Warnf("recv ctx:%v exit refreshAccessToken", ctx.Err()) + return + } + // 查询并获取新的AccessToken + tokenInfo, err := queryAccessToken(ctx, tokenURL, appID, clientSecrent) + if err == nil { + atoken.setAuthToken(tokenInfo) + fmt.Printf("获取到的token是: %s\n", tokenInfo.Token) // 输出获取到的token + tokenTTL = tokenInfo.ExpiresIn + } else { + log.Errorf("queryAccessToken err:%v", err) + } + } + }() + }) + return } +// 测试用 +// func (atoken *AuthTokenInfo) StartRefreshAccessToken(ctx context.Context, tokenURL, appID, clientSecrent string) (err error) { +// // 创建一个固定的token信息 +// fixedTokenInfo := AccessTokenInfo{ +// Token: "PpAPgoel0-gTeaxy-ydak0kUKxJrCSlbLcwtuPt99jCPVrahkqh3WSiIy9s63tCZnTEp4asw035u", +// ExpiresIn: 3600, // 这里假设token的有效时间是3600秒,你可以根据需要调整 +// } +// atoken.setAuthToken(fixedTokenInfo) +// return nil +// } + func (atoken *AuthTokenInfo) getAuthToken() AccessTokenInfo { atoken.lock.RLock() defer atoken.lock.RUnlock() diff --git a/botgo/token/token.go b/botgo/token/token.go index b669b243..181312f0 100644 --- a/botgo/token/token.go +++ b/botgo/token/token.go @@ -91,16 +91,16 @@ func (t *Token) GetString_old() string { } // GetAccessToken 取得鉴权Token -// func (t *Token) GetAccessToken() string { -// return t.authToken.getAuthToken().Token -// } - -// GetAccessToken 取得测试鉴权Token func (t *Token) GetAccessToken() string { - // 固定的token值 - return "PpAPgoel0-gTeaxy-ydak0kUKxJrCSlbLcwtuPt99jCPVrahkqh3WSiIy9s63tCZnTEp4asw035u" + return t.authToken.getAuthToken().Token } +// GetAccessToken 取得测试鉴权Token +// func (t *Token) GetAccessToken() string { +// // 固定的token值 +// return "PpAPgoel0-gTeaxy-ydak0kUKxJrCSlbLcwtuPt99jCPVrahkqh3WSiIy9s63tCZnTEp4asw035u" +// } + // UpAccessToken 更新accessToken func (t *Token) UpAccessToken(ctx context.Context, reason interface{}) error { return t.authToken.ForceUpToken(ctx, fmt.Sprint(reason)) diff --git a/callapi/callapi.go b/callapi/callapi.go index 445ea523..51116fd4 100644 --- a/callapi/callapi.go +++ b/callapi/callapi.go @@ -58,9 +58,11 @@ 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{}因为它可能是多种类型 - UserID interface{} `json:"user_id"` // 这里使用interface{}因为它可能是多种类型 + GroupID interface{} `json:"group_id"` // 每一种onebotv11实现的字段类型都可能不同 + Message interface{} `json:"message"` // 这里使用interface{}因为它可能是多种类型 + UserID interface{} `json:"user_id"` // 这里使用interface{}因为它可能是多种类型 + Duration int `json:"duration,omitempty"` // 可选的整数 + Enable bool `json:"enable,omitempty"` // 可选的布尔值 } // 自定义一个ParamsContent的UnmarshalJSON 让GroupID同时兼容str和int @@ -68,6 +70,7 @@ func (p *ParamsContent) UnmarshalJSON(data []byte) error { type Alias ParamsContent aux := &struct { GroupID interface{} `json:"group_id"` + UserID interface{} `json:"user_id"` *Alias }{ Alias: (*Alias)(p), @@ -86,6 +89,18 @@ func (p *ParamsContent) UnmarshalJSON(data []byte) error { default: return fmt.Errorf("GroupID has unsupported type") } + + switch v := aux.UserID.(type) { + case nil: // 当UserID不存在时 + p.UserID = "" + case float64: // JSON的数字默认被解码为float64 + p.UserID = fmt.Sprintf("%.0f", v) // 将其转换为字符串,忽略小数点后的部分 + case string: + p.UserID = v + default: + return fmt.Errorf("UserID has unsupported type") + } + return nil } @@ -99,7 +114,8 @@ type Message struct { // 这是一个接口,在wsclient传入client但不需要引用wsclient包,避免循环引用 type Client interface { SendMessage(message map[string]interface{}) error - GetAppID() string + GetAppID() uint64 + GetAppIDStr() string } // 根据action订阅handler处理api diff --git a/config/config.go b/config/config.go index 8019b144..2d0f37a0 100644 --- a/config/config.go +++ b/config/config.go @@ -101,3 +101,25 @@ func GetPortValue() string { } return instance.Settings.Port } + +// 获取Array的值 +func GetArrayValue() bool { + mu.Lock() + defer mu.Unlock() + + if instance == nil { + log.Println("Warning: instance is nil when trying to get array value.") + return false + } + return instance.Settings.Array +} + +// 获取AppID +func GetAppID() uint64 { + mu.Lock() + defer mu.Unlock() + if instance != nil { + return instance.Settings.AppID + } + return 0 // or whatever default value you'd like to return if instance is nil +} diff --git a/config_template.go b/config_template.go index 69999947..edb75ad5 100644 --- a/config_template.go +++ b/config_template.go @@ -26,7 +26,7 @@ settings: global_private_to_channel: false # 是否将私聊转换成频道 array: false - server_dir: ":" # 提供图片上传服务的服务器(图床)需要带端口号. 如果需要发base64图,需为公网ip,且开放对应端口 + server_dir: "" # 提供图片上传服务的服务器(图床)需要带端口号. 如果需要发base64图,需为公网ip,且开放对应端口 port: "" # idmaps和图床对外开放的端口号 lotus: false # lotus特性默认为false,当为true时,将会连接到另一个lotus为false的gensokyo。 # 使用它提供的图床和idmaps服务(场景:同一个机器人在不同服务器运行,或内网需要发送base64图)。 diff --git a/config_template.yml b/config_template.yml index bbfd3259..dc534926 100644 --- a/config_template.yml +++ b/config_template.yml @@ -23,7 +23,7 @@ settings: global_private_to_channel: false # 是否将私聊转换成频道 array: false - server_dir: ":" # 提供图片上传服务的服务器(图床)需要带端口号. 如果需要发base64图,需为公网ip,且开放对应端口 + server_dir: "" # 提供图片上传服务的服务器(图床)需要带端口号. 如果需要发base64图,需为公网ip,且开放对应端口 port: "" # idmaps和图床对外开放的端口号 lotus: false # lotus特性默认为false,当为true时,将会连接到另一个lotus为false的gensokyo。 # 使用它提供的图床和idmaps服务(场景:同一个机器人在不同服务器运行,或内网需要发送base64图)。 diff --git a/handlers/get_friend_list.go b/handlers/get_friend_list.go new file mode 100644 index 00000000..313b2630 --- /dev/null +++ b/handlers/get_friend_list.go @@ -0,0 +1,63 @@ +package handlers + +import ( + "encoding/json" + "log" + + "github.com/hoshinonyaruko/gensokyo/callapi" + "github.com/tencent-connect/botgo/openapi" +) + +func init() { + callapi.RegisterHandler("get_friend_list", handleGetFriendList) +} + +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"` +} + +func handleGetFriendList(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) { + 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) + } + + output.Message = "" + output.RetCode = 0 + output.Status = "ok" + + output.Echo = message.Echo + + // Convert the APIOutput structure to a map[string]interface{} + outputMap := structToMap(output) + + // Send the map + err := client.SendMessage(outputMap) //发回去 + if err != nil { + log.Printf("error sending friend list via wsclient: %v", err) + } + + result, err := json.Marshal(output) + if err != nil { + log.Printf("Error marshaling data: %v", err) + return + } + + log.Printf("get_friend_list: %s", result) +} diff --git a/handlers/get_group_info.go b/handlers/get_group_info.go index 3464a97d..21cc3028 100644 --- a/handlers/get_group_info.go +++ b/handlers/get_group_info.go @@ -77,7 +77,7 @@ func handleGetGroupInfo(client callapi.Client, api openapi.OpenAPI, apiv2 openap groupInfoMap := structToMap(groupInfo) // 打印groupInfoMap的内容 - log.Printf("groupInfoMap(频道): %+v/n", groupInfoMap) + log.Printf("groupInfoMap(频道): %+v\n", groupInfoMap) err = client.SendMessage(groupInfoMap) //发回去 if err != nil { diff --git a/handlers/get_group_list.go b/handlers/get_group_list.go new file mode 100644 index 00000000..604a1327 --- /dev/null +++ b/handlers/get_group_list.go @@ -0,0 +1,154 @@ +package handlers + +import ( + "context" + "encoding/json" + "log" + "strconv" + "time" + + "github.com/hoshinonyaruko/gensokyo/callapi" + "github.com/tencent-connect/botgo/dto" + "github.com/tencent-connect/botgo/openapi" +) + +func init() { + callapi.RegisterHandler("get_group_list", getGroupList) +} + +type Guild struct { + JoinedAt string `json:"joined_at"` + ID string `json:"id"` + OwnerID string `json:"owner_id"` + Description string `json:"description"` + Name string `json:"name"` + MaxMembers string `json:"max_members"` + MemberCount string `json:"member_count"` +} + +type Group struct { + GroupCreateTime string `json:"group_create_time"` + GroupID string `json:"group_id"` + GroupLevel string `json:"group_level"` + GroupMemo string `json:"group_memo"` + GroupName string `json:"group_name"` + MaxMemberCount string `json:"max_member_count"` + MemberCount string `json:"member_count"` +} + +type GroupList struct { + Data []Group `json:"data"` + Message string `json:"message"` + RetCode int `json:"retcode"` + Status string `json:"status"` + Echo interface{} `json:"echo"` +} + +func getGroupList(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) { + + //群还不支持,这里取得是频道的,如果后期支持了群,那都请求,一起返回 + + // 初始化pager + pager := &dto.GuildPager{ + Limit: "400", + } + + guilds, err := api.MeGuilds(context.TODO(), pager) + if err != nil { + log.Println("Error fetching guild list:", err) + // 创建虚拟的Group + virtualGroup := Group{ + GroupCreateTime: time.Now().Format(time.RFC3339), + GroupID: "0000000", // 或其他虚拟值 + GroupLevel: "0", + GroupMemo: "Error Fetching Guilds", + GroupName: "Error Guild", + MaxMemberCount: "0", + MemberCount: "0", + } + + // 创建包含虚拟Group的GroupList + groupList := GroupList{ + Data: []Group{virtualGroup}, + Message: "Error fetching guilds", + RetCode: -1, // 可以使用其他的错误代码 + Status: "error", + Echo: "0", + } + + if message.Echo == "" { + groupList.Echo = "0" + } else { + groupList.Echo = message.Echo + + outputMap := structToMap(groupList) + + log.Printf("getGroupList(频道): %+v\n", outputMap) + + err = client.SendMessage(outputMap) + if err != nil { + log.Printf("error sending group info via wsclient: %v", err) + } + + result, err := json.Marshal(groupList) + if err != nil { + log.Printf("Error marshaling data: %v", err) + return + } + + log.Printf("get_group_list: %s", result) + return + } + } + + var groups []Group + for _, guild := range guilds { + joinedAtTime, err := guild.JoinedAt.Time() + if err != nil { + log.Println("Error parsing JoinedAt timestamp:", err) + continue + } + joinedAtStr := joinedAtTime.Format(time.RFC3339) // or any other format you prefer + + group := Group{ + GroupCreateTime: joinedAtStr, + GroupID: guild.ID, + GroupLevel: guild.OwnerID, + GroupMemo: guild.Desc, + GroupName: guild.Name, + MaxMemberCount: strconv.FormatInt(guild.MaxMembers, 10), + MemberCount: strconv.Itoa(guild.MemberCount), + // Add other fields if necessary + } + groups = append(groups, group) + } + + groupList := GroupList{ + Data: groups, + Message: "", + RetCode: 0, + Status: "ok", + } + if message.Echo == "" { + groupList.Echo = "0" + } else { + groupList.Echo = message.Echo + + outputMap := structToMap(groupList) + + log.Printf("getGroupList(频道): %+v\n", outputMap) + + err = client.SendMessage(outputMap) + if err != nil { + log.Printf("error sending group info via wsclient: %v", err) + } + + result, err := json.Marshal(groupList) + if err != nil { + log.Printf("Error marshaling data: %v", err) + return + } + + log.Printf("get_group_list: %s", result) + } +} diff --git a/handlers/get_group_member_list.go b/handlers/get_group_member_list.go new file mode 100644 index 00000000..b3c71333 --- /dev/null +++ b/handlers/get_group_member_list.go @@ -0,0 +1,96 @@ +package handlers + +import ( + "context" + "log" + "time" + + "github.com/hoshinonyaruko/gensokyo/callapi" + "github.com/hoshinonyaruko/gensokyo/idmap" + "github.com/tencent-connect/botgo/dto" + "github.com/tencent-connect/botgo/openapi" +) + +// Member Onebot 群成员 +type MemberList struct { + UserID string `json:"user_id"` + GroupID string `json:"group_id"` + Nickname string `json:"nickname"` + Role string `json:"role"` + JoinTime string `json:"join_time"` + LastSentTime string `json:"last_sent_time"` +} + +func init() { + callapi.RegisterHandler("get_group_member_list", getGroupMemberList) +} + +func getGroupMemberList(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) { + + msgType, err := idmap.ReadConfigv2(message.Params.GroupID.(string), "type") + if err != nil { + log.Printf("Error reading config: %v", err) + return + } + + switch msgType { + case "group": + log.Printf("getGroupMemberList(频道): 目前暂未开放该能力") + return + case "private": + log.Printf("getGroupMemberList(频道): 目前暂未适配私聊虚拟群场景获取虚拟群列表能力") + return + case "guild": + pager := &dto.GuildMembersPager{ + Limit: "400", + } + membersFromAPI, err := api.GuildMembers(context.TODO(), message.Params.GroupID.(string), pager) + if err != nil { + log.Printf("Failed to fetch group members for guild %s: %v", message.Params.GroupID.(string), err) + return + } + + var members []MemberList + for _, memberFromAPI := range membersFromAPI { + joinedAtTime, err := memberFromAPI.JoinedAt.Time() + if err != nil { + log.Println("Error parsing JoinedAt timestamp:", err) + continue + } + joinedAtStr := joinedAtTime.Format(time.RFC3339) // or any other format + + member := MemberList{ + UserID: memberFromAPI.User.ID, + GroupID: message.Params.GroupID.(string), + Nickname: memberFromAPI.Nick, + JoinTime: joinedAtStr, + } + for _, role := range memberFromAPI.Roles { + switch role { + case "4": + member.Role = "owner" + case "2": + member.Role = "admin" + case "11", "default": + member.Role = "member" + } + if member.Role == "owner" || member.Role == "admin" { + break + } + } + members = append(members, member) + } + + // Convert the APIOutput structure to a map[string]interface{} + outputMap := structToMap(members) + + log.Printf("getGroupMemberList(频道): %+v\n", outputMap) + + err = client.SendMessage(outputMap) //发回去 + if err != nil { + log.Printf("Error sending message via client: %v", err) + } + default: + log.Printf("Unknown msgType: %s", msgType) + } +} diff --git a/handlers/get_guild_channel_list.go b/handlers/get_guild_channel_list.go new file mode 100644 index 00000000..c2f0acb6 --- /dev/null +++ b/handlers/get_guild_channel_list.go @@ -0,0 +1,41 @@ +package handlers + +import ( + "log" + + "github.com/hoshinonyaruko/gensokyo/callapi" + "github.com/tencent-connect/botgo/openapi" +) + +type GuildChannelListResponse struct { + Data []interface{} `json:"data"` + Message string `json:"message"` + RetCode int `json:"retcode"` + Status string `json:"status"` + Echo interface{} `json:"echo"` +} + +func init() { + callapi.RegisterHandler("get_guild_channel_list", getGuildChannelList) +} + +func getGuildChannelList(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) { + + var response GuildChannelListResponse + + response.Data = make([]interface{}, 0) // No data at the moment, but can be populated in the future + response.Message = "" + response.RetCode = 0 + response.Status = "ok" + response.Echo = message.Echo + + // Convert the members slice to a map + outputMap := structToMap(response) + + log.Printf("get_guild_channel_list: %s", outputMap) + + err := client.SendMessage(outputMap) //发回去 + if err != nil { + log.Printf("Error sending message via client: %v", err) + } +} diff --git a/handlers/get_guild_list.go b/handlers/get_guild_list.go new file mode 100644 index 00000000..97036ae7 --- /dev/null +++ b/handlers/get_guild_list.go @@ -0,0 +1,58 @@ +package handlers + +import ( + "log" + + "github.com/hoshinonyaruko/gensokyo/callapi" + "github.com/tencent-connect/botgo/openapi" +) + +type GuildListResponse struct { + Data []GuildData `json:"data"` + Message string `json:"message"` + RetCode int `json:"retcode"` + Status string `json:"status"` + Echo interface{} `json:"echo"` +} + +type GuildData struct { + GuildID string `json:"guild_id"` + GuildName string `json:"guild_name"` + GuildDisplayID string `json:"guild_display_id"` +} + +func init() { + callapi.RegisterHandler("get_guild_list", getGuildList) +} + +func getGuildList(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) { + + var response GuildListResponse + + // Assuming 'a' is some value you want to loop till. + a := 1 // Replace with appropriate value + + for i := 1; i <= a; i++ { + guildData := GuildData{ + GuildID: "0", + GuildName: "868858989", + GuildDisplayID: "868858989", + } + response.Data = append(response.Data, guildData) + } + + response.Message = "" + response.RetCode = 0 + response.Status = "ok" + response.Echo = string(message.Echo) // Directly assign the string value + + // Convert the members slice to a map + outputMap := structToMap(response) + + log.Printf("getGuildList(频道): %+v\n", outputMap) + + err := client.SendMessage(outputMap) + if err != nil { + log.Printf("Error sending message via client: %v", err) + } +} diff --git a/handlers/get_guild_service_profile.go b/handlers/get_guild_service_profile.go new file mode 100644 index 00000000..b4305e09 --- /dev/null +++ b/handlers/get_guild_service_profile.go @@ -0,0 +1,51 @@ +package handlers + +import ( + "log" + + "github.com/hoshinonyaruko/gensokyo/callapi" + "github.com/tencent-connect/botgo/openapi" +) + +type GuildServiceProfileResponse struct { + Data GuildServiceProfileData `json:"data"` + Message string `json:"message"` + RetCode int `json:"retcode"` + Status string `json:"status"` + Echo interface{} `json:"echo"` +} + +type GuildServiceProfileData struct { + Nickname string `json:"nickname"` + TinyID int64 `json:"tiny_id"` +} + +func init() { + callapi.RegisterHandler("get_guild_service_profile", getGuildServiceProfile) +} + +func getGuildServiceProfile(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) { + + var response GuildServiceProfileResponse + + response.Data = GuildServiceProfileData{ + Nickname: "", + TinyID: 0, + } + response.Message = "" + response.RetCode = 0 + response.Status = "ok" + response.Echo = string(message.Echo) // Directly assign the string value + + // Convert the members slice to a map + outputMap := structToMap(response) + + log.Printf("get_guild_service_profile: %+v/n", outputMap) + + err := client.SendMessage(outputMap) + if err != nil { + log.Printf("Error sending message via client: %v", err) + } else { + log.Printf("响应get_guild_service_profile: %+v", outputMap) + } +} diff --git a/handlers/get_login_info.go b/handlers/get_login_info.go new file mode 100644 index 00000000..1ac51b61 --- /dev/null +++ b/handlers/get_login_info.go @@ -0,0 +1,59 @@ +package handlers + +import ( + "fmt" + "log" + + "github.com/hoshinonyaruko/gensokyo/callapi" + "github.com/hoshinonyaruko/gensokyo/config" + "github.com/tencent-connect/botgo/openapi" +) + +type LoginInfoResponse struct { + Data LoginInfoData `json:"data"` + Message string `json:"message"` + RetCode int `json:"retcode"` + Status string `json:"status"` + Echo interface{} `json:"echo"` +} + +type LoginInfoData struct { + Nickname string `json:"nickname"` + UserID string `json:"user_id"` // Assuming UserID is a string type based on the pseudocode +} + +func init() { + callapi.RegisterHandler("get_login_info", getLoginInfo) +} + +func getLoginInfo(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) { + + var response LoginInfoResponse + + // Assuming 全局_botid is a global or environment variable + globalBotID := config.GetAppID() // Replace with the actual global variable or value + userIDStr := fmt.Sprintf("%d", globalBotID) + + response.Data = LoginInfoData{ + Nickname: "gensokyo全域机器人", + UserID: userIDStr, + } + response.Message = "" + response.RetCode = 0 + response.Status = "ok" + response.Echo = string(message.Echo) + + // Convert the members slice to a map + outputMap := structToMap(response) + + log.Printf("get_login_info: %+v\n", outputMap) + + err := client.SendMessage(outputMap) + if err != nil { + log.Printf("Error sending message via client: %v", err) + } else { + log.Printf("响应get_login_info: %+v", outputMap) + } + + return +} diff --git a/handlers/get_online_clients.go b/handlers/get_online_clients.go new file mode 100644 index 00000000..6e82aeae --- /dev/null +++ b/handlers/get_online_clients.go @@ -0,0 +1,51 @@ +package handlers + +import ( + "log" + + "github.com/hoshinonyaruko/gensokyo/callapi" + "github.com/tencent-connect/botgo/openapi" +) + +type OnlineClientsResponse struct { + Data OnlineClientsData `json:"data"` + Message string `json:"message"` + RetCode int `json:"retcode"` + Status string `json:"status"` + Echo interface{} `json:"echo"` +} + +type OnlineClientsData struct { + Clients []interface{} `json:"clients"` // It seems you want an empty array for clients + TinyID int64 `json:"tiny_id"` +} + +func init() { + callapi.RegisterHandler("get_online_clients", getOnlineClients) +} + +func getOnlineClients(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) { + + var response OnlineClientsResponse + + response.Data = OnlineClientsData{ + Clients: make([]interface{}, 0), // Empty array + TinyID: 0, + } + response.Message = "" + response.RetCode = 0 + response.Status = "ok" + response.Echo = string(message.Echo) + + // Convert the members slice to a map + outputMap := structToMap(response) + + log.Printf("get_online_clients: %+v\n", outputMap) + + err := client.SendMessage(outputMap) + if err != nil { + log.Printf("Error sending message via client: %v", err) + } else { + log.Printf("响应get_online_clients: %+v", outputMap) + } +} diff --git a/handlers/get_version_info.go b/handlers/get_version_info.go new file mode 100644 index 00000000..4431a6b2 --- /dev/null +++ b/handlers/get_version_info.go @@ -0,0 +1,73 @@ +package handlers + +import ( + "log" + + "github.com/hoshinonyaruko/gensokyo/callapi" + "github.com/tencent-connect/botgo/openapi" +) + +type VersionInfoResponse struct { + Data VersionData `json:"data"` + Message string `json:"message"` + RetCode int `json:"retcode"` + Status string `json:"status"` + Echo interface{} `json:"echo"` +} + +type VersionData struct { + AppFullName string `json:"app_full_name"` + AppName string `json:"app_name"` + AppVersion string `json:"app_version"` + CoolQDirectory string `json:"coolq_directory"` + CoolQEdition string `json:"coolq_edition"` + GoCQHTTP bool `json:"go-cqhttp"` + PluginBuildConfiguration string `json:"plugin_build_configuration"` + PluginBuildNumber int `json:"plugin_build_number"` + PluginVersion string `json:"plugin_version"` + ProtocolName int `json:"protocol_name"` + ProtocolVersion string `json:"protocol_version"` + RuntimeOS string `json:"runtime_os"` + RuntimeVersion string `json:"runtime_version"` + Version string `json:"version"` +} + +func init() { + callapi.RegisterHandler("get_version_info", getVersionInfo) +} + +func getVersionInfo(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) { + + var response VersionInfoResponse + + response.Data = VersionData{ + AppFullName: "gensokyo", + AppName: "gensokyo", + AppVersion: "v1.0.0", + CoolQDirectory: "", + CoolQEdition: "pro", + GoCQHTTP: true, + PluginBuildConfiguration: "release", + PluginBuildNumber: 99, + PluginVersion: "4.15.0", + ProtocolName: 4, + ProtocolVersion: "v11", + RuntimeOS: "windows", + RuntimeVersion: "go1.20.2", + Version: "v1.0.0", + } + response.Message = "" + response.RetCode = 0 + response.Status = "ok" + response.Echo = string(message.Echo) // Directly assign the string value + + // Convert the members slice to a map + outputMap := structToMap(response) + + log.Printf("get_version_info: %+v/n", outputMap) + + err := client.SendMessage(outputMap) + if err != nil { + log.Printf("Error sending message via client: %v", err) + } +} diff --git a/handlers/message_parser.go b/handlers/message_parser.go index 58dc8a31..3c98a62d 100644 --- a/handlers/message_parser.go +++ b/handlers/message_parser.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/hoshinonyaruko/gensokyo/callapi" + "github.com/tencent-connect/botgo/dto" ) var BotID string @@ -116,6 +117,7 @@ func transformMessageText(messageText string) string { }) } +// 处理at和其他定形文到onebotv11格式(cq码) func RevertTransformedText(messageText string) string { // Trim leading and trailing spaces messageText = strings.TrimSpace(messageText) @@ -134,3 +136,77 @@ func RevertTransformedText(messageText string) string { return m }) } + +// 将收到的data.content转换为message segment todo,群场景不支持受图片,频道场景的图片可以拼一下 +func ConvertToSegmentedMessage(data interface{}) []map[string]interface{} { + // 强制类型转换,获取Message结构 + var msg *dto.Message + switch v := data.(type) { + case *dto.WSGroupATMessageData: + msg = (*dto.Message)(v) + case *dto.WSATMessageData: + msg = (*dto.Message)(v) + case *dto.WSMessageData: + msg = (*dto.Message)(v) + case *dto.WSDirectMessageData: + msg = (*dto.Message)(v) + case *dto.WSC2CMessageData: + msg = (*dto.Message)(v) + default: + return nil + } + + var messageSegments []map[string]interface{} + + // 处理Attachments字段来构建图片消息 + for _, attachment := range msg.Attachments { + imageFileMD5 := attachment.FileName + for _, ext := range []string{"{", "}", ".png", ".jpg", ".gif", "-"} { + imageFileMD5 = strings.ReplaceAll(imageFileMD5, ext, "") + } + imageSegment := map[string]interface{}{ + "type": "image", + "data": map[string]interface{}{ + "file": imageFileMD5 + ".image", + "subType": "0", + "url": attachment.URL, + }, + } + messageSegments = append(messageSegments, imageSegment) + + // 在msg.Content中替换旧的图片链接 + newImagePattern := "[CQ:image,file=" + attachment.URL + "]" + msg.Content = msg.Content + newImagePattern + } + + // 使用正则表达式查找所有的[@数字]格式 + r := regexp.MustCompile(`<@!(\d+)>`) + atMatches := r.FindAllStringSubmatch(msg.Content, -1) + + for _, match := range atMatches { + // 构建at部分的映射并加入到messageSegments + atSegment := map[string]interface{}{ + "type": "at", + "data": map[string]interface{}{ + "qq": match[1], + }, + } + messageSegments = append(messageSegments, atSegment) + + // 从原始内容中移除at部分 + msg.Content = strings.Replace(msg.Content, match[0], "", 1) + } + + // 如果还有其他内容,那么这些内容被视为文本部分 + if msg.Content != "" { + textSegment := map[string]interface{}{ + "type": "text", + "data": map[string]interface{}{ + "text": msg.Content, + }, + } + messageSegments = append(messageSegments, textSegment) + } + + return messageSegments +} diff --git a/handlers/send_group_msg.go b/handlers/send_group_msg.go index 18115504..76091c21 100644 --- a/handlers/send_group_msg.go +++ b/handlers/send_group_msg.go @@ -27,12 +27,12 @@ func handleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap //如果获取不到 就用user_id获取信息类型 if msgType == "" { - msgType = GetMessageTypeByUserid(client.GetAppID(), message.Params.UserID) + msgType = GetMessageTypeByUserid(client.GetAppIDStr(), message.Params.UserID) } //如果获取不到 就用group_id获取信息类型 if msgType == "" { - msgType = GetMessageTypeByGroupid(client.GetAppID(), message.Params.GroupID) + msgType = GetMessageTypeByGroupid(client.GetAppIDStr(), message.Params.GroupID) } switch msgType { @@ -50,7 +50,7 @@ func handleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap log.Println("foundItems:", foundItems) // 如果messageID为空,通过函数获取 if messageID == "" { - messageID = GetMessageIDByUseridOrGroupid(client.GetAppID(), message.Params.GroupID) + messageID = GetMessageIDByUseridOrGroupid(client.GetAppIDStr(), message.Params.GroupID) log.Println("通过GetMessageIDByUserid函数获取的message_id:", messageID) } @@ -64,7 +64,7 @@ func handleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap // 优先发送文本信息 if messageText != "" { - groupReply := generateMessage(messageID, nil, messageText) + groupReply := generateGroupMessage(messageID, nil, messageText) // 进行类型断言 groupMessage, ok := groupReply.(*dto.MessageToCreate) @@ -85,7 +85,7 @@ func handleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap var singleItem = make(map[string][]string) singleItem[key] = urls - groupReply := generateMessage(messageID, singleItem, "") + groupReply := generateGroupMessage(messageID, singleItem, "") // 进行类型断言 richMediaMessage, ok := groupReply.(*dto.RichMediaMessage) @@ -123,16 +123,8 @@ func handleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap handleSendGuildChannelPrivateMsg(client, api, apiv2, message, &value, &message.Params.ChannelID) case "group_private": //用userid还原出openid 这是虚拟成群的群聊私聊信息 - //todo - message.Params.ChannelID = message.Params.GroupID.(string) - //读取ini 通过ChannelID取回之前储存的guild_id - value, err := idmap.ReadConfigv2(message.Params.ChannelID, "guild_id") - if err != nil { - log.Printf("Error reading config: %v", err) - return - } - message.Params.GroupID = value - handleSendGuildChannelMsg(client, api, apiv2, message) + message.Params.UserID = message.Params.GroupID.(string) + handleSendPrivateMsg(client, api, apiv2, message) default: log.Printf("Unknown message type: %s", msgType) } diff --git a/handlers/send_guild_channel_msg.go b/handlers/send_guild_channel_msg.go index 99085d24..71e47fe4 100644 --- a/handlers/send_guild_channel_msg.go +++ b/handlers/send_guild_channel_msg.go @@ -25,12 +25,12 @@ func handleSendGuildChannelMsg(client callapi.Client, api openapi.OpenAPI, apiv2 //如果获取不到 就用user_id获取信息类型 if msgType == "" { - msgType = GetMessageTypeByUserid(client.GetAppID(), message.Params.UserID) + msgType = GetMessageTypeByUserid(client.GetAppIDStr(), message.Params.UserID) } //如果获取不到 就用group_id获取信息类型 if msgType == "" { - appID := client.GetAppID() + appID := client.GetAppIDStr() groupID := message.Params.GroupID fmt.Printf("appID: %s, GroupID: %v\n", appID, groupID) diff --git a/handlers/send_msg.go b/handlers/send_msg.go index 4c4caf01..e20753d4 100644 --- a/handlers/send_msg.go +++ b/handlers/send_msg.go @@ -27,7 +27,7 @@ func handleSendMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.Ope //如果获取不到 就用group_id获取信息类型 if msgType == "" { - appID := client.GetAppID() + appID := client.GetAppIDStr() groupID := message.Params.GroupID fmt.Printf("appID: %s, GroupID: %v\n", appID, groupID) @@ -37,7 +37,7 @@ func handleSendMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.Ope //如果获取不到 就用user_id获取信息类型 if msgType == "" { - msgType = GetMessageTypeByUserid(client.GetAppID(), message.Params.UserID) + msgType = GetMessageTypeByUserid(client.GetAppIDStr(), message.Params.UserID) } switch msgType { @@ -55,7 +55,7 @@ func handleSendMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.Ope log.Println("foundItems:", foundItems) // 如果messageID为空,通过函数获取 if messageID == "" { - messageID = GetMessageIDByUseridOrGroupid(client.GetAppID(), message.Params.GroupID) + messageID = GetMessageIDByUseridOrGroupid(client.GetAppIDStr(), message.Params.GroupID) log.Println("通过GetMessageIDByUserid函数获取的message_id:", messageID) } @@ -143,17 +143,62 @@ func handleSendMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.Ope handleSendGuildChannelPrivateMsg(client, api, apiv2, message, GuildidPtr, channelIDPtr) case "group_private": - //用userid还原出openid 这是虚拟成群的群聊私聊信息 - //todo - message.Params.ChannelID = message.Params.GroupID.(string) - //读取ini 通过ChannelID取回之前储存的guild_id - value, err := idmap.ReadConfigv2(message.Params.ChannelID, "guild_id") + //私聊信息 + //还原真实的userid + UserID, err := idmap.RetrieveRowByIDv2(message.Params.UserID.(string)) if err != nil { log.Printf("Error reading config: %v", err) return } - message.Params.GroupID = value - handleSendGuildChannelMsg(client, api, apiv2, message) + + // 解析消息内容 + messageText, foundItems := parseMessageContent(message.Params) + + // 获取 echo 的值 + echostr := string(message.Echo) + + // 使用 echo 获取消息ID + messageID := echo.GetMsgIDByKey(echostr) + log.Println("私聊发信息对应的message_id:", messageID) + log.Println("私聊发信息messageText:", messageText) + log.Println("foundItems:", foundItems) + + // 优先发送文本信息 + if messageText != "" { + groupReply := generateMessage(messageID, nil, messageText) + + // 进行类型断言 + groupMessage, ok := groupReply.(*dto.MessageToCreate) + if !ok { + log.Println("Error: Expected MessageToCreate type.") + return + } + + groupMessage.Timestamp = time.Now().Unix() // 设置时间戳 + _, err := apiv2.PostC2CMessage(context.TODO(), UserID, groupMessage) + if err != nil { + log.Printf("发送文本私聊信息失败: %v", err) + } + } + + // 遍历 foundItems 并发送每种信息 + for key, urls := range foundItems { + var singleItem = make(map[string][]string) + singleItem[key] = urls + + groupReply := generateMessage(messageID, singleItem, "") + + // 进行类型断言 + richMediaMessage, ok := groupReply.(*dto.RichMediaMessage) + if !ok { + log.Printf("Error: Expected RichMediaMessage type for key %s.", key) + continue + } + _, err := apiv2.PostC2CMessage(context.TODO(), UserID, richMediaMessage) + if err != nil { + log.Printf("发送 %s 私聊信息失败: %v", key, err) + } + } default: log.Printf("1Unknown message type: %s", msgType) } diff --git a/handlers/send_private_msg.go b/handlers/send_private_msg.go index 2d52727c..68423f61 100644 --- a/handlers/send_private_msg.go +++ b/handlers/send_private_msg.go @@ -25,6 +25,14 @@ func handleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open switch msgType { case "group_private": + //私聊信息 + //还原真实的userid + UserID, err := idmap.RetrieveRowByIDv2(message.Params.UserID.(string)) + if err != nil { + log.Printf("Error reading config: %v", err) + return + } + // 解析消息内容 messageText, foundItems := parseMessageContent(message.Params) @@ -33,18 +41,10 @@ func handleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open // 使用 echo 获取消息ID messageID := echo.GetMsgIDByKey(echostr) - log.Println("群组发信息对应的message_id:", messageID) - log.Println("群组发信息messageText:", messageText) + log.Println("私聊发信息对应的message_id:", messageID) + log.Println("私聊发信息messageText:", messageText) log.Println("foundItems:", foundItems) - //通过bolt数据库还原真实的GroupID - originalGroupID, err := idmap.RetrieveRowByIDv2(message.Params.GroupID.(string)) - if err != nil { - log.Printf("Error retrieving original GroupID: %v", err) - return - } - message.Params.GroupID = originalGroupID - // 优先发送文本信息 if messageText != "" { groupReply := generatePrivateMessage(messageID, nil, messageText) @@ -53,17 +53,17 @@ func handleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open groupMessage, ok := groupReply.(*dto.MessageToCreate) if !ok { log.Println("Error: Expected MessageToCreate type.") - return // 或其他错误处理 + return } groupMessage.Timestamp = time.Now().Unix() // 设置时间戳 - _, err := apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), groupMessage) + _, err := apiv2.PostC2CMessage(context.TODO(), UserID, groupMessage) if err != nil { - log.Printf("发送文本群组信息失败: %v", err) + log.Printf("发送文本私聊信息失败: %v", err) } } - // 遍历foundItems并发送每种信息 + // 遍历 foundItems 并发送每种信息 for key, urls := range foundItems { var singleItem = make(map[string][]string) singleItem[key] = urls @@ -74,13 +74,11 @@ func handleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open richMediaMessage, ok := groupReply.(*dto.RichMediaMessage) if !ok { log.Printf("Error: Expected RichMediaMessage type for key %s.", key) - continue // 跳过这个项,继续下一个 + continue } - - //richMediaMessage.Timestamp = time.Now().Unix() // 设置时间戳 - _, err := apiv2.PostGroupMessage(context.TODO(), message.Params.GroupID.(string), richMediaMessage) + _, err := apiv2.PostC2CMessage(context.TODO(), UserID, richMediaMessage) if err != nil { - log.Printf("发送 %s 信息失败: %v", key, err) + log.Printf("发送 %s 私聊信息失败: %v", key, err) } } case "guild_private": @@ -151,7 +149,7 @@ func handleSendGuildChannelPrivateMsg(client callapi.Client, api openapi.OpenAPI log.Println("foundItems:", foundItems) // 如果messageID为空,通过函数获取 if messageID == "" { - messageID = GetMessageIDByUseridOrGroupid(client.GetAppID(), message.Params.UserID) + messageID = GetMessageIDByUseridOrGroupid(client.GetAppIDStr(), message.Params.UserID) log.Println("通过GetMessageIDByUserid函数获取的message_id:", messageID) } diff --git a/handlers/set_group_ban.go b/handlers/set_group_ban.go new file mode 100644 index 00000000..affb142b --- /dev/null +++ b/handlers/set_group_ban.go @@ -0,0 +1,65 @@ +package handlers + +import ( + "context" + "log" + "strconv" + + "github.com/hoshinonyaruko/gensokyo/callapi" + "github.com/hoshinonyaruko/gensokyo/idmap" + "github.com/tencent-connect/botgo/dto" + "github.com/tencent-connect/botgo/openapi" +) + +func init() { + callapi.RegisterHandler("get_group_ban", setGroupBan) +} + +func setGroupBan(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) { + + // 从message中获取group_id和UserID + groupID := message.Params.GroupID.(string) + receivedUserID := message.Params.UserID.(string) + + // 根据group_id读取guild_id + guildID, err := idmap.ReadConfigv2(groupID, "guild_id") + if err != nil { + log.Printf("Error reading config for guild_id: %v", err) + return + } + + // 根据UserID读取真实的userid + realUserID, err := idmap.RetrieveRowByIDv2(receivedUserID) + if err != nil { + log.Printf("Error reading real userID: %v", err) + return + } + + // 读取消息类型 + msgType, err := idmap.ReadConfigv2(groupID, "type") + if err != nil { + log.Printf("Error reading config for message type: %v", err) + return + } + + // 根据消息类型进行操作 + switch msgType { + case "group": + log.Printf("setGroupBan(频道): 目前暂未开放该能力") + return + case "private": + log.Printf("setGroupBan(频道): 目前暂未适配私聊虚拟群场景的禁言能力") + return + case "guild": + duration := strconv.Itoa(message.Params.Duration) + mute := &dto.UpdateGuildMute{ + MuteSeconds: duration, + UserIDs: []string{realUserID}, + } + err := api.MemberMute(context.TODO(), guildID, realUserID, mute) + if err != nil { + log.Printf("Error muting member: %v", err) + } + return + } +} diff --git a/handlers/set_group_whole_ban.go b/handlers/set_group_whole_ban.go new file mode 100644 index 00000000..771dae55 --- /dev/null +++ b/handlers/set_group_whole_ban.go @@ -0,0 +1,60 @@ +package handlers + +import ( + "context" + "log" + + "github.com/hoshinonyaruko/gensokyo/callapi" + "github.com/hoshinonyaruko/gensokyo/idmap" + "github.com/tencent-connect/botgo/dto" + "github.com/tencent-connect/botgo/openapi" +) + +func init() { + callapi.RegisterHandler("get_group_whole_ban", setGroupBan) +} + +func setGroupWholeBan(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) { + // 从message中获取group_id + groupID := message.Params.GroupID.(string) + + // 根据group_id读取guild_id + guildID, err := idmap.ReadConfigv2(groupID, "guild_id") + if err != nil { + log.Printf("Error reading config for guild_id: %v", err) + return + } + + // 读取消息类型 + msgType, err := idmap.ReadConfigv2(groupID, "type") + if err != nil { + log.Printf("Error reading config for message type: %v", err) + return + } + + // 根据消息类型进行操作 + switch msgType { + case "group": + log.Printf("setGroupWholeBan(频道): 目前暂未开放该能力") + return + case "private": + log.Printf("setGroupWholeBan(频道): 目前暂未适配私聊虚拟群场景的禁言能力") + return + case "guild": + var duration string + if message.Params.Enable { + duration = "604800" // 7天: 60 * 60 * 24 * 7 onebot的全体禁言只有禁言和解开,先尝试7天 + } else { + duration = "0" + } + + mute := &dto.UpdateGuildMute{ + MuteSeconds: duration, + } + err := api.GuildMute(context.TODO(), guildID, mute) + if err != nil { + log.Printf("Error setting whole guild mute: %v", err) + } + return + } +} diff --git a/idmap/service.go b/idmap/service.go index 554b9a7a..d4f6202f 100644 --- a/idmap/service.go +++ b/idmap/service.go @@ -43,7 +43,7 @@ func CloseDB() { } // 根据a储存b -func StoreIDv2(id string) (int64, error) { +func StoreID(id string) (int64, error) { var newRow int64 err := db.Update(func(tx *bolt.Tx) error { @@ -79,8 +79,8 @@ func StoreIDv2(id string) (int64, error) { return newRow, err } -// StoreIDv2v2 根据a储存b -func StoreIDv2v2(id string) (int64, error) { +// StoreIDv2 根据a储存b +func StoreIDv2(id string) (int64, error) { if config.GetLotusValue() { // 使用网络请求方式 serverDir := config.GetServer_dir() @@ -112,11 +112,11 @@ func StoreIDv2v2(id string) (int64, error) { } // 如果lotus为假,就保持原来的store的方法 - return StoreIDv2(id) + return StoreID(id) } // 根据b得到a -func RetrieveRowByIDv2(rowid string) (string, error) { +func RetrieveRowByID(rowid string) (string, error) { var id string err := db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(BucketName)) @@ -134,8 +134,8 @@ func RetrieveRowByIDv2(rowid string) (string, error) { return id, err } -// RetrieveRowByIDv2v2 根据b得到a -func RetrieveRowByIDv2v2(rowid string) (string, error) { +// RetrieveRowByIDv2 根据b得到a +func RetrieveRowByIDv2(rowid string) (string, error) { if config.GetLotusValue() { // 使用网络请求方式 serverDir := config.GetServer_dir() @@ -167,11 +167,11 @@ func RetrieveRowByIDv2v2(rowid string) (string, error) { } // 如果lotus为假,就保持原来的RetrieveRowByIDv2的方法 - return RetrieveRowByIDv2(rowid) + return RetrieveRowByID(rowid) } // 根据a 以b为类别 储存c -func WriteConfigv2(sectionName, keyName, value string) error { +func WriteConfig(sectionName, keyName, value string) error { return db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte(ConfigBucket)) if err != nil { @@ -183,8 +183,8 @@ func WriteConfigv2(sectionName, keyName, value string) error { }) } -// WriteConfigv2v2 根据a以b为类别储存c -func WriteConfigv2v2(sectionName, keyName, value string) error { +// WriteConfigv2 根据a以b为类别储存c +func WriteConfigv2(sectionName, keyName, value string) error { if config.GetLotusValue() { // 使用网络请求方式 serverDir := config.GetServer_dir() @@ -213,11 +213,11 @@ func WriteConfigv2v2(sectionName, keyName, value string) error { } // 如果lotus为假,则使用原始方法在本地写入配置 - return WriteConfigv2(sectionName, keyName, value) + return WriteConfig(sectionName, keyName, value) } // 根据a和b取出c -func ReadConfigv2(sectionName, keyName string) (string, error) { +func ReadConfig(sectionName, keyName string) (string, error) { var result string err := db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(ConfigBucket)) @@ -238,8 +238,8 @@ func ReadConfigv2(sectionName, keyName string) (string, error) { return result, err } -// ReadConfigv2v2 根据a和b取出c -func ReadConfigv2v2(sectionName, keyName string) (string, error) { +// ReadConfigv2 根据a和b取出c +func ReadConfigv2(sectionName, keyName string) (string, error) { if config.GetLotusValue() { // 使用网络请求方式 serverDir := config.GetServer_dir() @@ -281,7 +281,7 @@ func ReadConfigv2v2(sectionName, keyName string) (string, error) { } // 如果lotus为假,则使用原始方法在本地读取配置 - return ReadConfigv2(sectionName, keyName) + return ReadConfig(sectionName, keyName) } // 灵感,ini配置文件 diff --git a/main.go b/main.go index 6b5938e3..924bab40 100644 --- a/main.go +++ b/main.go @@ -7,7 +7,6 @@ import ( "log" "os" "os/signal" - "strconv" "syscall" "time" @@ -87,16 +86,16 @@ func main() { apiV2 := botgo.NewOpenAPI(token).WithTimeout(3 * time.Second) // 执行API请求 显示机器人信息 - // me, err := api.Me(ctx) // Adjusted to pass only the context - // if err != nil { - // fmt.Printf("Error fetching bot details: %v\n", err) - // return - // } - // fmt.Printf("Bot details: %+v\n", me) + me, err := api.Me(ctx) // Adjusted to pass only the context + if err != nil { + fmt.Printf("Error fetching bot details: %v\n", err) + return + } + fmt.Printf("Bot details: %+v\n", me) //初始化handlers - //handlers.BotID = me.ID - handlers.BotID = "1234" + handlers.BotID = me.ID + //handlers.BotID = "1234" handlers.AppID = fmt.Sprintf("%d", conf.Settings.AppID) // 获取 websocket 信息 这里用哪一个api获取就是用哪一个api去连接ws @@ -139,8 +138,7 @@ func main() { // 在新的 go 函数中初始化 wsClient go func() { - appIDStr := strconv.FormatUint(conf.Settings.AppID, 10) // Assuming base 10 - wsClient, err := wsclient.NewWebSocketClient(conf.Settings.WsAddress, appIDStr, api, apiV2) + wsClient, err := wsclient.NewWebSocketClient(conf.Settings.WsAddress, conf.Settings.AppID, api, apiV2) if err != nil { fmt.Printf("Error creating WebSocketClient: %v\n", err) close(wsClientChan) // 关闭通道表示不再发送值 @@ -269,7 +267,8 @@ func GroupATMessageEventHandler() event.GroupATMessageEventHandler { // C2CMessageEventHandler 实现处理 群私聊 消息的回调 func C2CMessageEventHandler() event.C2CMessageEventHandler { return func(event *dto.WSPayload, data *dto.WSC2CMessageData) error { - return processor.ProcessC2CMessage(string(event.RawMessage), data) + log.Print("1111") + return processor.ProcessC2CMessage(data) } } diff --git a/wsclient/ws.go b/wsclient/ws.go index 6c01fd48..224259a0 100644 --- a/wsclient/ws.go +++ b/wsclient/ws.go @@ -17,14 +17,19 @@ type WebSocketClient struct { conn *websocket.Conn api openapi.OpenAPI apiv2 openapi.OpenAPI - appid string + appid uint64 } // 获取appid -func (c *WebSocketClient) GetAppID() string { +func (c *WebSocketClient) GetAppID() uint64 { return c.appid } +// 获取appid的字符串形式 +func (c *WebSocketClient) GetAppIDStr() string { + return fmt.Sprintf("%d", c.appid) +} + // 发送json信息给onebot应用端 func (c *WebSocketClient) SendMessage(message map[string]interface{}) error { msgBytes, err := json.Marshal(message) @@ -86,7 +91,7 @@ func truncateMessage(message callapi.ActionMessage, maxLength int) string { } // 发送心跳包 -func (c *WebSocketClient) sendHeartbeat(ctx context.Context, botID string) { +func (c *WebSocketClient) sendHeartbeat(ctx context.Context, botID uint64) { for { select { case <-ctx.Done(): @@ -105,11 +110,11 @@ func (c *WebSocketClient) sendHeartbeat(ctx context.Context, botID string) { } // NewWebSocketClient 创建 WebSocketClient 实例,接受 WebSocket URL、botID 和 openapi.OpenAPI 实例 -func NewWebSocketClient(urlStr string, botID string, api openapi.OpenAPI, apiv2 openapi.OpenAPI) (*WebSocketClient, error) { +func NewWebSocketClient(urlStr string, botID uint64, api openapi.OpenAPI, apiv2 openapi.OpenAPI) (*WebSocketClient, error) { headers := http.Header{ "User-Agent": []string{"CQHttp/4.15.0"}, "X-Client-Role": []string{"Universal"}, - "X-Self-ID": []string{botID}, + "X-Self-ID": []string{fmt.Sprintf("%d", botID)}, } dialer := websocket.Dialer{