From 8ed94abdecad80dad8d3919dbf7da9762f86100f Mon Sep 17 00:00:00 2001 From: Sheyiyuan <2125107118@qq.com> Date: Fri, 13 Dec 2024 22:04:56 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=86api=E5=BA=95?= =?UTF-8?q?=E5=B1=82=E5=B0=81=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LOG/log.go | 10 +++- core/api.go | 134 ++++++++++++--------------------------------- core/app_admin.go | 2 +- core/web_socket.go | 130 +++++++++++++++++++++---------------------- wba/wind.go | 96 ++++++++++++++++++++++++++++++++ 5 files changed, 204 insertions(+), 168 deletions(-) diff --git a/LOG/log.go b/LOG/log.go index f38f4b6..f721fe1 100644 --- a/LOG/log.go +++ b/LOG/log.go @@ -3,11 +3,17 @@ package LOG import ( "fmt" "log" + "runtime" ) func DEBUG(text string, msg ...interface{}) { - msgText := fmt.Sprintf(text, msg...) - log.Println("[DEBUG] ", msgText) + pc, file, line, ok := runtime.Caller(2) + if ok { + funcName := runtime.FuncForPC(pc).Name() + log.Printf("[DEBUG] [%s:%d %s()] %s\n", file, line, funcName, fmt.Sprintf(text, msg...)) + } else { + log.Printf("[DEBUG] %s\n", fmt.Sprintf(text, msg...)) + } } func INFO(text string, msg ...interface{}) { diff --git a/core/api.go b/core/api.go index 7857e1b..c6d38df 100644 --- a/core/api.go +++ b/core/api.go @@ -4,7 +4,6 @@ import ( "ProjectWIND/LOG" "ProjectWIND/wba" "crypto/rand" - "encoding/json" "fmt" ) @@ -48,13 +47,8 @@ func (a *apiInfo) SendMsg(msg wba.MessageEventInfo, message string, autoEscape b } messageData.Params.Message = message messageData.Params.AutoEscape = autoEscape - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("发送消息时,构建JSON数据失败: %v", err) - return - } // 发送消息 - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("发送消息时,发送失败: %v", err) return @@ -71,13 +65,8 @@ func (a *apiInfo) SendPrivateMsg(msg wba.MessageEventInfo, message string, autoE messageData.Params.UserId = msg.UserId messageData.Params.Message = message messageData.Params.AutoEscape = autoEscape - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("发送消息(SendPrivateMsg)时,构建JSON数据失败: %v", err) - return - } // 发送消息 - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("发送消息(SendPrivateMsg)时,发送失败: %v", err) return @@ -94,13 +83,8 @@ func (a *apiInfo) SendGroupMsg(msg wba.MessageEventInfo, message string, autoEsc messageData.Params.GroupId = msg.GroupId messageData.Params.Message = message messageData.Params.AutoEscape = autoEscape - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("发送消息(SendGroupMsg)时,构建JSON数据失败: %v", err) - return - } // 发送消息 - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("发送消息(SendGroupMsg)时,发送失败: %v", err) return @@ -115,12 +99,7 @@ func (a *apiInfo) DeleteMsg(msg wba.MessageEventInfo) { var messageData wba.APIRequestInfo messageData.Action = "delete_msg" messageData.Params.MessageId = msg.MessageId - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("撤回消息(DeleteMsg)时,构建JSON数据失败: %v", err) - return - } - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("撤回消息(DeleteMsg)时,发送失败: %v", err) return @@ -136,12 +115,7 @@ func (a *apiInfo) SendLike(userId int64, times int) { messageData.Action = "send_like" messageData.Params.UserId = userId messageData.Params.Times = times - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("发送赞(SendLike)时,构建JSON数据失败: %v", err) - return - } - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("发送赞(SendLike)时,发送失败: %v", err) return @@ -157,12 +131,7 @@ func (a *apiInfo) SetGroupKick(groupId int64, userId int64, rejectAddRequest boo messageData.Params.GroupId = groupId messageData.Params.UserId = userId messageData.Params.RejectAddRequest = rejectAddRequest - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("移出群聊(SetGroupKick)时,构建JSON数据失败: %v", err) - return - } - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("移出群聊(SetGroupKick)时,发送失败: %v", err) return @@ -178,12 +147,7 @@ func (a *apiInfo) SetGroupBan(groupId int64, userId int64, duration int32) { messageData.Params.GroupId = groupId messageData.Params.UserId = userId messageData.Params.Duration = duration - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("禁言群成员(SetGroupBan)时,构建JSON数据失败: %v", err) - return - } - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("禁言群成员(SetGroupBan)时,执行失败: %v", err) return @@ -198,12 +162,7 @@ func (a *apiInfo) SetGroupWholeBan(groupId int64, enable bool) { messageData.Action = "set_group_whole_ban" messageData.Params.GroupId = groupId messageData.Params.Enable = enable - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("设置全员禁言(SetGroupWholeBan)时,构建JSON数据失败: %v", err) - return - } - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("设置全员禁言(SetGroupWholeBan)时,执行失败: %v", err) return @@ -219,12 +178,7 @@ func (a *apiInfo) SetGroupAdmin(groupId int64, userId int64, enable bool) { messageData.Params.GroupId = groupId messageData.Params.UserId = userId messageData.Params.Enable = enable - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("设置群管理员(SetGroupAdmin)时,构建JSON数据失败: %v", err) - return - } - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("设置群管理员(SetGroupAdmin)时,执行失败: %v", err) return @@ -240,12 +194,7 @@ func (a *apiInfo) SetGroupCard(groupId int64, userId int64, card string) { messageData.Params.GroupId = groupId messageData.Params.UserId = userId messageData.Params.Card = card - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("设置群名片(SetGroupCard)时,构建JSON数据失败: %v", err) - return - } - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("设置群名片(SetGroupCard)时,执行失败: %v", err) return @@ -255,17 +204,12 @@ func (a *apiInfo) SetGroupCard(groupId int64, userId int64, card string) { } // SetGroupName 设置群名称(可能需要群主或管理员权限) -func (a *apiInfo) SetGroupName(groupId int64, groupName string) { +func (a apiInfo) SetGroupName(groupId int64, groupName string) { var messageData wba.APIRequestInfo messageData.Action = "set_group_name" messageData.Params.GroupId = groupId messageData.Params.GroupName = groupName - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("设置群名称(SetGroupName)时,构建JSON数据失败: %v", err) - return - } - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("设置群名称(SetGroupName)时,执行失败: %v", err) return @@ -275,17 +219,12 @@ func (a *apiInfo) SetGroupName(groupId int64, groupName string) { } // SetGroupLeave 退出群聊 -func (a *apiInfo) SetGroupLeave(groupId int64, isDismiss bool) { +func (a apiInfo) SetGroupLeave(groupId int64, isDismiss bool) { var messageData wba.APIRequestInfo messageData.Action = "set_group_leave" messageData.Params.GroupId = groupId messageData.Params.IsDismiss = isDismiss - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("退出群聊(SetGroupLeave)时,构建JSON数据失败: %v", err) - return - } - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("退出群聊(SetGroupLeave)时,执行失败: %v", err) return @@ -295,19 +234,14 @@ func (a *apiInfo) SetGroupLeave(groupId int64, isDismiss bool) { } // SetGroupSpecialTitle 设置群专属头衔(需要群主权限) -func (a *apiInfo) SetGroupSpecialTitle(groupId int64, userId int64, specialTitle string, duration int32) { +func (a apiInfo) SetGroupSpecialTitle(groupId int64, userId int64, specialTitle string, duration int32) { var messageData wba.APIRequestInfo messageData.Action = "set_group_special_title" messageData.Params.GroupId = groupId messageData.Params.UserId = userId messageData.Params.SpecialTitle = specialTitle messageData.Params.Duration = duration - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("设置群特殊头衔(SetGroupSpecialTitle)时,构建JSON数据失败: %v", err) - return - } - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("设置群特殊头衔(SetGroupSpecialTitle)时,执行失败: %v", err) return @@ -317,18 +251,13 @@ func (a *apiInfo) SetGroupSpecialTitle(groupId int64, userId int64, specialTitle } // SetFriendAddRequest 处理加好友请求 -func (a *apiInfo) SetFriendAddRequest(flag string, approve bool, remark string) { +func (a apiInfo) SetFriendAddRequest(flag string, approve bool, remark string) { var messageData wba.APIRequestInfo messageData.Action = "set_friend_add_request" messageData.Params.Flag = flag messageData.Params.Approve = approve messageData.Params.Remark = remark - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("处理加好友请求(SetFriendAddRequest)时,构建JSON数据失败: %v", err) - return - } - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("处理加好友请求(SetFriendAddRequest)时,执行失败: %v", err) return @@ -338,19 +267,14 @@ func (a *apiInfo) SetFriendAddRequest(flag string, approve bool, remark string) } // SetGroupAddRequest 处理加群请求/邀请 -func (a *apiInfo) SetGroupAddRequest(flag string, subType string, approve bool, reason string) { +func (a apiInfo) SetGroupAddRequest(flag string, subType string, approve bool, reason string) { var messageData wba.APIRequestInfo messageData.Action = "set_group_add_request" messageData.Params.Flag = flag messageData.Params.SubType = subType messageData.Params.Approve = approve messageData.Params.Reason = reason - messageJson, err := json.Marshal(messageData) - if err != nil { - LOG.ERROR("处理加群请求/邀请(SetGroupAddRequest)时,构建JSON数据失败: %v", err) - return - } - err = wsAPI(messageJson) + _, err := wsAPI(messageData) if err != nil { LOG.ERROR("处理加群请求/邀请(SetGroupAddRequest)时,执行失败: %v", err) return @@ -361,8 +285,22 @@ func (a *apiInfo) SetGroupAddRequest(flag string, subType string, approve bool, // 2.有响应API,需添加echo字段 -func (a *apiInfo) GetLoginInfo(flag string, approve bool) { - +func (a apiInfo) GetLoginInfo() (Response wba.APIResponseInfo) { + LOG.INFO("获取登录信息(GetLoginInfo)") + var messageData wba.APIRequestInfo + var err error + messageData.Action = "get_login_info" + messageData.Echo, err = GenerateUUID() + if err != nil { + LOG.ERROR("获取登录信息(GetLoginInfo)时,生成UUID失败: %v", err) + return wba.APIResponseInfo{} + } + Response, err = wsAPI(messageData) + if err != nil { + LOG.ERROR("获取登录信息(GetLoginInfo)时,执行失败: %v", err) + return wba.APIResponseInfo{} + } + return Response } var AppApi apiInfo diff --git a/core/app_admin.go b/core/app_admin.go index ecd0073..86cf8e1 100644 --- a/core/app_admin.go +++ b/core/app_admin.go @@ -60,7 +60,7 @@ func reloadAPP(file os.DirEntry, appsDir string) (totalDelta int, successDelta i LOG.ERROR("Error initializing app %s: %v", pluginPath, err) } - //CmdMap = mergeMaps(CmdMap, app.Get()) + CmdMap = mergeMaps(CmdMap, app.Get().CmdMap) LOG.INFO("App %s initialized successfully", pluginPath) return 1, 1 diff --git a/core/web_socket.go b/core/web_socket.go index 846e99d..844487c 100644 --- a/core/web_socket.go +++ b/core/web_socket.go @@ -2,22 +2,22 @@ package core import ( "ProjectWIND/LOG" - "bytes" + "ProjectWIND/wba" "encoding/json" "fmt" - "io" + "github.com/gorilla/websocket" "net/http" "net/url" - - "github.com/gorilla/websocket" ) var gProtocolAddr string +var gToken string // WebSocketHandler 接收WebSocket连接处的消息并处理 func WebSocketHandler(protocolAddr string, token string) error { // 保存全局变量 gProtocolAddr = protocolAddr + gToken = token // 解析连接URL u, err := url.Parse(protocolAddr) if err != nil { @@ -25,7 +25,7 @@ func WebSocketHandler(protocolAddr string, token string) error { return err } - // 创建一个带有自定义头的HTTP请求 + // 创建一个带有Authorization头的HTTP请求 req, err := http.NewRequest("GET", u.String(), nil) if err != nil { LOG.FATAL("创建请求出错:%v", err) @@ -44,13 +44,13 @@ func WebSocketHandler(protocolAddr string, token string) error { LOG.ERROR("Close error: %v", err) } }(conn) - LOG.INFO("WebSocket connection to %v established.", u.String()) + logInfo := AppApi.GetLoginInfo() + LOG.INFO("连接到账号: %v(%v)", logInfo.Data.Nickname, logInfo.Data.UserId) // 定义通道,缓存消息和消息类型,防止消息处理阻塞 messageChan := make(chan []byte, 32) messageTypeChan := make(chan int, 32) - for { // 接收消息并放入通道 messageType, message, err := conn.ReadMessage() @@ -113,46 +113,34 @@ func processMessage(messageType int, message []byte) { HandleMetaEvent(message) return } - default: - { - messageMap := make(map[string]interface{}) - err := json.Unmarshal(message, &messageMap) - if err != nil { - LOG.ERROR("Unmarshal error when handling api response message: %v", err) - return - } - if messageMap["status"] != "ok" { - LOG.ERROR("API response error: %v", messageMap["status"]) - return - } - if messageMap["echo"] == "" { - LOG.WARN("Unknown API response: %v", messageMap["echo"]) - return - } - apiResp := make(map[string]interface{}) - apiResp["uuid"] = messageMap["echo"] - ApiChan := make(chan map[string]interface{}) - go func(apiResp map[string]interface{}) { - ApiChan <- apiResp - }(apiResp) - // 此处为api请求响应数据,通过channel返回给调用者 - return - } } } // wsSendMessage 向WebSocket服务器发送消息并返回发送状态 -func wsAPI(body []byte) error { - // 解析连接URL - u, err := url.Parse(fmt.Sprintf("%v/api", gProtocolAddr)) +func wsAPI(body wba.APIRequestInfo) (Response wba.APIResponseInfo, err error) { + // 序列化请求体 + bodyBytes, err := json.Marshal(body) if err != nil { - return fmt.Errorf("无效的URL: %v", err) + return wba.APIResponseInfo{}, err } - - // 建立连接 - conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil) + // 解析连接URL + u, err := url.Parse(gProtocolAddr) if err != nil { - return fmt.Errorf("连接失败: %v", err) + LOG.ERROR("Parse URL error: %v", err) + return wba.APIResponseInfo{}, err + } + // 创建一个带有Authorization头的HTTP请求 + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + LOG.FATAL("创建请求出错:%v", err) + } + req.Header.Set("Authorization", "Bearer "+gToken) + // 配置WebSocket连接升级器 + dialer := websocket.DefaultDialer + // 使用升级器建立WebSocket连接 + conn, _, err := dialer.Dial(req.URL.String(), req.Header) + if err != nil { + LOG.FATAL("建立WebSocket连接出错:%v", err) } defer func(conn *websocket.Conn) { err := conn.Close() @@ -160,36 +148,44 @@ func wsAPI(body []byte) error { LOG.ERROR("Close error: %v", err) } }(conn) - - // 发送请求 - err = conn.WriteMessage(websocket.TextMessage, body) + err = conn.WriteMessage(websocket.TextMessage, bodyBytes) if err != nil { - return fmt.Errorf("请求发送失败: %v", err) + return wba.APIResponseInfo{}, fmt.Errorf("请求发送失败: %v", err) } - - return nil -} - -func httpAPI(method, action string, body []byte) (int, []byte, error) { - urlStr := fmt.Sprintf("%v/api/%v", gProtocolAddr, action) - resp, err := http.Post(urlStr, "application/json", bytes.NewReader(body)) - if err != nil { - return 0, nil, fmt.Errorf("请求失败: %v", err) - } - defer func(resp *http.Response) { - err := resp.Body.Close() - if err != nil { - LOG.ERROR("Close error: %v", err) + if body.Action == "get_group_list" || body.Action == "get_member_list" { + // 处理get_group_list和get_member_list请求,直接返回 + for { + _, message, err := conn.ReadMessage() + if err != nil { + return wba.APIResponseInfo{}, fmt.Errorf("响应接收失败: %v", err) + } + var Response wba.APIResponseInfo + err = json.Unmarshal(message, &Response) + if err != nil { + return wba.APIResponseInfo{}, fmt.Errorf("unmarshal error: %v", err) + } + if Response.Echo == body.Echo { + return Response, nil + } } - }(resp) - - if resp.StatusCode != http.StatusOK { - return 0, nil, fmt.Errorf("请求失败: %v", resp.Status) } - - body, err = io.ReadAll(resp.Body) - if err != nil { - return 0, nil, fmt.Errorf("读取响应失败: %v", err) + //检查是否含有echo字段 + if body.Echo != "" { + // 接收响应消息,直到收到echo字段一致的消息 + for { + _, message, err := conn.ReadMessage() + if err != nil { + return wba.APIResponseInfo{}, fmt.Errorf("响应接收失败: %v", err) + } + var Response wba.APIResponseInfo + err = json.Unmarshal(message, &Response) + if err != nil { + return wba.APIResponseInfo{}, fmt.Errorf("unmarshal error: %v", err) + } + if Response.Echo == body.Echo { + return Response, nil + } + } } - return resp.StatusCode, body, nil + return wba.APIResponseInfo{}, nil } diff --git a/wba/wind.go b/wba/wind.go index 93963dc..9260d42 100644 --- a/wba/wind.go +++ b/wba/wind.go @@ -27,6 +27,7 @@ type WindAPI interface { SetGroupSpecialTitle(groupId int64, userId int64, specialTitle string, duration int32) SetFriendAddRequest(flag string, approve bool, remark string) SetGroupAddRequest(flag string, subType string, approve bool, reason string) + GetLoginInfo() APIResponseInfo } type AppInfo struct { @@ -286,4 +287,99 @@ type APIRequestInfo struct { Echo string `json:"echo,omitempty"` } +type APIResponseInfo struct { + Status string `json:"status,omitempty"` + Retcode int64 `json:"retcode,omitempty"` + Data ResponseDataInfo `json:"data,omitempty"` + Echo string `json:"echo,omitempty"` +} + +type APIResponseListInfo struct { + Status string `json:"status,omitempty"` + Retcode int64 `json:"retcode,omitempty"` + Data []ResponseDataInfo `json:"data,omitempty"` + Echo string `json:"echo,omitempty"` +} + +type ResponseDataInfo struct { + UserId int64 `json:"user_id,omitempty"` + Nickname string `json:"nickname,omitempty"` + Sex string `json:"sex,omitempty"` + Age int32 `json:"age,omitempty"` + Remark string `json:"remark,omitempty"` + GroupId int64 `json:"group_id,omitempty"` + GroupName string `json:"group_name,omitempty"` + MemberCount int32 `json:"member_count,omitempty"` + MaxMemberCount int32 `json:"max_member_count,omitempty"` + Card string `json:"card,omitempty"` + Area string `json:"area,omitempty"` + JoinTime int32 `json:"join_time,omitempty"` + LastSentTime int32 `json:"last_sent_time,omitempty"` + Level string `json:"level,omitempty"` + Role string `json:"role,omitempty"` + Unfriendly bool `json:"unfriendly,omitempty"` + Title string `json:"title,omitempty"` + TitleExpireTime int32 `json:"title_expire_time,omitempty"` + CardChangeable bool `json:"card_changeable,omitempty"` + CurrentTalkative CurrentTalkativeInfo `json:"current_talkative,omitempty"` + TalkativeList []CurrentTalkativeInfo `json:"talkative_list,omitempty"` + PerformerList []HonorInfo `json:"performer_list,omitempty"` + LegendList []HonorInfo `json:"legend_list,omitempty"` + StrongNewbieList []HonorInfo `json:"strong_newbie_list,omitempty"` + EmoticonList []HonorInfo `json:"emoticon_list,omitempty"` + Cookies string `json:"cookies,omitempty"` + Token string `json:"token,omitempty"` + CsrfToken string `json:"csrf_token,omitempty"` + File string `json:"file,omitempty"` + OutFormat string `json:"out_format,omitempty"` + Yes bool `json:"yes,omitempty"` + Online bool `json:"online,omitempty"` + Good bool `json:"good,omitempty"` + AppName string `json:"app_name,omitempty"` + AppVersion string `json:"app_version,omitempty"` + ProtocolVersion string `json:"protocol_version,omitempty"` + Time int64 `json:"time,omitempty"` + MessageType string `json:"message_type,omitempty"` + MessageId int32 `json:"message_id,omitempty"` + RealId int32 `json:"real_id,omitempty"` + Sender SenderInfo `json:"sender,omitempty"` + Message []MessageDataInfo `json:"message,omitempty"` +} + +type CurrentTalkativeInfo struct { + UserId int64 `json:"user_id,omitempty"` + Nickname string `json:"nickname,omitempty"` + Avatar string `json:"avatar,omitempty"` + DayCount int32 `json:"day_count,omitempty"` +} + +type HonorInfo struct { + UserId int64 `json:"user_id,omitempty"` + Nickname string `json:"nickname,omitempty"` + Avatar string `json:"avatar,omitempty"` + Description string `json:"description,omitempty"` +} + +type SegmentInfo struct { + Type string `json:"type,omitempty"` + Data SegmentDataInfo `json:"data,omitempty"` +} + +type SegmentDataInfo struct { + Type string `json:"type,omitempty"` + QQ string `json:"qq,omitempty"` + Id int64 `json:"id,omitempty"` + UserId int64 `json:"user_id,omitempty"` + Nickname string `json:"nickname,omitempty"` + Content string `json:"content,omitempty"` + Url string `json:"url,omitempty"` + Lat string `json:"lat,omitempty"` + Lon string `json:"lon,omitempty"` + Title string `json:"title,omitempty"` + Audio string `json:"audio,omitempty"` + Image string `json:"image,omitempty"` + Video string `json:"video,omitempty"` + Data string `json:"data,omitempty"` +} + var Wind WindAPI