Merge pull request #107 from opentdp/master

Fix http auth and sdk errors
This commit is contained in:
Changhua 2024-01-10 10:04:34 +08:00 committed by GitHub
commit 4a7e27cc40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 195 additions and 252 deletions

View File

@ -1,69 +1,40 @@
# 微信 REST API
基于 [WeChatFerry RPC](https://github.com/lich0821/WeChatFerry/tree/master/WeChatFerry) 实现的电脑版微信 REST API使用 Go 语言编写,无第三方运行时依赖。基于 HTTP 提供操作接口,轻松对接任意编程语言。
基于 [WeChatFerry RPC](https://github.com/lich0821/WeChatFerry/tree/master/WeChatFerry) 实现,主要特性如下:
- 使用 Go 语言编写,无运行时依赖
- 基于 HTTP 提供操作接口,无缝对接大多数编程语言
- 支持 HTTP 接口授权,参见 [配置说明](#配置说明)
- 消息中的 Xml 尽可能转为 Object
> 此源码仅提供 HTTP REST API 能力,其他能力可参考 [wechat-rest](https://github.com/opentdp/wechat-rest) 相关说明
## 使用方法
1、下载并安装 [WeChatSetup-3.9.2.23](https://github.com/opentdp/wechat-rest/releases/download/v0.0.1/WeChatSetup-3.9.2.23.exe) 和 [Wechat-rest](https://github.com/opentdp/wechat-rest/releases)
1、下载并安装 [WeChatSetup-3.9.2.23](https://github.com/opentdp/wechat-rest/releases/download/v0.0.1/WeChatSetup-3.9.2.23.exe),其他版本不支持
2、双击 `wrest.exe` 将自动启动微信和接口服务,扫码登录即可
2、下载 [WeChatFerry](https://github.com/lich0821/WeChatFerry/releases)解压后将2个dll文件复制到当前目录其他文件可忽略
3、浏览器打开 `http://localhost:7600` 查看支持的接口
3、双击 `start.bat` 将自动启动微信和接口服务,扫码登录
> 接口使用范例请参考 <https://github.com/opentdp/wechat-robot>
> 初始化时出现 **Attempt to access invalid address** 错误信息可以忽略
4、浏览器打开 `http://localhost:7600` 查看支持的接口
## 配置说明
```yml
httpd:
address: 127.0.0.1:7600 # api 监听地址
token: "" # 使用 token 验证请求
swag: true # 启用 OpenApi 文档
logger:
dir: logs # 日志目录
level: info # 日志级别
target: stdout # 日志输出方式
wcf:
address: 127.0.0.1:10080 # rpc 监听地址
sdklibrary: libs/sdk.dll # sdk 依赖库
wechatauto: true # 自动启动或停止微信
msgprint: true # 打印收到的消息
```
启动 `wrest` 时将自动创建一个默认配置文件,完整配置说明可参考开源仓库中的 [config.yml](./config.yml)
> 若设置了 `token`,请求时需携带 **header** 信息: `Authorization: Bearer $token`
- 应使用 `Ctrl + C` 终止 **wrest**,而非直接关闭 **wrest** 窗口
- 若设置了 `token`,请求时需携带 **header** 信息: `Authorization: Bearer $token`
## 功能清单
## 开发说明
- 检查登录状态
- 获取登录账号 wxid
- 获取登录账号个人信息
- 获取所有消息类型
- 获取完整通讯录
- 获取好友列表
- 获取所有数据库
- 获取数据库中所有表
- 执行 SQL 查询
- 发送文本消息(可 @
- 发送图片
- 发送文件
- 发送卡片消息
- 保存图片
- 保存语音
- 图片 OCR
- 接受好友申请
- 接收转账
- 刷新朋友圈
- 添加群成员
- 删除群成员
- 获取群列表
- 获取群成员列表
- 获取群成员昵称
- 邀请群成员
- 拍一拍群友
- 转发消息给好友
- 转发收到的消息到URL
### 编译须知
## 生成 OpenApi 文档
由于微信和WCF均为32位应用所以`go`也必须以`32`位模式编译,务必设置 `GOARCH` 环境变量为 `386`
### 生成 OpenApi 文档
```shell
go get github.com/swaggo/swag/cmd/swag

View File

@ -12,36 +12,36 @@ var Debug bool
var Efs *embed.FS
// Http 服务参数
var Httpd = struct {
Address string `yaml:"address"`
Token string `yaml:"token"`
Swag bool `yaml:"swag"`
}{
Address: "127.0.0.1:7600",
Swag: true,
}
// 日志参数
var Logger = struct {
Dir string
Level string
Target string
Dir string `yaml:"dir"`
Level string `yaml:"level"`
Target string `yaml:"target"`
}{
Dir: "logs",
Level: "info",
Target: "stdout",
}
// Http 服务参数
var Httpd = struct {
Address string
Token string
Swag bool
}{
Address: "127.0.0.1:7600",
Swag: true,
}
// Wcf 服务参数
var Wcf = struct {
Address string
SdkLibrary string
WeChatAuto bool
MsgPrint bool
Address string `yaml:"address"`
SdkLibrary string `yaml:"sdkLibrary"`
WeChatAuto bool `yaml:"wechatAuto"`
MsgPrinter bool `yaml:"msgPrinter"`
}{
Address: "127.0.0.1:10080",
SdkLibrary: "sdk.dll",

View File

@ -28,7 +28,11 @@ func (c *Config) Init() *Config {
Delim: ".",
})
c.Parser = yaml.Parser()
c.File = "config.yml"
if len(os.Args) > 1 {
c.File = os.Args[1]
}
return c

View File

@ -12,8 +12,8 @@ func (c *Config) Unmarshal() {
// 读取默认配置
mp := map[string]any{
"logger": &Logger,
"httpd": &Httpd,
"logger": &Logger,
"wcf": &Wcf,
}
c.Koanf.Load(confmap.Provider(mp, "."), nil)
@ -35,7 +35,7 @@ func (c *Config) Unmarshal() {
Level: Logger.Level,
Target: Logger.Target,
Storage: Logger.Dir,
Filename: "rest",
Filename: "wrest",
})
// 写入配置文件

View File

@ -1,37 +0,0 @@
#!/bin/sh
#
set -e
set -o noglob
###########################################
export CGO_ENABLED=0
export GO111MODULE=on
export GOOS=windows
export GOARCH=386
####################################################################
RUN_NUMBER=${GITHUB_RUN_NUMBER:-0}
last_tag=`git tag | sort -V | tail -n 1`
prev_tag=`git tag | sort -V | tail -n 2 | head -n 1`
git log $prev_tag..$last_tag --pretty=format:"%s" | grep -v "^release" | sed 's/^/- /' | sort > RELEASE.md
####################################################################
echo building for $GOOS/$GOARCH
target=build/wrest.exe
go build -ldflags="-s -w" -o $target main.go
####################################################################
cp README.md build/
cp wcferry/libs/sdk.dll build/
cp wcferry/libs/spy.dll build/
mv build wechat-rest
zip -r wechat-rest.zip wechat-rest/

View File

@ -1,13 +1,18 @@
# REST 接口
httpd:
address: 127.0.0.1:7600
token: ""
swag: true
address: 127.0.0.1:7600 # Api 监听地址
token: "" # 使用 Token 验证请求
swag: true # 是否启用 OpenApi 文档
# 运行日志
logger:
dir: logs
level: info
target: stdout
dir: logs # 日志目录
level: info # 日志级别
target: stdout # 日志输出方式
# WeChat Ferry
wcf:
address: 127.0.0.1:10080
sdklibrary: sdk.dll
wechatauto: true
msgprint: true
address: 127.0.0.1:10080 # Rpc 监听地址
sdkLibrary: wcferry/libs/sdk.dll # Sdk 路径
wechatAuto: true # 是否跟随启停微信
msgPrinter: false # 是否打印收到的消息

View File

@ -4,9 +4,10 @@ go 1.21
require (
github.com/gin-gonic/gin v1.9.1
github.com/opentdp/go-helper v0.5.2
go.nanomsg.org/mangos/v3 v3.4.2
google.golang.org/protobuf v1.31.0
github.com/knadh/koanf v1.5.0
github.com/knadh/koanf/v2 v2.0.1
github.com/opentdp/go-helper v0.5.5-0.20240109013403-7323088c3f39
github.com/opentdp/wechat-rest v0.6.0
)
require (
@ -16,6 +17,7 @@ require (
github.com/cheggaaa/pb/v3 v3.1.4 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/clbanning/mxj v1.8.4 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
@ -28,8 +30,6 @@ require (
github.com/gorilla/websocket v1.5.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/knadh/koanf v1.5.0
github.com/knadh/koanf/v2 v2.0.1
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
@ -39,18 +39,20 @@ require (
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
go.nanomsg.org/mangos v2.0.0+incompatible
golang.org/x/arch v0.6.0 // indirect
golang.org/x/crypto v0.16.0 // indirect
go.nanomsg.org/mangos v2.0.0+incompatible // indirect
go.nanomsg.org/mangos/v3 v3.4.2 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.16.0 // indirect
golang.org/x/tools v0.16.1 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
nanomsg.org/go/mangos/v2 v2.0.8 // indirect

View File

@ -46,6 +46,8 @@ github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpV
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I=
github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@ -246,13 +248,15 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/opentdp/go-helper v0.5.2 h1:eta16BJS7Ew8mo8faITFF9vXzoIZN9snIbss2C2q0fQ=
github.com/opentdp/go-helper v0.5.2/go.mod h1:H3qhSAcclbDAQd3XlR4k109vAdypJL3thcW8XkMLhoQ=
github.com/opentdp/go-helper v0.5.5-0.20240109013403-7323088c3f39 h1:qIzCCWpIPhzZq9ZXevYuqBV3w4F/D8/SK+W6UjKhSf0=
github.com/opentdp/go-helper v0.5.5-0.20240109013403-7323088c3f39/go.mod h1:9m+t/2x1CmjZ9YQP37+xECCO84eqMnsxnRE/7y37GjE=
github.com/opentdp/wechat-rest v0.6.0 h1:e7Co8Bne32gQ8MDGNyBzJ0dhIMhlrIwsDhOxSXI4j1Q=
github.com/opentdp/wechat-rest v0.6.0/go.mod h1:F3rutIf4PahHxPGuAm3wlM6d1S7nznaU/ZNrk0dMEDA=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -323,15 +327,15 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc=
golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@ -360,8 +364,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -410,8 +414,8 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -433,8 +437,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -466,8 +470,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -29,8 +29,8 @@ func ApiGuard(c *gin.Context) {
func SwagGuard(c *gin.Context) {
if !args.Httpd.Swag && strings.HasPrefix(c.Request.URL.Path, "/swag") {
c.Set("Error", gin.H{"Code": 403, "Message": "功能已禁用"})
c.Set("ExitCode", 403)
c.Header("Content-Type", "text/html; charset=utf-8")
c.String(200, "功能已禁用")
c.Abort()
}

View File

@ -20,11 +20,10 @@ import (
func Server() {
httpd.Engine(args.Debug)
httpd.Use(midware.OutputHandle)
// Api 守卫
api := httpd.Group("/api")
api.Use(midware.ApiGuard)
api.Use(midware.OutputHandle, midware.ApiGuard)
// Wcf 路由
wcfrest.Route(api)

View File

@ -1,50 +1,23 @@
package wcfrest
import (
"net"
"strings"
"github.com/gin-gonic/gin"
"github.com/opentdp/go-helper/logman"
"github.com/opentdp/go-helper/strutil"
"github.com/opentdp/wechat-rest/wcferry"
"wechat-rest/args"
"github.com/opentdp/wechat-rest/wcferry"
)
var wc *wcferry.Client
func initService() {
host, port, err := net.SplitHostPort(args.Wcf.Address)
if err != nil {
logman.Fatal("invalid address", "error", err)
}
wc = &wcferry.Client{
ListenAddr: host,
ListenPort: strutil.ToInt(port),
SdkLibrary: args.Wcf.SdkLibrary,
WeChatAuto: args.Wcf.WeChatAuto,
}
logman.Info("wcf starting ...")
if err := wc.Connect(); err != nil {
logman.Fatal("failed to start wcf", "error", err)
}
// 打印收到的消息
if args.Wcf.MsgPrint {
wc.EnrollReceiver(true, wcferry.MsgPrinter)
}
type Controller struct {
*wcferry.Client
}
// @Summary 检查登录状态
// @Produce json
// @Success 200 {object} bool
// @Router /is_login [get]
func isLogin(c *gin.Context) {
func (wc *Controller) isLogin(c *gin.Context) {
c.Set("Payload", wc.CmdClient.IsLogin())
@ -54,7 +27,7 @@ func isLogin(c *gin.Context) {
// @Produce json
// @Success 200 {object} string
// @Router /self_wxid [get]
func getSelfWxid(c *gin.Context) {
func (wc *Controller) getSelfWxid(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetSelfWxid())
@ -64,7 +37,7 @@ func getSelfWxid(c *gin.Context) {
// @Produce json
// @Success 200 {object} wcferry.UserInfo
// @Router /user_info [get]
func getUserInfo(c *gin.Context) {
func (wc *Controller) getUserInfo(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetUserInfo())
@ -74,7 +47,7 @@ func getUserInfo(c *gin.Context) {
// @Produce json
// @Success 200 {object} []wcferry.RpcContact
// @Router /contacts [get]
func getContacts(c *gin.Context) {
func (wc *Controller) getContacts(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetContacts())
@ -84,7 +57,7 @@ func getContacts(c *gin.Context) {
// @Produce json
// @Success 200 {object} []wcferry.RpcContact
// @Router /friends [get]
func getFriends(c *gin.Context) {
func (wc *Controller) getFriends(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetFriends())
@ -95,7 +68,7 @@ func getFriends(c *gin.Context) {
// @Param wxid path string true "wxid"
// @Success 200 {object} wcferry.RpcContact
// @Router /user_info/{wxid} [get]
func getUserInfoByWxid(c *gin.Context) {
func (wc *Controller) getUserInfoByWxid(c *gin.Context) {
wxid := c.Param("wxid")
c.Set("Payload", wc.CmdClient.GetInfoByWxid(wxid))
@ -106,7 +79,7 @@ func getUserInfoByWxid(c *gin.Context) {
// @Produce json
// @Success 200 {object} []string
// @Router /db_names [get]
func getDbNames(c *gin.Context) {
func (wc *Controller) getDbNames(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetDbNames())
@ -117,7 +90,7 @@ func getDbNames(c *gin.Context) {
// @Param db path string true "数据库名"
// @Success 200 {object} []wcferry.DbTable
// @Router /db_tables/{db} [get]
func getDbTables(c *gin.Context) {
func (wc *Controller) getDbTables(c *gin.Context) {
db := c.Param("db")
c.Set("Payload", wc.CmdClient.GetDbTables(db))
@ -129,7 +102,7 @@ func getDbTables(c *gin.Context) {
// @Param body body DbSqlQueryRequest true "数据库查询请求参数"
// @Success 200 {object} map[string]any
// @Router /db_query_sql [post]
func dbSqlQuery(c *gin.Context) {
func (wc *Controller) dbSqlQuery(c *gin.Context) {
var req DbSqlQueryRequest
if err := c.ShouldBindJSON(&req); err != nil {
@ -145,7 +118,7 @@ func dbSqlQuery(c *gin.Context) {
// @Produce json
// @Success 200 {object} map[int32]string
// @Router /msg_types [get]
func getMsgTypes(c *gin.Context) {
func (wc *Controller) getMsgTypes(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetMsgTypes())
@ -156,7 +129,7 @@ func getMsgTypes(c *gin.Context) {
// @Param id path int true "朋友圈id"
// @Success 200 {object} RespPayload
// @Router /refresh_pyq/{id} [get]
func refreshPyq(c *gin.Context) {
func (wc *Controller) refreshPyq(c *gin.Context) {
id := c.Param("id")
pyqid := uint64(strutil.ToUint(id))
@ -173,7 +146,7 @@ func refreshPyq(c *gin.Context) {
// @Produce json
// @Success 200 {object} []wcferry.RpcContact
// @Router /chatrooms [get]
func getChatRooms(c *gin.Context) {
func (wc *Controller) getChatRooms(c *gin.Context) {
c.Set("Payload", wc.CmdClient.GetChatRooms())
@ -184,7 +157,7 @@ func getChatRooms(c *gin.Context) {
// @Param roomid path string true "群id"
// @Success 200 {object} []wcferry.RpcContact
// @Router /chatroom_members/{roomid} [get]
func getChatRoomMembers(c *gin.Context) {
func (wc *Controller) getChatRoomMembers(c *gin.Context) {
roomid := c.Param("roomid")
c.Set("Payload", wc.CmdClient.GetChatRoomMembers(roomid))
@ -197,7 +170,7 @@ func getChatRoomMembers(c *gin.Context) {
// @Param roomid path string true "群id"
// @Success 200 {object} string
// @Router /alias_in_chatroom/{wxid}/{roomid} [get]
func getAliasInChatRoom(c *gin.Context) {
func (wc *Controller) getAliasInChatRoom(c *gin.Context) {
wxid := c.Param("wxid")
roomid := c.Param("roomid")
@ -210,7 +183,7 @@ func getAliasInChatRoom(c *gin.Context) {
// @Param body body wcferry.MemberMgmt true "增删群成员请求参数"
// @Success 200 {object} RespPayload
// @Router /invite_chatroom_members [post]
func inviteChatroomMembers(c *gin.Context) {
func (wc *Controller) inviteChatroomMembers(c *gin.Context) {
var req wcferry.MemberMgmt
if err := c.ShouldBindJSON(&req); err != nil {
@ -231,7 +204,7 @@ func inviteChatroomMembers(c *gin.Context) {
// @Param body body wcferry.MemberMgmt true "增删群成员请求参数"
// @Success 200 {object} RespPayload
// @Router /add_chatroom_members [post]
func addChatRoomMembers(c *gin.Context) {
func (wc *Controller) addChatRoomMembers(c *gin.Context) {
var req wcferry.MemberMgmt
if err := c.ShouldBindJSON(&req); err != nil {
@ -252,7 +225,7 @@ func addChatRoomMembers(c *gin.Context) {
// @Param body body wcferry.MemberMgmt true "增删群成员请求参数"
// @Success 200 {object} RespPayload
// @Router /del_chatroom_members [post]
func delChatRoomMembers(c *gin.Context) {
func (wc *Controller) delChatRoomMembers(c *gin.Context) {
var req wcferry.MemberMgmt
if err := c.ShouldBindJSON(&req); err != nil {
@ -273,7 +246,7 @@ func delChatRoomMembers(c *gin.Context) {
// @Param msgid path int true "消息id"
// @Success 200 {object} RespPayload
// @Router /revoke_msg/{msgid} [get]
func revokeMsg(c *gin.Context) {
func (wc *Controller) revokeMsg(c *gin.Context) {
id := c.Param("msgid")
msgid := uint64(strutil.ToUint(id))
@ -291,7 +264,7 @@ func revokeMsg(c *gin.Context) {
// @Param body body wcferry.ForwardMsg true "转发消息请求参数"
// @Success 200 {object} RespPayload
// @Router /forward_msg [post]
func forwardMsg(c *gin.Context) {
func (wc *Controller) forwardMsg(c *gin.Context) {
var req wcferry.ForwardMsg
if err := c.ShouldBindJSON(&req); err != nil {
@ -312,7 +285,7 @@ func forwardMsg(c *gin.Context) {
// @Param body body wcferry.TextMsg true "文本消息请求参数"
// @Success 200 {object} RespPayload
// @Router /send_txt [post]
func sendTxt(c *gin.Context) {
func (wc *Controller) sendTxt(c *gin.Context) {
var req wcferry.TextMsg
if err := c.ShouldBindJSON(&req); err != nil {
@ -333,7 +306,7 @@ func sendTxt(c *gin.Context) {
// @Param body body wcferry.PathMsg true "图片消息请求参数"
// @Success 200 {object} RespPayload
// @Router /send_img [post]
func sendImg(c *gin.Context) {
func (wc *Controller) sendImg(c *gin.Context) {
var req wcferry.PathMsg
if err := c.ShouldBindJSON(&req); err != nil {
@ -354,7 +327,7 @@ func sendImg(c *gin.Context) {
// @Param body body wcferry.PathMsg true "文件消息请求参数"
// @Success 200 {object} RespPayload
// @Router /send_file [post]
func sendFile(c *gin.Context) {
func (wc *Controller) sendFile(c *gin.Context) {
var req wcferry.PathMsg
if err := c.ShouldBindJSON(&req); err != nil {
@ -375,7 +348,7 @@ func sendFile(c *gin.Context) {
// @Param body body wcferry.RichText true "卡片消息请求参数"
// @Success 200 {object} RespPayload
// @Router /send_rich_text [post]
func sendRichText(c *gin.Context) {
func (wc *Controller) sendRichText(c *gin.Context) {
var req wcferry.RichText
if err := c.ShouldBindJSON(&req); err != nil {
@ -396,7 +369,7 @@ func sendRichText(c *gin.Context) {
// @Param body body wcferry.PatMsg true "拍一拍请求参数"
// @Success 200 {object} RespPayload
// @Router /send_pat_msg [post]
func sendPatMsg(c *gin.Context) {
func (wc *Controller) sendPatMsg(c *gin.Context) {
var req wcferry.PatMsg
if err := c.ShouldBindJSON(&req); err != nil {
@ -417,7 +390,7 @@ func sendPatMsg(c *gin.Context) {
// @Param body body GetAudioMsgRequest true "语音消息请求参数"
// @Success 200 {object} RespPayload
// @Router /get_audio_msg [post]
func getAudioMsg(c *gin.Context) {
func (wc *Controller) getAudioMsg(c *gin.Context) {
var req GetAudioMsgRequest
if err := c.ShouldBindJSON(&req); err != nil {
@ -447,7 +420,7 @@ func getAudioMsg(c *gin.Context) {
// @Param body body GetOcrRequest true "文本请求参数"
// @Success 200 {object} RespPayload
// @Router /get_ocr_result [post]
func getOcrResult(c *gin.Context) {
func (wc *Controller) getOcrResult(c *gin.Context) {
var req GetOcrRequest
if err := c.ShouldBindJSON(&req); err != nil {
@ -477,7 +450,7 @@ func getOcrResult(c *gin.Context) {
// @Param body body DownloadImageRequest true "下载图片参数"
// @Success 200 {object} RespPayload
// @Router /download_image [post]
func downloadImage(c *gin.Context) {
func (wc *Controller) downloadImage(c *gin.Context) {
var req DownloadImageRequest
if err := c.ShouldBindJSON(&req); err != nil {
@ -500,7 +473,7 @@ func downloadImage(c *gin.Context) {
// @Param body body DownloadAttachRequest true "下载附件参数"
// @Success 200 {object} RespPayload
// @Router /download_attach [post]
func downloadAttach(c *gin.Context) {
func (wc *Controller) downloadAttach(c *gin.Context) {
var req DownloadAttachRequest
if err := c.ShouldBindJSON(&req); err != nil {
@ -521,7 +494,7 @@ func downloadAttach(c *gin.Context) {
// @Param body body wcferry.Verification true "接受好友请求参数"
// @Success 200 {object} RespPayload
// @Router /accept_new_friend [post]
func acceptNewFriend(c *gin.Context) {
func (wc *Controller) acceptNewFriend(c *gin.Context) {
var req wcferry.Verification
if err := c.ShouldBindJSON(&req); err != nil {
@ -542,7 +515,7 @@ func acceptNewFriend(c *gin.Context) {
// @Param body body wcferry.Transfer true "接受转账请求参数"
// @Success 200 {object} RespPayload
// @Router /receive_transfer [post]
func receiveTransfer(c *gin.Context) {
func (wc *Controller) receiveTransfer(c *gin.Context) {
var req wcferry.Transfer
if err := c.ShouldBindJSON(&req); err != nil {
@ -563,7 +536,7 @@ func receiveTransfer(c *gin.Context) {
// @Param body body ForwardMsgRequest true "消息转发请求参数"
// @Success 200 {object} RespPayload
// @Router /enable_forward_msg [post]
func enableForwardMsg(c *gin.Context) {
func (wc *Controller) enableForwardMsg(c *gin.Context) {
var req ForwardMsgRequest
if err := c.ShouldBindJSON(&req); err != nil {
@ -576,7 +549,7 @@ func enableForwardMsg(c *gin.Context) {
return
}
err := enableForwardToUrl(req.Url)
err := wc.enableForwardToUrl(req.Url)
c.Set("Payload", RespPayload{
Success: err == nil,
Error: err,
@ -589,7 +562,7 @@ func enableForwardMsg(c *gin.Context) {
// @Param body body ForwardMsgRequest true "消息转发请求参数"
// @Success 200 {object} RespPayload
// @Router /disable_forward_msg [post]
func disableForwardMsg(c *gin.Context) {
func (wc *Controller) disableForwardMsg(c *gin.Context) {
var req ForwardMsgRequest
if err := c.ShouldBindJSON(&req); err != nil {
@ -597,7 +570,7 @@ func disableForwardMsg(c *gin.Context) {
return
}
err := disableForwardToUrl(req.Url)
err := wc.disableForwardToUrl(req.Url)
c.Set("Payload", RespPayload{
Success: err == nil,
Error: err,

View File

@ -12,13 +12,14 @@ import (
var forwardToUrlStat = false
var forwardToUrlList = map[string]bool{}
func enableForwardToUrl(url string) error {
func (wc *Controller) enableForwardToUrl(url string) error {
if !forwardToUrlStat {
err := wc.EnrollReceiver(true, func(msg *wcferry.WxMsg) {
ret := wcferry.WxMsgParser(msg)
for url := range forwardToUrlList {
logman.Info("forward msg", "url", url, "Id", msg.Id)
request.JsonPost(url, msg, request.H{})
logman.Info("forward msg", "url", url, "Id", ret.Id)
go request.JsonPost(url, ret, request.H{})
}
})
if err != nil {
@ -37,7 +38,7 @@ func enableForwardToUrl(url string) error {
}
func disableForwardToUrl(url string) error {
func (wc *Controller) disableForwardToUrl(url string) error {
if _, ok := forwardToUrlList[url]; !ok {
return errors.New("url not exists")

View File

@ -2,49 +2,50 @@ package wcfrest
import (
"github.com/gin-gonic/gin"
"github.com/opentdp/wechat-rest/wclient"
)
func Route(rg *gin.RouterGroup) {
initService()
ctrl := Controller{wclient.Register()}
rg.GET("is_login", isLogin)
rg.GET("self_wxid", getSelfWxid)
rg.GET("user_info", getUserInfo)
rg.GET("contacts", getContacts)
rg.GET("friends", getFriends)
rg.GET("user_info/:wxid", getUserInfoByWxid)
rg.GET("is_login", ctrl.isLogin)
rg.GET("self_wxid", ctrl.getSelfWxid)
rg.GET("user_info", ctrl.getUserInfo)
rg.GET("contacts", ctrl.getContacts)
rg.GET("friends", ctrl.getFriends)
rg.GET("user_info/:wxid", ctrl.getUserInfoByWxid)
rg.GET("db_names", getDbNames)
rg.GET("db_tables/:db", getDbTables)
rg.POST("db_query_sql", dbSqlQuery)
rg.GET("db_names", ctrl.getDbNames)
rg.GET("db_tables/:db", ctrl.getDbTables)
rg.POST("db_query_sql", ctrl.dbSqlQuery)
rg.GET("msg_types", getMsgTypes)
rg.GET("refresh_pyq/:id", refreshPyq)
rg.GET("msg_types", ctrl.getMsgTypes)
rg.GET("refresh_pyq/:id", ctrl.refreshPyq)
rg.GET("chatrooms", getChatRooms)
rg.GET("chatroom_members/:roomid", getChatRoomMembers)
rg.GET("alias_in_chatroom/:wxid/:roomid", getAliasInChatRoom)
rg.POST("invite_chatroom_members", inviteChatroomMembers)
rg.POST("add_chatroom_members", addChatRoomMembers)
rg.POST("del_chatroom_members", delChatRoomMembers)
rg.GET("chatrooms", ctrl.getChatRooms)
rg.GET("chatroom_members/:roomid", ctrl.getChatRoomMembers)
rg.GET("alias_in_chatroom/:wxid/:roomid", ctrl.getAliasInChatRoom)
rg.POST("invite_chatroom_members", ctrl.inviteChatroomMembers)
rg.POST("add_chatroom_members", ctrl.addChatRoomMembers)
rg.POST("del_chatroom_members", ctrl.delChatRoomMembers)
rg.GET("revoke_msg/:msgid", revokeMsg)
rg.POST("forward_msg", forwardMsg)
rg.POST("send_txt", sendTxt)
rg.POST("send_img", sendImg)
rg.POST("send_file", sendFile)
rg.POST("send_rich_text", sendRichText)
rg.POST("send_pat_msg", sendPatMsg)
rg.POST("get_audio_msg", getAudioMsg)
rg.POST("get_ocr_result", getOcrResult)
rg.POST("download_image", downloadImage)
rg.POST("download_attach", downloadAttach)
rg.GET("revoke_msg/:msgid", 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("get_audio_msg", ctrl.getAudioMsg)
rg.POST("get_ocr_result", ctrl.getOcrResult)
rg.POST("download_image", ctrl.downloadImage)
rg.POST("download_attach", ctrl.downloadAttach)
rg.POST("accept_new_friend", acceptNewFriend)
rg.POST("receive_transfer", receiveTransfer)
rg.POST("accept_new_friend", ctrl.acceptNewFriend)
rg.POST("receive_transfer", ctrl.receiveTransfer)
rg.POST("enable_forward_msg", enableForwardMsg)
rg.POST("disable_forward_msg", disableForwardMsg)
rg.POST("enable_forward_msg", ctrl.enableForwardMsg)
rg.POST("disable_forward_msg", ctrl.disableForwardMsg)
}

View File

@ -12,7 +12,7 @@
<body>
<ul>
<li><a href="/swag">Api Document</a></li>
<li><a href="/swag/">Api Document</a></li>
</ul>
</body>

20
clients/gohttp/start.bat Normal file
View File

@ -0,0 +1,20 @@
@ECHO OFF
::
SET GOARCH=386
SET CGO_ENABLED=0
SET GO111MODULE=on
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
CD /d %~dp0
go mod tidy
if exist .local.yml (
echo use .local.yaml as config
go run main.go .local.yml
) else (
go run main.go
)