]> 127.0.0.1 Git - front/.git/commitdiff
1
authorqydysky <qydysky@foxmail.com>
Sun, 9 Mar 2025 16:28:13 +0000 (00:28 +0800)
committerqydysky <qydysky@foxmail.com>
Sun, 9 Mar 2025 16:28:13 +0000 (00:28 +0800)
README.md
config.go
filiter/filiter.go
go.mod
go.sum
main/main.json

index 31e321b1d133d1e1a1804e35a802e717394a5ada..38931541f2a396f107f6829a58c01d07767aa371 100755 (executable)
--- a/README.md
+++ b/README.md
@@ -75,8 +75,8 @@ config:
 - *addr*: string 监听端口 例:`0.0.0.0:8081`
 - *matchRule*: string 匹配规则,默认`prefix`。 `prefix`:当未匹配到时,返回最近的/匹配, `all`:当未匹配到时,返回404
 - *copyBlocks*: int 转发的块数量,默认`1000`
-- *retryBlocks*: {} 重试, 当停用时,分配仅进行一次
-    - *sizeB*: int 重试的块大小,默认`1000000`
+- *retryBlocks*: {} 重试, 当停用时,分配仅进行一次。当所有块都在使用中时,跳过。当请求没有`Content-Length`时,跳过。
+    - *size*: string 重试的块大小,默认`1M`
     - *num*: int 重试的块数量,默认`0`,为`0`时停用重试
 - *tls*: {} 启用tls, 默认空
     - *pub*: string 公钥pem路径
@@ -91,10 +91,6 @@ config:
         - `dealingC_MinFirst`(连接数较少的优先)
         - `chosenC_MinFirst`(被选择较少的优先)
         - (使用rand.Shuffle随机,默认)
-    - reqBody: 请求后端前,请求数据过滤器
-        - action: string 可选`access`、`deny`。
-        - reqSize: string 限定请求数据大小,默认为`1M`
-        - matchExp: string `access`时如不匹配将结束请求。`deny`时如匹配将结束请求。
     - setting... 将会给backs默认值
     - backs: [] 后端
         - name: string 后端名称,将在日志中显示
@@ -105,7 +101,7 @@ config:
         - alwaysUp: bool 总是在线, 当只有一个后端时,默认为true
         - setting...
 
-setting: json配置不需要setting
+setting: setting代指下述各配置
 
 - splicing: int 当客户端支持cookie时,将会固定使用后端多少秒,默认不启用
 - errToSec: float64 当后端响应超过(ws则指初次返回时间)指定秒,将会触发errBanSec
@@ -130,6 +126,11 @@ setting: json配置不需要setting
             - id:
                 - key: string header头
                 - matchExp: string
+    - reqBody: 请求后端前,请求数据过滤器(仅route层有效)
+        - action: string 可选`access`、`deny`
+        - reqSize: string 限定请求数据大小,默认为`1M`
+        - matchExp: string `access`时如不匹配将结束请求。`deny`时如匹配将结束请求
+
 - dealer:
     - reqUri:[] 请求后端前,路径处理器
         - action: string 可选`replace`。
index 67779b37a665b25b5b831c6996b010d4ad75627b..9377194e7820dd92d6a862e772cfcf55893f2068 100755 (executable)
--- a/config.go
+++ b/config.go
@@ -11,6 +11,7 @@ import (
        "net"
        "net/http"
        "os"
+       "strconv"
        "strings"
        "sync"
        "time"
@@ -32,8 +33,9 @@ type Config struct {
                Key string `json:"key"`
        } `json:"tls"`
        RetryBlocks struct {
-               SizeB int `json:"sizeB"`
-               Num   int `json:"num"`
+               Size string `json:"size"`
+               size int    `json:"-"`
+               Num  int    `json:"num"`
        } `json:"retryBlocks"`
        RetryBlocksI pslice.BlocksI[byte] `json:"-"`
        MatchRule    string               `json:"matchRule"`
@@ -71,11 +73,13 @@ func (t *Config) Run(ctx context.Context, logger Logger) {
                }
                t.BlocksI = pslice.NewBlocks[byte](16*1024, t.CopyBlocks)
        }
