From 82e2ea8466b0750229401a2e2b14905f19f21a53 Mon Sep 17 00:00:00 2001 From: Mrs4s <1844812067@qq.com> Date: Thu, 23 Jul 2020 20:58:17 +0800 Subject: [PATCH] http post supported. --- README.md | 2 +- coolq/bot.go | 6 +++--- coolq/event.go | 26 +++++++++++++------------- global/config.go | 14 ++++++++------ go.mod | 1 + go.sum | 14 ++++++++++++++ main.go | 7 +++++++ server/http.go | 42 ++++++++++++++++++++++++++++++++++++++++++ server/websocket.go | 7 +++++-- 9 files changed, 94 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 99469b8..497111d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ # 兼容性 #### 接口 - [x] HTTP API -- [ ] 反向HTTP POST (开发中) +- [x] 反向HTTP POST (暂不支持回复) - [x] 正向Websocket - [ ] 反向Websocket (开发中) #### 实现 diff --git a/coolq/bot.go b/coolq/bot.go index e66d897..a6dbda6 100644 --- a/coolq/bot.go +++ b/coolq/bot.go @@ -19,7 +19,7 @@ import ( type CQBot struct { Client *client.QQClient - events []func(string) + events []func(MSG) db *nutsdb.DB friendReqCache sync.Map invitedReqCache sync.Map @@ -62,7 +62,7 @@ func NewQQBot(cli *client.QQClient, conf *global.JsonConfig) *CQBot { return bot } -func (bot *CQBot) OnEventPush(f func(m string)) { +func (bot *CQBot) OnEventPush(f func(m MSG)) { bot.events = append(bot.events, f) } @@ -157,7 +157,7 @@ func (bot *CQBot) Release() { _ = bot.db.Close() } -func (bot *CQBot) dispatchEventMessage(m string) { +func (bot *CQBot) dispatchEventMessage(m MSG) { for _, f := range bot.events { f(m) } diff --git a/coolq/event.go b/coolq/event.go index 6bf2ae9..dc46a16 100644 --- a/coolq/event.go +++ b/coolq/event.go @@ -35,7 +35,7 @@ func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMess "age": 0, }, } - bot.dispatchEventMessage(fm.ToJson()) + bot.dispatchEventMessage(fm) } func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage) { @@ -92,7 +92,7 @@ func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage) ms["card"] = mem.CardName ms["title"] = mem.SpecialTitle } - bot.dispatchEventMessage(gm.ToJson()) + bot.dispatchEventMessage(gm) } func (bot *CQBot) tempMessageEvent(c *client.QQClient, m *message.TempMessage) { @@ -117,7 +117,7 @@ func (bot *CQBot) tempMessageEvent(c *client.QQClient, m *message.TempMessage) { "age": 0, }, } - bot.dispatchEventMessage(tm.ToJson()) + bot.dispatchEventMessage(tm) } func (bot *CQBot) groupMutedEvent(c *client.QQClient, e *client.GroupMuteEvent) { @@ -144,7 +144,7 @@ func (bot *CQBot) groupMutedEvent(c *client.QQClient, e *client.GroupMuteEvent) } return "lift_ban" }(), - }.ToJson()) + }) } func (bot *CQBot) groupRecallEvent(c *client.QQClient, e *client.GroupMessageRecalledEvent) { @@ -161,7 +161,7 @@ func (bot *CQBot) groupRecallEvent(c *client.QQClient, e *client.GroupMessageRec "operator_id": e.OperatorUin, "time": e.Time, "message_id": gid, - }.ToJson()) + }) } func (bot *CQBot) joinGroupEvent(c *client.QQClient, group *client.GroupInfo) { @@ -193,7 +193,7 @@ func (bot *CQBot) memberPermissionChangedEvent(c *client.QQClient, e *client.Mem "user_id": e.Member.Uin, "time": time.Now().Unix(), "self_id": c.Uin, - }.ToJson()) + }) } func (bot *CQBot) memberJoinEvent(c *client.QQClient, e *client.MemberJoinGroupEvent) { @@ -222,7 +222,7 @@ func (bot *CQBot) friendRequestEvent(c *client.QQClient, e *client.NewFriendRequ "flag": flag, "time": time.Now().Unix(), "self_id": c.Uin, - }.ToJson()) + }) } func (bot *CQBot) groupInvitedEvent(c *client.QQClient, e *client.GroupInvitedRequest) { @@ -239,7 +239,7 @@ func (bot *CQBot) groupInvitedEvent(c *client.QQClient, e *client.GroupInvitedRe "flag": flag, "time": time.Now().Unix(), "self_id": c.Uin, - }.ToJson()) + }) } func (bot *CQBot) groupJoinReqEvent(c *client.QQClient, e *client.UserJoinGroupRequest) { @@ -256,10 +256,10 @@ func (bot *CQBot) groupJoinReqEvent(c *client.QQClient, e *client.UserJoinGroupR "flag": flag, "time": time.Now().Unix(), "self_id": c.Uin, - }.ToJson()) + }) } -func (bot *CQBot) groupIncrease(groupCode, operatorUin, userUin int64) string { +func (bot *CQBot) groupIncrease(groupCode, operatorUin, userUin int64) MSG { return MSG{ "post_type": "notice", "notice_type": "group_increase", @@ -269,10 +269,10 @@ func (bot *CQBot) groupIncrease(groupCode, operatorUin, userUin int64) string { "sub_type": "approve", "time": time.Now().Unix(), "user_id": userUin, - }.ToJson() + } } -func (bot *CQBot) groupDecrease(groupCode, userUin int64, operator *client.GroupMemberInfo) string { +func (bot *CQBot) groupDecrease(groupCode, userUin int64, operator *client.GroupMemberInfo) MSG { return MSG{ "post_type": "notice", "notice_type": "group_decrease", @@ -295,7 +295,7 @@ func (bot *CQBot) groupDecrease(groupCode, userUin int64, operator *client.Group }(), "time": time.Now().Unix(), "user_id": userUin, - }.ToJson() + } } func checkImage(e []message.IMessageElement) { diff --git a/global/config.go b/global/config.go index 161813f..8f8e3b2 100644 --- a/global/config.go +++ b/global/config.go @@ -36,9 +36,10 @@ type CQHttpApiConfig struct { } type GoCQHttpConfig struct { - Enabled bool `json:"enabled"` - Host string `json:"host"` - Port uint16 `json:"port"` + Enabled bool `json:"enabled"` + Host string `json:"host"` + Port uint16 `json:"port"` + PostUrls map[string]string `json:"post_urls"` } type GoCQWebsocketConfig struct { @@ -51,9 +52,10 @@ func DefaultConfig() *JsonConfig { return &JsonConfig{ EnableDB: true, HttpConfig: &GoCQHttpConfig{ - Enabled: true, - Host: "0.0.0.0", - Port: 5700, + Enabled: true, + Host: "0.0.0.0", + Port: 5700, + PostUrls: map[string]string{}, }, WSConfig: &GoCQWebsocketConfig{ Enabled: true, diff --git a/go.mod b/go.mod index b887667..166d3a8 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/Mrs4s/MiraiGo v0.0.0-20200721195252-2accd73f8b8e github.com/gin-gonic/gin v1.6.3 github.com/gorilla/websocket v1.4.2 + github.com/guonaihong/gout v0.1.1 github.com/lestrrat-go/file-rotatelogs v2.3.0+incompatible github.com/lestrrat-go/strftime v1.0.1 // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/go.sum b/go.sum index 01d1b76..e802555 100644 --- a/go.sum +++ b/go.sum @@ -24,11 +24,14 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= @@ -53,13 +56,18 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/guonaihong/gout v0.1.1 h1:2i3eqQ1KUhTlj7AFeIHqVUFku5QwUhwE2wNgYTVpbxQ= +github.com/guonaihong/gout v0.1.1/go.mod h1:vXvv5Kxr70eM5wrp4F0+t9lnLWmq+YPW2GByll2f/EA= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= @@ -67,6 +75,7 @@ github.com/lestrrat-go/file-rotatelogs v2.3.0+incompatible h1:4mNlp+/SvALIPFpbXV github.com/lestrrat-go/file-rotatelogs v2.3.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= github.com/lestrrat-go/strftime v1.0.1 h1:o7qz5pmLzPDLyGW4lG6JvTKPUfTFXwe+vOamIYWtnVU= github.com/lestrrat-go/strftime v1.0.1/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -116,6 +125,8 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -124,6 +135,7 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo= @@ -155,6 +167,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go index 1615feb..b347ec1 100644 --- a/main.go +++ b/main.go @@ -53,9 +53,13 @@ func init() { goConf.HttpConfig.Port = conf.Port goConf.WSConfig.Host = conf.WSHost goConf.WSConfig.Port = conf.WSPort + if conf.PostUrl != "" { + goConf.HttpConfig.PostUrls[conf.PostUrl] = conf.Secret + } if err := goConf.Save("config.json"); err != nil { log.Fatalf("保存 config.json 时出现错误: %v", err) } + _ = os.Remove("cqhttp.json") } } @@ -126,6 +130,9 @@ func main() { b := coolq.NewQQBot(cli, conf) if conf.HttpConfig != nil && conf.HttpConfig.Enabled { server.HttpServer.Run(fmt.Sprintf("%s:%d", conf.HttpConfig.Host, conf.HttpConfig.Port), conf.AccessToken, b) + for k, v := range conf.HttpConfig.PostUrls { + server.NewClient().Run(k, v, b) + } } if conf.WSConfig != nil && conf.WSConfig.Enabled { server.WebsocketServer.Run(fmt.Sprintf("%s:%d", conf.WSConfig.Host, conf.WSConfig.Port), conf.AccessToken, b) diff --git a/server/http.go b/server/http.go index f12790c..208ab39 100644 --- a/server/http.go +++ b/server/http.go @@ -1,12 +1,17 @@ package server import ( + "crypto/hmac" + "crypto/sha1" + "encoding/hex" "github.com/Mrs4s/go-cqhttp/coolq" "github.com/gin-gonic/gin" + "github.com/guonaihong/gout" log "github.com/sirupsen/logrus" "github.com/tidwall/gjson" "strconv" "strings" + "time" ) type httpServer struct { @@ -14,6 +19,12 @@ type httpServer struct { bot *coolq.CQBot } +type httpClient struct { + bot *coolq.CQBot + secret string + addr string +} + var HttpServer = &httpServer{} func (s *httpServer) Run(addr, authToken string, bot *coolq.CQBot) { @@ -137,6 +148,37 @@ func (s *httpServer) Run(addr, authToken string, bot *coolq.CQBot) { }() } +func NewClient() *httpClient { + return &httpClient{} +} + +func (c *httpClient) Run(addr, secret string, bot *coolq.CQBot) { + c.bot = bot + c.secret = secret + c.addr = addr + bot.OnEventPush(c.onBotPushEvent) + log.Infof("HTTP POST上报器已启动: %v", addr) +} + +func (c *httpClient) onBotPushEvent(m coolq.MSG) { + err := gout.POST(c.addr).SetJSON(m).SetHeader(func() gout.H { + h := gout.H{ + "X-Self_ID": c.bot.Client.Uin, + "X-Client-Role": "Universal", + "User-Agent": "CQHttp/4.15.0", + } + if c.secret != "" { + mac := hmac.New(sha1.New, []byte(c.secret)) + mac.Write([]byte(m.ToJson())) + h["X-Signature"] = "sha1=" + hex.EncodeToString(mac.Sum(nil)) + } + return h + }()).SetTimeout(time.Second * 5).Do() + if err != nil { + log.Warnf("上报Event数据到 %v 失败: %v", c.addr, err) + } +} + func (s *httpServer) GetLoginInfo(c *gin.Context) { c.JSON(200, s.bot.CQGetLoginInfo()) } diff --git a/server/websocket.go b/server/websocket.go index 08ce5e0..45ad310 100644 --- a/server/websocket.go +++ b/server/websocket.go @@ -20,6 +20,9 @@ type websocketServer struct { handshake string } +type websocketClient struct { +} + var WebsocketServer = &websocketServer{} var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { @@ -119,12 +122,12 @@ func (s *websocketServer) listenApi(c *websocket.Conn) { } } -func (s *websocketServer) onBotPushEvent(m string) { +func (s *websocketServer) onBotPushEvent(m coolq.MSG) { s.pushLock.Lock() defer s.pushLock.Unlock() pos := 0 for _, conn := range s.eventConn { - err := conn.WriteMessage(websocket.TextMessage, []byte(m)) + err := conn.WriteMessage(websocket.TextMessage, []byte(m.ToJson())) if err != nil { _ = conn.Close() s.eventConn = append(s.eventConn[:pos], s.eventConn[pos+1:]...)