Skip to content

Commit

Permalink
Beta356 (#365)
Browse files Browse the repository at this point in the history
* beta338

* beta319

* beta340

* beta341

* actionfix

* beta342

* beta342

* beta342

* beta344

* beta345

* beta346

* beta347

* beta348

* beta349

* beta350

* beta351

* beta352

* beta353

* beta354

* beta355

* beta356
  • Loading branch information
Hoshinonyaruko authored Mar 31, 2024
1 parent 36bb923 commit 690fd99
Show file tree
Hide file tree
Showing 6 changed files with 393 additions and 0 deletions.
67 changes: 67 additions & 0 deletions botgo/dto/message_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}
2 changes: 2 additions & 0 deletions botgo/openapi/iface.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 相关接口
Expand Down
21 changes: 21 additions & 0 deletions botgo/openapi/v1/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
21 changes: 21 additions & 0 deletions botgo/openapi/v2/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
229 changes: 229 additions & 0 deletions handlers/send_private_msg_sse.go
Original file line number Diff line number Diff line change
@@ -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

}
Loading

0 comments on commit 690fd99

Please sign in to comment.