-       if t.RetryBlocks.SizeB == 0 {
-               t.RetryBlocks.SizeB = humanize.MByte
+       if size, err := humanize.ParseBytes(t.RetryBlocks.Size); err != nil || size < humanize.MByte {
+               t.RetryBlocks.size = humanize.MByte
+       } else {
+               t.RetryBlocks.size = int(size)
        }
-       if t.RetryBlocks.SizeB > 0 && t.RetryBlocks.Num > 0 {
-               t.RetryBlocksI = pslice.NewBlocks[byte](t.RetryBlocks.SizeB, t.RetryBlocks.Num)
+       if t.RetryBlocks.size > 0 && t.RetryBlocks.Num > 0 {
+               t.RetryBlocksI = pslice.NewBlocks[byte](t.RetryBlocks.size, t.RetryBlocks.Num)
        }
 
        defer logger.Info(`I:`, fmt.Sprintf("%v shutdown", t.Addr))
@@ -160,7 +164,7 @@ func (t *Config) SwapSign(ctx context.Context, logger Logger) {
                                        return
                                }
 
-                               if ok, e := route.ReqBody.Match(r); e != nil {
+                               if ok, e := route.Filiter.ReqBody.Match(r); e != nil {
                                        logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "Err", e))
                                } else if !ok {
                                        logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "BLOCK", ErrBodyCheckFail))
@@ -210,59 +214,65 @@ func (t *Config) SwapSign(ctx context.Context, logger Logger) {
                                }
 
                                // repack
-                               var reBuf []byte
+                               var (
+                                       reqBuf     []byte
+                                       reqBufUsed bool
+                               )
                                if t.RetryBlocksI != nil && r.Body != nil {
-                                       var putBack func()
-                                       var e error
-                                       reBuf, putBack, e = t.RetryBlocksI.Get()
-                                       if e != nil {
-                                               logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "Err", ErrReqReBodyFail))
-                                               w.Header().Add(header+"Error", ErrReqReBodyFail.Error())
-                                               w.WriteHeader(http.StatusServiceUnavailable)
-                                               return
-                                       }
-                                       defer putBack()
-                                       if n, _ := r.Body.Read(reBuf); n == cap(reBuf) {
-                                               logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "Err", ErrReqReBodyOverflow))
-                                               w.Header().Add(header+"Error", ErrReqReBodyOverflow.Error())
-                                               w.WriteHeader(http.StatusServiceUnavailable)
-                                               return
+                                       if contentLength := r.Header.Get("Content-Length"); contentLength != "" {
+                                               if len, e := strconv.Atoi(contentLength); e == nil && t.RetryBlocks.size >= len {
+                                                       var putBack func()
+                                                       var e error
+                                                       reqBuf, putBack, e = t.RetryBlocksI.Get()
+                                                       if e == nil {
+                                                               defer putBack()
+                                                               reqBufUsed = true
+                                                               _, _ = r.Body.Read(reqBuf)
+                                                               // if n, _ := r.Body.Read(reqBuf); n == cap(reqBuf) {
+                                                               // logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "Err", ErrReqReBodyOverflow))
+                                                               //      w.Header().Add(header+"Error", ErrReqReBodyOverflow.Error())
+                                                               //      w.WriteHeader(http.StatusServiceUnavailable)
+                                                               //      return
+                                                               // }
+                                                               // logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "Err", ErrReqReBodyFail))
+                                                               // w.Header().Add(header+"Error", ErrReqReBodyFail.Error())
+                                                               // w.WriteHeader(http.StatusServiceUnavailable)
+                                                               // return
+                                                       } else {
+                                                               logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "Err", ErrReqReBodyOverflow))
+                                                       }
+                                               }
                                        }
                                }
 
