mirror of
https://github.com/Mrs4s/go-cqhttp.git
synced 2025-05-04 19:17:37 +08:00
* feat: support set max retries and retries interval * fix: httpresponse using `res` before checking for errors * fix: `HttpServerPost` now be unexported * refactor: pretty `httpDefault`
This commit is contained in:
parent
024ec34fbe
commit
bfc29a8c97
115
server/http.go
115
server/http.go
@ -9,7 +9,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@ -40,14 +39,18 @@ type HTTPServer struct {
|
|||||||
Enabled bool `yaml:"enabled"`
|
Enabled bool `yaml:"enabled"`
|
||||||
MaxQueueSize int `yaml:"max-queue-size"`
|
MaxQueueSize int `yaml:"max-queue-size"`
|
||||||
} `yaml:"long-polling"`
|
} `yaml:"long-polling"`
|
||||||
Post []struct {
|
Post []httpServerPost `yaml:"post"`
|
||||||
URL string `yaml:"url"`
|
|
||||||
Secret string `yaml:"secret"`
|
|
||||||
}
|
|
||||||
|
|
||||||
MiddleWares `yaml:"middlewares"`
|
MiddleWares `yaml:"middlewares"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type httpServerPost struct {
|
||||||
|
URL string `yaml:"url"`
|
||||||
|
Secret string `yaml:"secret"`
|
||||||
|
MaxRetries *uint64 `yaml:"max-retries"`
|
||||||
|
RetriesInterval *uint64 `yaml:"retries-interval"`
|
||||||
|
}
|
||||||
|
|
||||||
type httpServer struct {
|
type httpServer struct {
|
||||||
HTTP *http.Server
|
HTTP *http.Server
|
||||||
api *api.Caller
|
api *api.Caller
|
||||||
@ -62,6 +65,8 @@ type HTTPClient struct {
|
|||||||
filter string
|
filter string
|
||||||
apiPort int
|
apiPort int
|
||||||
timeout int32
|
timeout int32
|
||||||
|
MaxRetries uint64
|
||||||
|
RetriesInterval uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type httpCtx struct {
|
type httpCtx struct {
|
||||||
@ -70,37 +75,41 @@ type httpCtx struct {
|
|||||||
postForm url.Values
|
postForm url.Values
|
||||||
}
|
}
|
||||||
|
|
||||||
const httpDefault = ` # HTTP 通信设置
|
const httpDefault = `
|
||||||
- http:
|
- http: # HTTP 通信设置
|
||||||
# 服务端监听地址
|
host: 127.0.0.1 # 服务端监听地址
|
||||||
host: 127.0.0.1
|
port: 5700 # 服务端监听端口
|
||||||
# 服务端监听端口
|
timeout: 5 # 反向 HTTP 超时时间, 单位秒,<5 时将被忽略
|
||||||
port: 5700
|
long-polling: # 长轮询拓展
|
||||||
# 反向HTTP超时时间, 单位秒
|
enabled: false # 是否开启
|
||||||
# 最小值为5,小于5将会忽略本项设置
|
max-queue-size: 2000 # 消息队列大小,0 表示不限制队列大小,谨慎使用
|
||||||
timeout: 5
|
|
||||||
# 长轮询拓展
|
|
||||||
long-polling:
|
|
||||||
# 是否开启
|
|
||||||
enabled: false
|
|
||||||
# 消息队列大小,0 表示不限制队列大小,谨慎使用
|
|
||||||
max-queue-size: 2000
|
|
||||||
middlewares:
|
middlewares:
|
||||||
<<: *default # 引用默认中间件
|
<<: *default # 引用默认中间件
|
||||||
# 反向HTTP POST地址列表
|
post: # 反向HTTP POST地址列表
|
||||||
post:
|
|
||||||
#- url: '' # 地址
|
#- url: '' # 地址
|
||||||
# secret: '' # 密钥
|
# secret: '' # 密钥
|
||||||
|
# max-retries: 3 # 最大重试,0 时禁用
|
||||||
|
# retries-interval: 1500 # 重试时间,单位毫秒,0 时立即
|
||||||
#- url: http://127.0.0.1:5701/ # 地址
|
#- url: http://127.0.0.1:5701/ # 地址
|
||||||
# secret: '' # 密钥
|
# secret: '' # 密钥
|
||||||
|
# max-retries: 10 # 最大重试,0 时禁用
|
||||||
|
# retries-interval: 1000 # 重试时间,单位毫秒,0 时立即
|
||||||
`
|
`
|
||||||
|
|
||||||
func init() {
|
func nilParseUint(s string, base int, bitSize int) *uint64 {
|
||||||
config.AddServer(&config.Server{
|
pu, err := strconv.ParseUint(s, base, bitSize)
|
||||||
Brief: "HTTP通信",
|
if err != nil {
|
||||||
Default: httpDefault,
|
return nil
|
||||||
ParseEnv: func() (string, *yaml.Node) {
|
}
|
||||||
if os.Getenv("GCQ_HTTP_PORT") != "" {
|
return &pu
|
||||||
|
}
|
||||||
|
|
||||||
|
func readEnvConfig() (string, *yaml.Node) {
|
||||||
|
|
||||||
|
if s, ok := os.LookupEnv("GCQ_HTTP_PORT"); !ok || s == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
// type convert tools
|
// type convert tools
|
||||||
toInt64 := func(str string) int64 {
|
toInt64 := func(str string) int64 {
|
||||||
i, _ := strconv.ParseInt(str, 10, 64)
|
i, _ := strconv.ParseInt(str, 10, 64)
|
||||||
@ -119,17 +128,19 @@ func init() {
|
|||||||
param.SetExcludeDefault(&httpConf.Host, os.Getenv("GCQ_HTTP_HOST"), "")
|
param.SetExcludeDefault(&httpConf.Host, os.Getenv("GCQ_HTTP_HOST"), "")
|
||||||
param.SetExcludeDefault(&httpConf.Port, int(toInt64(os.Getenv("GCQ_HTTP_PORT"))), 0)
|
param.SetExcludeDefault(&httpConf.Port, int(toInt64(os.Getenv("GCQ_HTTP_PORT"))), 0)
|
||||||
if os.Getenv("GCQ_HTTP_POST_URL") != "" {
|
if os.Getenv("GCQ_HTTP_POST_URL") != "" {
|
||||||
httpConf.Post = append(httpConf.Post, struct {
|
httpConf.Post = append(httpConf.Post, httpServerPost{
|
||||||
URL string `yaml:"url"`
|
os.Getenv("GCQ_HTTP_POST_URL"),
|
||||||
Secret string `yaml:"secret"`
|
os.Getenv("GCQ_HTTP_POST_SECRET"),
|
||||||
}{os.Getenv("GCQ_HTTP_POST_URL"), os.Getenv("GCQ_HTTP_POST_SECRET")})
|
nilParseUint(os.Getenv("GCQ_HTTP_POST_MAXRETRIES"), 10, 64),
|
||||||
|
nilParseUint(os.Getenv("GCQ_HTTP_POST_RETRIESINTERVAL"), 10, 64),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
_ = node.Encode(httpConf)
|
_ = node.Encode(httpConf)
|
||||||
return "http", node
|
return "http", node
|
||||||
}
|
}
|
||||||
return "", nil
|
|
||||||
},
|
func init() {
|
||||||
})
|
config.AddServer(&config.Server{Brief: "HTTP通信", Default: httpDefault, ParseEnv: readEnvConfig})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpCtx) Get(s string) gjson.Result {
|
func (h *httpCtx) Get(s string) gjson.Result {
|
||||||
@ -242,6 +253,13 @@ func checkAuth(req *http.Request, token string) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func puint64Operator(p *uint64, def uint64) uint64 {
|
||||||
|
if p == nil {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
return *p
|
||||||
|
}
|
||||||
|
|
||||||
// runHTTP 启动HTTP服务器与HTTP上报客户端
|
// runHTTP 启动HTTP服务器与HTTP上报客户端
|
||||||
func runHTTP(bot *coolq.CQBot, node yaml.Node) {
|
func runHTTP(bot *coolq.CQBot, node yaml.Node) {
|
||||||
var conf HTTPServer
|
var conf HTTPServer
|
||||||
@ -291,6 +309,8 @@ client:
|
|||||||
apiPort: conf.Port,
|
apiPort: conf.Port,
|
||||||
filter: conf.Filter,
|
filter: conf.Filter,
|
||||||
timeout: conf.Timeout,
|
timeout: conf.Timeout,
|
||||||
|
MaxRetries: puint64Operator(c.MaxRetries, 3),
|
||||||
|
RetriesInterval: puint64Operator(c.RetriesInterval, 1500),
|
||||||
}.Run()
|
}.Run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -330,10 +350,7 @@ func (c *HTTPClient) onBotPushEvent(e *coolq.Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var res *http.Response
|
var res *http.Response
|
||||||
var err error
|
for i := uint64(0); i <= c.MaxRetries; i++ {
|
||||||
const maxAttemptTimes = 5
|
|
||||||
|
|
||||||
for i := 0; i <= maxAttemptTimes; i++ {
|
|
||||||
// see https://stackoverflow.com/questions/31337891/net-http-http-contentlength-222-with-body-length-0
|
// see https://stackoverflow.com/questions/31337891/net-http-http-contentlength-222-with-body-length-0
|
||||||
// we should create a new request for every single post trial
|
// we should create a new request for every single post trial
|
||||||
req, err := http.NewRequest("POST", c.addr, bytes.NewReader(e.JSONBytes()))
|
req, err := http.NewRequest("POST", c.addr, bytes.NewReader(e.JSONBytes()))
|
||||||
@ -344,24 +361,22 @@ func (c *HTTPClient) onBotPushEvent(e *coolq.Event) {
|
|||||||
req.Header = header
|
req.Header = header
|
||||||
|
|
||||||
res, err = client.Do(req)
|
res, err = client.Do(req)
|
||||||
if err == nil {
|
if res != nil {
|
||||||
//goland:noinspection GoDeferInLoop
|
//goland:noinspection GoDeferInLoop
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if i != maxAttemptTimes {
|
if i < c.MaxRetries {
|
||||||
log.Warnf("上报 Event 数据到 %v 失败: %v 将进行第 %d 次重试", c.addr, err, i+1)
|
log.Warnf("上报 Event 数据到 %v 失败: %v 将进行第 %d 次重试", c.addr, err, i+1)
|
||||||
}
|
} else {
|
||||||
const maxWait = int64(time.Second * 3)
|
log.Warnf("上报 Event 数据 %s 到 %v 失败: %v 停止上报:已达重试上线", e.JSONBytes(), c.addr, err)
|
||||||
const minWait = int64(time.Millisecond * 500)
|
|
||||||
wait := rand.Int63n(maxWait-minWait) + minWait
|
|
||||||
time.Sleep(time.Duration(wait))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("上报Event数据 %s 到 %v 失败: %v", e.JSONBytes(), c.addr, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
time.Sleep(time.Millisecond * time.Duration(c.RetriesInterval))
|
||||||
|
}
|
||||||
|
|
||||||
log.Debugf("上报Event数据 %s 到 %v", e.JSONBytes(), c.addr)
|
log.Debugf("上报Event数据 %s 到 %v", e.JSONBytes(), c.addr)
|
||||||
|
|
||||||
r, err := io.ReadAll(res.Body)
|
r, err := io.ReadAll(res.Body)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user