feat: 适配新版sdk

This commit is contained in:
若海
2024-08-26 13:28:25 +08:00
parent 354fd28c00
commit b44a2b070c
21 changed files with 1620 additions and 2523 deletions
-45
View File
@@ -1,45 +0,0 @@
# WeChat Rest Api
基于 [wcferry](https://github.com/opentdp/wechat-rest/tree/master/wcferry) 实现的 HTTP 接口服务,已实现如下功能:
- 检查登录状态
- 获取登录账号 wxid
- 获取登录账号个人信息
- 获取所有消息类型
- 获取完整通讯录
- 获取好友列表
- 获取所有数据库
- 获取数据库中所有表
- 执行 SQL 查询
- 发送文本消息(可 @
- 发送图片
- 发送文件
- 发送卡片消息
- 保存图片
- 保存语音
- 图片 OCR
- 接受好友申请
- 接收转账
- 刷新朋友圈
- 添加群成员
- 删除群成员
- 获取群列表
- 获取群成员列表
- 获取群成员昵称
- 邀请群成员
- 拍一拍群友
- 转发消息给好友
- 转发收到的消息到URL
## 生成 OpenApi 文档
```shell
go get github.com/swaggo/swag/cmd/swag
go install github.com/swaggo/swag/cmd/swag
swag init --parseDependency -g httpd/server.go -o public/swagger -ot json
```
## 生成 OpenApi 客户端
将生成的 `swagger.json` 上传至 `https://editor.swagger.io` 生成对应的客户端
-39
View File
@@ -1,39 +0,0 @@
package midware
import (
"strings"
"github.com/gin-gonic/gin"
"wechat-rest/args"
)
func ApiGuard(c *gin.Context) {
token := ""
// 取回 Token
authcode := c.GetHeader("Authorization")
parts := strings.SplitN(authcode, " ", 2)
if len(parts) == 2 && parts[0] == "Bearer" {
token = parts[1]
}
// 校验 Token
if token != args.Web.Token {
c.Set("Error", gin.H{"Code": 401, "Message": "操作未授权"})
c.Set("ExitCode", 401)
c.Abort()
}
}
func SwaggerGuard(c *gin.Context) {
if !args.Web.Swagger && strings.HasPrefix(c.Request.URL.Path, "/swagger") {
c.Header("Content-Type", "text/html; charset=utf-8")
c.String(200, "功能已禁用")
c.Abort()
}
}
-69
View File
@@ -1,69 +0,0 @@
package midware
import (
"errors"
"github.com/gin-gonic/gin"
)
// 获取错误代码
func exitCode(c *gin.Context, code int) int {
if code := c.GetInt("ExitCode"); code > 100 {
return code
}
return code
}
// 创建错误实例
func newError(data any) error {
if err, ok := data.(error); ok {
return err
}
if err, ok := data.(string); ok {
return errors.New(err)
}
return errors.New("未知错误")
}
// 构造错误信息
func newErrorMessage(data any) gin.H {
if err, ok := data.(error); ok {
return gin.H{"Error": gin.H{"Message": err.Error()}}
}
if err, ok := data.(string); ok {
return gin.H{"Error": gin.H{"Message": err}}
}
return gin.H{"Error": data}
}
// 构造结构数据
func newPayload(data any, msg, token string) gin.H {
payload := gin.H{"Payload": data}
if msg != "" {
payload["Message"] = msg
}
if token != "" {
payload["Token"] = token
}
return payload
}
-41
View File
@@ -1,41 +0,0 @@
package midware
import (
"github.com/gin-gonic/gin"
)
func OutputHandle(c *gin.Context) {
c.Next()
// 输出错误信息
if err, exists := c.Get("Error"); exists {
c.AbortWithStatusJSON(exitCode(c, 400), newErrorMessage(err))
return
}
// 输出请求结果
msg := c.GetString("Message")
if res, exists := c.Get("Payload"); exists || msg != "" {
data := newPayload(res, msg, c.GetString("JwtToken"))
c.AbortWithStatusJSON(exitCode(c, 200), data)
return
}
// 输出HTML内容
if htm := c.GetString("HTML"); htm != "" {
c.Header("Content-Type", "text/html; charset=utf-8")
c.String(200, htm)
c.Abort()
return
}
// 捕获异常返回
c.AbortWithStatusJSON(500, newErrorMessage("内部错误"))
}
+9 -13
View File
@@ -3,33 +3,29 @@ package httpd
import (
"github.com/opentdp/go-helper/httpd"
"wechat-rest/args"
"wechat-rest/httpd/midware"
"wechat-rest/httpd/wcfrest"
"github.com/opentdp/wrest-chat/args"
"github.com/opentdp/wrest-chat/httpd/middle"
"github.com/opentdp/wrest-chat/httpd/wcfrest"
)
// @title WeChat Rest Api
// @title Wrest Chat Api
// @version v0.10.0
// @description 基于 WeChatFerry RPC 实现的微信接口,使用 Go 语言编写,无第三方运行时依赖,易于对接任意编程语言。
// @contact.name WeChatRest
// @contact.url https://github.com/opentdp/wechat-rest
// @contact.url https://github.com/opentdp/wrest-chat
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @BasePath /api
// @BasePath /
func Server() {
httpd.Engine(args.Debug)
// Api 守卫
api := httpd.Group("/api")
api.Use(midware.OutputHandle, midware.ApiGuard)
// Wcf 路由
wcfrest.Route(api)
// Wcfrest 路由
wcfrest.Route()
// Swagger 守卫
httpd.Use(midware.SwaggerGuard)
httpd.Use(middle.SwaggerGuard)
// 前端文件路由
httpd.StaticEmbed("/", "public", args.Efs)
-951
View File
@@ -1,951 +0,0 @@
package wcfrest
import (
"strings"
"github.com/gin-gonic/gin"
"github.com/mitchellh/mapstructure"
"github.com/opentdp/go-helper/logman"
"golang.org/x/net/websocket"
"github.com/opentdp/wechat-rest/wcferry"
)
type Controller struct {
*wcferry.Client
}
// 通用结果
type CommonPayload struct {
// 是否成功
Success bool `json:"success,omitempty"`
// 返回结果
Result string `json:"result,omitempty"`
// 错误信息
Error error `json:"error,omitempty"`
}
// @Summary 检查登录状态
// @Produce json
// @Success 200 {object} bool
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /is_login [post]
func (wc *Controller) isLogin(c *gin.Context) {
c.Set("Payload", wc.CmdClient.IsLogin())
}
// @Summary 获取登录账号wxid
// @Produce json
// @Success 200 {object} string
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /self_wxid [post]
func (wc *Controller) getSelfWxid(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetSelfWxid())
}
// @Summary 获取登录账号个人信息
// @Produce json
// @Success 200 {object} UserInfoPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /self_info [post]
func (wc *Controller) getSelfInfo(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetSelfInfo())
}
type UserInfoPayload struct {
// 用户 id
Wxid string `json:"wxid,omitempty"`
// 昵称
Name string `json:"name,omitempty"`
// 手机号
Mobile string `json:"mobile,omitempty"`
// 文件/图片等父路径
Home string `json:"home,omitempty"`
}
// @Summary 获取所有消息类型
// @Produce json
// @Success 200 {object} map[int32]string
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /msg_types [post]
func (wc *Controller) getMsgTypes(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetMsgTypes())
}
// @Summary 获取数据库列表
// @Produce json
// @Success 200 {object} []string
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /db_names [post]
func (wc *Controller) getDbNames(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetDbNames())
}
// @Summary 获取数据库表列表
// @Produce json
// @Param body body GetDbTablesRequest true "获取数据库表列表参数"
// @Success 200 {object} []DbTablePayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /db_tables [post]
func (wc *Controller) getDbTables(c *gin.Context) {
var req GetDbTablesRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
c.Set("Payload", wc.CmdClient.GetDbTables(req.Db))
}
type DbTablePayload struct {
// 表名
Name string `json:"name,omitempty"`
// 建表 SQL
Sql string `json:"sql,omitempty"`
}
type GetDbTablesRequest struct {
// 数据库名称
Db string `json:"db"`
}
// @Summary 执行数据库查询
// @Produce json
// @Param body body DbSqlQueryRequest true "数据库查询参数"
// @Success 200 {object} []map[string]any
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /db_query_sql [post]
func (wc *Controller) dbSqlQuery(c *gin.Context) {
var req DbSqlQueryRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
c.Set("Payload", wc.CmdClient.DbSqlQuery(req.Db, req.Sql))
}
type DbSqlQueryRequest struct {
// 数据库名称
Db string `json:"db"`
// 待执行的 SQL
Sql string `json:"sql"`
}
// @Summary 获取群列表
// @Produce json
// @Success 200 {object} []ContactPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /chatrooms [post]
func (wc *Controller) getChatRooms(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetChatRooms())
}
// @Summary 获取群成员列表
// @Produce json
// @Param body body GetChatRoomMembersRequest true "获取群成员列表参数"
// @Success 200 {object} []ContactPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /chatroom_members [post]
func (wc *Controller) getChatRoomMembers(c *gin.Context) {
var req GetChatRoomMembersRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
c.Set("Payload", wc.CmdClient.GetChatRoomMembers(req.Roomid))
}
type GetChatRoomMembersRequest struct {
// 群聊 id
Roomid string `json:"roomid"`
}
// @Summary 获取群成员昵称
// @Produce json
// @Param body body GetAliasInChatRoomRequest true "获取群成员昵称参数"
// @Success 200 {object} string
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /alias_in_chatroom [post]
func (wc *Controller) getAliasInChatRoom(c *gin.Context) {
var req GetAliasInChatRoomRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
c.Set("Payload", wc.CmdClient.GetAliasInChatRoom(req.Wxid, req.Roomid))
}
type GetAliasInChatRoomRequest struct {
// 群聊 id
Roomid string `json:"roomid"`
// 用户 id
Wxid string `json:"wxid"`
}
// @Summary 邀请群成员
// @Produce json
// @Param body body ChatroomMembersRequest true "管理群成员参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /invite_chatroom_members [post]
func (wc *Controller) inviteChatroomMembers(c *gin.Context) {
var req ChatroomMembersRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.InviteChatroomMembers(req.Roomid, strings.Join(req.Wxids, ","))
c.Set("Payload", CommonPayload{
Success: status == 1,
})
}
type ChatroomMembersRequest struct {
// 群聊 id
Roomid string `json:"roomid"`
// 用户 id 列表
Wxids []string `json:"wxids"`
}
// @Summary 添加群成员
// @Produce json
// @Param body body ChatroomMembersRequest true "管理群成员参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /add_chatroom_members [post]
func (wc *Controller) addChatRoomMembers(c *gin.Context) {
var req ChatroomMembersRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.AddChatRoomMembers(req.Roomid, strings.Join(req.Wxids, ","))
c.Set("Payload", CommonPayload{
Success: status == 1,
})
}
// @Summary 删除群成员
// @Produce json
// @Param body body ChatroomMembersRequest true "管理群成员参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /del_chatroom_members [post]
func (wc *Controller) delChatRoomMembers(c *gin.Context) {
var req ChatroomMembersRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.DelChatRoomMembers(req.Roomid, strings.Join(req.Wxids, ","))
c.Set("Payload", CommonPayload{
Success: status == 1,
})
}
// @Summary 撤回消息
// @Produce json
// @Param body body RevokeMsgRequest true "撤回消息参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /revoke_msg [post]
func (wc *Controller) revokeMsg(c *gin.Context) {
var req RevokeMsgRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.RevokeMsg(req.Msgid)
c.Set("Payload", CommonPayload{
Success: status == 1,
})
}
type RevokeMsgRequest struct {
// 消息 id
Msgid uint64 `json:"msgid"`
}
// @Summary 转发消息
// @Produce json
// @Param body body ForwardMsgRequest true "转发消息参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /forward_msg [post]
func (wc *Controller) forwardMsg(c *gin.Context) {
var req ForwardMsgRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.ForwardMsg(req.Id, strings.Join(req.Receiver, ","))
c.Set("Payload", CommonPayload{
Success: status == 1,
})
}
type ForwardMsgRequest struct {
// 待转发消息 id
Id uint64 `json:"id"`
// 转发接收人或群的 id 列表
Receiver []string `json:"receiver"`
}
// @Summary 发送文本消息
// @Produce json
// @Param body body SendTxtRequest true "发送文本消息参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /send_txt [post]
func (wc *Controller) sendTxt(c *gin.Context) {
var req SendTxtRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.SendTxt(req.Msg, req.Receiver, strings.Join(req.Aters, ","))
c.Set("Payload", CommonPayload{
Success: status == 0,
})
}
type SendTxtRequest struct {
// 消息内容
Msg string `json:"msg"`
// 接收人或群的 id
Receiver string `json:"receiver"`
// 需要 At 的用户 id 列表
Aters []string `json:"aters"`
}
// @Summary 发送图片消息
// @Produce json
// @Param body body SendImgRequest true "发送图片消息参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /send_img [post]
func (wc *Controller) sendImg(c *gin.Context) {
var req SendImgRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.SendImg(req.Path, req.Receiver)
c.Set("Payload", CommonPayload{
Success: status == 0,
})
}
type SendImgRequest struct {
// 图片路径
Path string `json:"path"`
// 接收人或群的 id
Receiver string `json:"receiver"`
}
// @Summary 发送文件消息
// @Produce json
// @Param body body SendFileRequest true "发送文件消息参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /send_file [post]
func (wc *Controller) sendFile(c *gin.Context) {
var req SendFileRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.SendFile(req.Path, req.Receiver)
c.Set("Payload", CommonPayload{
Success: status == 0,
})
}
type SendFileRequest struct {
// 文件路径
Path string `json:"path"`
// 接收人或群的 id
Receiver string `json:"receiver"`
}
// @Summary 发送卡片消息
// @Produce json
// @Param body body SendRichTextRequest true "发送卡片消息参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /send_rich_text [post]
func (wc *Controller) sendRichText(c *gin.Context) {
var req SendRichTextRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.SendRichText(req.Name, req.Account, req.Title, req.Digest, req.Url, req.Thumburl, req.Receiver)
c.Set("Payload", CommonPayload{
Success: status == 0,
})
}
type SendRichTextRequest struct {
// 左下显示的名字
Name string `json:"name"`
// 填公众号 id 可以显示对应的头像(gh_ 开头的)
Account string `json:"account"`
// 标题,最多两行
Title string `json:"title"`
// 摘要,三行
Digest string `json:"digest"`
// 点击后跳转的链接
Url string `json:"url"`
// 缩略图的链接
Thumburl string `json:"thumburl"`
// 接收人或群的 id
Receiver string `json:"receiver"`
}
// @Summary 拍一拍群友
// @Produce json
// @Param body body SendPatMsgRequest true "拍一拍群友参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /send_pat_msg [post]
func (wc *Controller) sendPatMsg(c *gin.Context) {
var req SendPatMsgRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.SendPatMsg(req.Roomid, req.Wxid)
c.Set("Payload", CommonPayload{
Success: status == 1,
})
}
type SendPatMsgRequest struct {
// 群 id
Roomid string `json:"roomid"`
// 用户 id
Wxid string `json:"wxid"`
}
// @Summary 获取语音消息
// @Produce json
// @Param body body GetAudioMsgRequest true "获取语音消息参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /get_audio_msg [post]
func (wc *Controller) getAudioMsg(c *gin.Context) {
var req GetAudioMsgRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
if req.Timeout > 0 {
resp, err := wc.CmdClient.GetAudioMsgTimeout(req.Msgid, req.Dir, req.Timeout)
c.Set("Payload", CommonPayload{
Success: resp != "",
Result: resp,
Error: err,
})
} else {
resp := wc.CmdClient.GetAudioMsg(req.Msgid, req.Dir)
c.Set("Payload", CommonPayload{
Success: resp != "",
Result: resp,
})
}
}
type GetAudioMsgRequest struct {
// 消息 id
Msgid uint64 `json:"msgid"`
// 存储路径
Dir string `json:"path"`
// 超时重试次数
Timeout int `json:"timeout"`
}
// @Summary 获取OCR识别结果
// @Produce json
// @Param body body GetOcrRequest true "获取OCR识别结果参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /get_ocr_result [post]
func (wc *Controller) getOcrResult(c *gin.Context) {
var req GetOcrRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
if req.Timeout > 0 {
resp, err := wc.CmdClient.GetOcrResultTimeout(req.Extra, req.Timeout)
c.Set("Payload", CommonPayload{
Success: resp != "",
Result: resp,
Error: err,
})
} else {
resp, stat := wc.CmdClient.GetOcrResult(req.Extra)
c.Set("Payload", CommonPayload{
Success: stat == 0,
Result: resp,
})
}
}
type GetOcrRequest struct {
// 消息中的 extra 字段
Extra string `json:"extra"`
// 超时重试次数
Timeout int `json:"timeout"`
}
// @Summary 下载图片
// @Produce json
// @Param body body DownloadImageRequest true "下载图片参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /download_image [post]
func (wc *Controller) downloadImage(c *gin.Context) {
var req DownloadImageRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
resp, err := wc.CmdClient.DownloadImage(req.Msgid, req.Extra, req.Dir, req.Timeout)
c.Set("Payload", CommonPayload{
Success: resp != "",
Result: resp,
Error: err,
})
}
type DownloadImageRequest struct {
// 消息 id
Msgid uint64 `json:"msgid"`
// 消息中的 extra 字段
Extra string `json:"extra"`
// 存储路径
Dir string `json:"dir"`
// 超时重试次数
Timeout int `json:"timeout"`
}
// @Summary 下载附件
// @Produce json
// @Param body body DownloadAttachRequest true "下载附件参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /download_attach [post]
func (wc *Controller) downloadAttach(c *gin.Context) {
var req DownloadAttachRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.DownloadAttach(req.Msgid, req.Thumb, req.Extra)
c.Set("Payload", CommonPayload{
Success: status == 0,
})
}
type DownloadAttachRequest struct {
// 消息 id
Msgid uint64 `json:"msgid"`
// 消息中的 thumb 字段
Thumb string `json:"thumb"`
// 消息中的 extra 字段
Extra string `json:"extra"`
}
// @Summary 获取头像列表
// @Produce json
// @Param body body GetAvatarsRequest true "获取头像列表参数"
// @Success 200 {object} []AvatarPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /avatars [post]
func (wc *Controller) getAvatars(c *gin.Context) {
var req GetAvatarsRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
sql := "SELECT usrName as UsrName, bigHeadImgUrl as BigHeadImgUrl, smallHeadImgUrl as SmallHeadImgUrl FROM ContactHeadImgUrl"
if len(req.Wxids) > 0 {
for i, v := range req.Wxids {
req.Wxids[i] = strings.ReplaceAll(v, "'", "''")
}
sql += " WHERE usrName IN ('" + strings.Join(req.Wxids, "','") + "')"
}
res := wc.CmdClient.DbSqlQuery("MicroMsg.db", sql)
var result []AvatarPayload
if mapstructure.Decode(res, &result) == nil {
c.Set("Payload", result)
} else {
c.Set("Payload", res)
}
}
type GetAvatarsRequest struct {
// 用户 id 列表
Wxids []string `json:"wxids"`
}
type AvatarPayload struct {
// 用户 id
UsrName string `json:"usr_name,omitempty"`
// 大头像 url
BigHeadImgUrl string `json:"big_head_img_url,omitempty"`
// 小头像 url
SmallHeadImgUrl string `json:"small_head_img_url,omitempty"`
}
// @Summary 获取完整通讯录
// @Produce json
// @Success 200 {object} []ContactPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /contacts [post]
func (wc *Controller) getContacts(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetContacts())
}
type ContactPayload struct {
// 用户 id
Wxid string `json:"wxid,omitempty"`
// 微信号
Code string `json:"code,omitempty"`
// 备注
Remark string `json:"remark,omitempty"`
// 昵称
Name string `json:"name,omitempty"`
// 国家
Country string `json:"country,omitempty"`
// 省/州
Province string `json:"province,omitempty"`
// 城市
City string `json:"city,omitempty"`
// 性别
Gender int32 `json:"gender,omitempty"`
}
// @Summary 获取好友列表
// @Produce json
// @Success 200 {object} []ContactPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /friends [post]
func (wc *Controller) getFriends(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetFriends())
}
// @Summary 根据wxid获取个人信息
// @Produce json
// @Param body body GetInfoByWxidRequest true "根据wxid获取个人信息参数"
// @Success 200 {object} ContactPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /user_info [post]
func (wc *Controller) getInfoByWxid(c *gin.Context) {
var req GetInfoByWxidRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
c.Set("Payload", wc.CmdClient.GetInfoByWxid(req.Wxid))
}
type GetInfoByWxidRequest struct {
// 用户 id
Wxid string `json:"wxid"`
}
// @Summary 刷新朋友圈
// @Produce json
// @Param body body RefreshPyqRequest true "刷新朋友圈参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /refresh_pyq [post]
func (wc *Controller) refreshPyq(c *gin.Context) {
var req RefreshPyqRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.RefreshPyq(req.Id)
c.Set("Payload", CommonPayload{
Success: status == 1,
})
}
type RefreshPyqRequest struct {
// 分页 id
Id uint64 `json:"id"`
}
// @Summary 接受好友请求
// @Produce json
// @Param body body AcceptNewFriendRequest true "接受好友参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /accept_new_friend [post]
func (wc *Controller) acceptNewFriend(c *gin.Context) {
var req AcceptNewFriendRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.AcceptNewFriend(req.V3, req.V4, req.Scene)
c.Set("Payload", CommonPayload{
Success: status == 1,
})
}
type AcceptNewFriendRequest struct {
// 加密的用户名
V3 string `json:"v3"`
// 验证信息 Ticket
V4 string `json:"v4"`
// 添加方式:17 名片,30 扫码
Scene int32 `json:"scene"`
}
// @Summary 接受转账
// @Produce json
// @Param body body ReceiveTransferRequest true "接受转账参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /receive_transfer [post]
func (wc *Controller) receiveTransfer(c *gin.Context) {
var req ReceiveTransferRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
status := wc.CmdClient.ReceiveTransfer(req.Wxid, req.Tfid, req.Taid)
c.Set("Payload", CommonPayload{
Success: status == 1,
})
}
type ReceiveTransferRequest struct {
// 转账人
Wxid string `json:"wxid,omitempty"`
// 转账id transferid
Tfid string `json:"tfid,omitempty"`
// Transaction id
Taid string `json:"taid,omitempty"`
}
// @Summary 开启推送消息到URL
// @Produce json
// @Param body body ReceiverRequest true "推送消息到URL参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /enable_receiver [post]
func (wc *Controller) enabledReceiver(c *gin.Context) {
var req ReceiverRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
if !strings.HasPrefix(req.Url, "http") {
c.Set("Error", "url must start with http(s)://")
return
}
err := wc.enableUrlReceiver(req.Url)
c.Set("Payload", CommonPayload{
Success: err == nil,
Error: err,
})
}
type ReceiverRequest struct {
// 接收推送消息的 url
Url string `json:"url"`
}
// @Summary 关闭推送消息到URL
// @Produce json
// @Param body body ReceiverRequest true "推送消息到URL参数"
// @Success 200 {object} CommonPayload
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /disable_receiver [post]
func (wc *Controller) disableReceiver(c *gin.Context) {
var req ReceiverRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.Set("Error", err)
return
}
err := wc.disableUrlReceiver(req.Url)
c.Set("Payload", CommonPayload{
Success: err == nil,
Error: err,
})
}
// @Summary 推送消息到Socket
// @Produce json
// @Tags websocket
// @Success 101 {string} string "Switching Protocols 响应"
// @Failure 400 {string} string "非法请求"
// @Failure 500 {string} string "内部服务器错误"
// @Router /socket_receiver [get]
func (wc *Controller) socketReceiver(c *gin.Context) {
h := websocket.Handler(func(ws *websocket.Conn) {
wc.enableSocketReceiver(ws)
for {
var rq string
if err := websocket.Message.Receive(ws, &rq); err != nil {
logman.Error("read:error", "error", err)
break
}
}
wc.disableSocketReceiver(ws)
})
h.ServeHTTP(c.Writer, c.Request)
c.Set("Payload", "连接已关闭")
}
-107
View File
@@ -1,107 +0,0 @@
package wcfrest
import (
"errors"
"github.com/opentdp/go-helper/logman"
"github.com/opentdp/go-helper/request"
"golang.org/x/net/websocket"
"github.com/opentdp/wechat-rest/wcferry"
)
var urlReceiverKey = ""
var urlReceiverList = map[string]bool{}
var socketReceiverKey = ""
var socketReceiverList = map[*websocket.Conn]bool{}
func (wc *Controller) enableUrlReceiver(url string) error {
logman.Info("enable receiver", "url", url)
if urlReceiverKey == "" {
key, err := wc.EnrollReceiver(true, func(msg *wcferry.WxMsg) {
ret := wcferry.ParseWxMsg(msg)
for u := range urlReceiverList {
logman.Info("call receiver", "url", u, "Id", ret.Id)
go request.JsonPost(u, ret, request.H{})
}
})
if err != nil {
return err
}
urlReceiverKey = key
}
if _, ok := urlReceiverList[url]; ok {
return errors.New("url already exists")
}
urlReceiverList[url] = true
return nil
}
func (wc *Controller) disableUrlReceiver(url string) error {
logman.Info("disable receiver", "url", url)
if _, ok := urlReceiverList[url]; !ok {
return errors.New("url not exists")
}
delete(urlReceiverList, url)
if len(urlReceiverList) == 0 {
return wc.DisableReceiver(urlReceiverKey)
}
return nil
}
func (wc *Controller) enableSocketReceiver(ws *websocket.Conn) error {
logman.Info("enable receiver", "socket", ws.RemoteAddr().String())
if len(socketReceiverList) == 0 {
key, err := wc.EnrollReceiver(true, func(msg *wcferry.WxMsg) {
ret := wcferry.ParseWxMsg(msg)
for w := range socketReceiverList {
logman.Info("call receiver", "socket", ws.RemoteAddr().String(), "Id", ret.Id)
go websocket.JSON.Send(w, ret)
}
})
if err != nil {
return err
}
socketReceiverKey = key
}
if _, ok := socketReceiverList[ws]; ok {
return errors.New("socket already exists")
}
socketReceiverList[ws] = true
return nil
}
func (wc *Controller) disableSocketReceiver(ws *websocket.Conn) error {
logman.Info("disable receiver", "socket", ws.RemoteAddr().String())
if _, ok := socketReceiverList[ws]; !ok {
return errors.New("socket not exists")
}
delete(socketReceiverList, ws)
if len(socketReceiverList) == 0 {
return wc.DisableReceiver(socketReceiverKey)
}
return nil
}
-54
View File
@@ -1,54 +0,0 @@
package wcfrest
import (
"github.com/gin-gonic/gin"
"github.com/opentdp/wechat-rest/wclient"
)
func Route(rg *gin.RouterGroup) {
ctrl := &Controller{wclient.Register()}
rg.POST("is_login", ctrl.isLogin)
rg.POST("self_wxid", ctrl.getSelfWxid)
rg.POST("self_info", ctrl.getSelfInfo)
rg.POST("msg_types", ctrl.getMsgTypes)
rg.POST("db_names", ctrl.getDbNames)
rg.POST("db_tables", ctrl.getDbTables)
rg.POST("db_query_sql", ctrl.dbSqlQuery)
rg.POST("chatrooms", ctrl.getChatRooms)
rg.POST("chatroom_members", ctrl.getChatRoomMembers)
rg.POST("alias_in_chatroom", ctrl.getAliasInChatRoom)
rg.POST("invite_chatroom_members", ctrl.inviteChatroomMembers)
rg.POST("add_chatroom_members", ctrl.addChatRoomMembers)
rg.POST("del_chatroom_members", ctrl.delChatRoomMembers)
rg.POST("revoke_msg", ctrl.revokeMsg)
rg.POST("forward_msg", ctrl.forwardMsg)
rg.POST("send_txt", ctrl.sendTxt)
rg.POST("send_img", ctrl.sendImg)
rg.POST("send_file", ctrl.sendFile)
rg.POST("send_rich_text", ctrl.sendRichText)
rg.POST("send_pat_msg", ctrl.sendPatMsg)
rg.POST("audio_msg", ctrl.getAudioMsg)
rg.POST("ocr_result", ctrl.getOcrResult)
rg.POST("download_image", ctrl.downloadImage)
rg.POST("download_attach", ctrl.downloadAttach)
rg.POST("avatars", ctrl.getAvatars)
rg.POST("contacts", ctrl.getContacts)
rg.POST("friends", ctrl.getFriends)
rg.POST("user_info", ctrl.getInfoByWxid)
rg.POST("refresh_pyq", ctrl.refreshPyq)
rg.POST("accept_new_friend", ctrl.acceptNewFriend)
rg.POST("receive_transfer", ctrl.receiveTransfer)
rg.POST("enable_receiver", ctrl.enabledReceiver)
rg.POST("disable_receiver", ctrl.disableReceiver)
rg.GET("socket_receiver", ctrl.socketReceiver)
}