-                               for i := 0; i < len(backIs); i++ {
-                                       if !backIs[i].IsLive() {
+                               for _, backP := range backIs {
+                                       if !backP.IsLive() {
                                                continue
                                        }
 
-                                       backIs[i].lock.Lock()
-                                       backIs[i].lastChosenT = time.Now()
-                                       backIs[i].lock.Unlock()
+                                       backP.lock.Lock()
+                                       backP.lastChosenT = time.Now()
+                                       backP.lock.Unlock()
 
-                                       if len(reBuf) != 0 {
-                                               r.Body = io.NopCloser(bytes.NewBuffer(reBuf))
+                                       if reqBufUsed {
+                                               r.Body = io.NopCloser(bytes.NewBuffer(reqBuf))
                                        }
 
-                                       if !strings.Contains(backIs[i].To, "://") {
-                                               e = component2.Get[reqDealer]("local").Deal(r.Context(), w, r, routePath, backIs[i], logger, t.BlocksI)
+                                       if !strings.Contains(backP.To, "://") {
+                                               e = component2.Get[reqDealer]("local").Deal(r.Context(), w, r, routePath, backP, logger, t.BlocksI)
                                        } else if strings.ToLower((r.Header.Get("Upgrade"))) == "websocket" {
-                                               e = component2.Get[reqDealer]("ws").Deal(r.Context(), w, r, routePath, backIs[i], logger, t.BlocksI)
+                                               e = component2.Get[reqDealer]("ws").Deal(r.Context(), w, r, routePath, backP, logger, t.BlocksI)
                                        } else {
-                                               e = component2.Get[reqDealer]("http").Deal(r.Context(), w, r, routePath, backIs[i], logger, t.BlocksI)
+                                               e = component2.Get[reqDealer]("http").Deal(r.Context(), w, r, routePath, backP, logger, t.BlocksI)
                                        }
 
-                                       // no err
                                        if e == nil {
+                                               // no err
                                                break
                                        }
 
-                                       // no retryBuf
-                                       if len(reBuf) == 0 {
-                                               break
-                                       }
-
-                                       // some err can retry
                                        if v, ok := e.(ErrCanRetry); !ok || !v.CanRetry {
+                                               // some err can't retry
                                                break
                                        }
                                }
@@ -329,9 +339,9 @@ type Route struct {
        config *Config  `json:"-"`
        Path   []string `json:"path"`
 
-       PathAdd  bool         `json:"pathAdd"`
-       RollRule string       `json:"rollRule"`
-       ReqBody  filiter.Body `json:"reqBody"`
+       PathAdd  bool   `json:"pathAdd"`
+       RollRule string `json:"rollRule"`
+       // ReqBody  filiter.Body `json:"reqBody"`
        Setting
 
        backMap sync.Map `json:"-"`
@@ -482,6 +492,14 @@ func (t *Back) getFiliterResHeader() *filiter.Header {
                return &t.Filiter.ResHeader
        }
 }
+
+//     func (t *Back) getFiliterResBody() *filiter.Body {
+//             if !t.Filiter.ReqBody.Valid() {
+//                     return &t.route.Filiter.ReqBody
+//             } else {
+//                     return &t.Filiter.ReqBody
+//             }
+//     }
 func (t *Back) getDealerReqUri() []dealer.UriDealer {
        return append(t.route.Dealer.ReqUri, t.Dealer.ReqUri...)
 }
index b18d8a283cd6ffade98a9fa2fa33f5ce8802ab65..8bca94a9c579f3bf118191cfcd78cc768e3799c5 100644 (file)
@@ -4,4 +4,5 @@ type Filiter struct {
        ReqHeader Header `json:"reqHeader"`
        ReqUri    Uri    `json:"reqUri"`
        ResHeader Header `json:"resHeader"`
+       ReqBody   Body   `json:"reqBody"`
 }
diff --git a/go.mod b/go.mod
index 87160d2f5905a2c6a56ac7c3e7002b36133ad83a..3cc3eb9b2bd2b3ce61441c460e81dbf686f849ee 100755 (executable)
--- a/go.mod
+++ b/go.mod
@@ -1,14 +1,12 @@
 module github.com/qydysky/front
 
-go 1.23
-
-toolchain go1.23.0
+go 1.24
 
 require (
        github.com/dustin/go-humanize v1.0.1
        github.com/gorilla/websocket v1.5.3
-       github.com/qydysky/part v0.28.20241026070051
-       golang.org/x/net v0.28.0
+       github.com/qydysky/part v0.28.20250302140701
+       golang.org/x/net v0.33.0
 )
 
 require (
@@ -19,10 +17,10 @@ require (
        github.com/qydysky/brotli v0.0.0-20240828134800-e9913a6e7ed9 // indirect
        github.com/shirou/gopsutil v3.21.11+incompatible // indirect
        github.com/tklauser/go-sysconf v0.3.14 // indirect
-       github.com/tklauser/numcpus v0.8.0 // indirect
+       github.com/tklauser/numcpus v0.9.0 // indirect
        github.com/yusufpapurcu/wmi v1.2.4 // indirect
-       golang.org/x/sys v0.24.0 // indirect
-       golang.org/x/text v0.17.0 // indirect
+       golang.org/x/sys v0.28.0 // indirect
+       golang.org/x/text v0.21.0 // indirect
        gopkg.in/yaml.v3 v3.0.1 // indirect
 )
 
diff --git a/go.sum b/go.sum
index 889b80a6aceafcfba577e498725381db79b316a2..be4973d9529fdd5824036c614501ed3379f10da2 100755 (executable)
--- a/go.sum
+++ b/go.sum
@@ -15,10 +15,10 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
 github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
 github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
 github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
-github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
-github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
-github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
-github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
+github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
+github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
+github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
+github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
@@ -27,47 +27,49 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/qydysky/brotli v0.0.0-20240828134800-e9913a6e7ed9 h1:k451T+bpsLr+Dq9Ujo+Qtx0iomRA1XXS5ttlEojvfuQ=
 github.com/qydysky/brotli v0.0.0-20240828134800-e9913a6e7ed9/go.mod h1:cI8/gy/wjy2Eb+p2IUj2ZuDnC8R5Vrx3O0VMPvMvphA=
-github.com/qydysky/part v0.28.20241026070051 h1:XZ6tchMpES/JFhpCNqK+qyIkBWhQpNE6RYor4MOxB48=
-github.com/qydysky/part v0.28.20241026070051/go.mod h1:s3h7P6YdST5b9WoqjlS9w+JzDFdMeSENQOi8noYuopg=
+github.com/qydysky/part v0.28.20250302140701 h1:ipKIXva/19714JdPIHeF/4d++BWisWwn97W30fDV/Rk=
+github.com/qydysky/part v0.28.20250302140701/go.mod h1:MsSAiZMiWQ5pGP5BCEB3OBsoAPaGykNB7vbeY3mKF2w=
 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
 github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
 github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
 github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
-github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
-github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
+github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo=
+github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI=
 github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
 github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
 github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
 github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
-golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
-golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
-golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
-golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
-golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
-golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
+golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU=
+golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
-golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
-golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a h1:CfbpOLEo2IwNzJdMvE8aiRbPMxoTpgAJeyePh0SmO8M=
-modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
-modernc.org/libc v1.59.9 h1:k+nNDDakwipimgmJ1D9H466LhFeSkaPPycAs1OZiDmY=
-modernc.org/libc v1.59.9/go.mod h1:EY/egGEU7Ju66eU6SBqCNYaFUDuc4npICkMWnU5EE3A=
+modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852 h1:IYXPPTTjjoSHvUClZIYexDiO7g+4x+XveKT4gCIAwiY=
+modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
+modernc.org/libc v1.61.4 h1:wVyqEx6tlltte9lPTjq0kDAdtdM9c4JH8rU6M1ZVawA=
+modernc.org/libc v1.61.4/go.mod h1:VfXVuM/Shh5XsMNrh3C6OkfL78G3loa4ZC/Ljv9k7xc=
 modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
 modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
 modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
 modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
-modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s=
-modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA=
+modernc.org/sqlite v1.34.2 h1:J9n76TPsfYYkFkZ9Uy1QphILYifiVEwwOT7yP5b++2Y=
+modernc.org/sqlite v1.34.2/go.mod h1:dnR723UrTtjKpoHCAMN0Q/gZ9MT4r+iRvIBb9umWFkU=
 modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
 modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
 modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
index e66f27da265649bd04ce6e150626d9b76e0ba6a5..4a9d5b81e777f685111a2a3cecd05184a8a3d531 100755 (executable)
@@ -7,16 +7,15 @@
       "pub": "",
       "key": ""
     },
+    "retryBlocks": {
+      "sizeB": 10,
+      "num": 10
+    },
     "routes": [
       {
         "path": [""],
         "pathAdd": false,
         "rollRule": "",
-        "reqBody": {
-          "action": "",
-          "reqSize": "1M",
-          "matchExp": ""
-        },
         "splicing": 0,
         "errToSec": 0,
         "errBanSec": 0,
                 "matchExp": ""
               }
             }
+          },
+          "reqBody": {
+            "action": "",
+            "reqSize": "1M",
+            "matchExp": ""
           }
         },
         "dealer": {