diff --git a/.gitignore b/.gitignore index a9ea21f..5c75b7d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,6 @@ .idea .vscode *.log -goinit.sh gomod.sh -*_test.go \ No newline at end of file +*_test.go +/vendor/ diff --git a/client.go b/client.go index 6f4b989..cddc9bd 100644 --- a/client.go +++ b/client.go @@ -4,23 +4,22 @@ import ( "go.dtapp.net/dorm" "go.dtapp.net/golog" "go.dtapp.net/gorequest" - "gorm.io/gorm" ) type ConfigClient struct { - AppKey string // 应用Key - SecretKey string // 密钥 - SiteId string // 网站ID/APP ID - PositionId string // 推广位id - MongoDb *dorm.MongoClient // 日志数据库 - PgsqlDb *gorm.DB // 日志数据库 - DatabaseName string // 库名 + AppKey string // 应用Key + SecretKey string // 密钥 + SiteId string // 网站ID/APP ID + PositionId string // 推广位id + GormClient *dorm.GormClient // 日志数据库 + LogClient *golog.ZapLog // 日志驱动 + LogDebug bool // 日志开关 } type Client struct { - client *gorequest.App // 请求客户端 - log *golog.ApiClient // 日志服务 - config *ConfigClient // 配置 + requestClient *gorequest.App // 请求服务 + logClient *golog.ApiClient // 日志服务 + config *ConfigClient // 配置 } func NewClient(config *ConfigClient) (*Client, error) { @@ -28,24 +27,16 @@ func NewClient(config *ConfigClient) (*Client, error) { var err error c := &Client{config: config} - c.client = gorequest.NewHttp() - c.client.Uri = apiUrl + c.requestClient = gorequest.NewHttp() + c.requestClient.Uri = apiUrl - if c.config.PgsqlDb != nil { - c.log, err = golog.NewApiClient( - golog.WithGormClient(c.config.PgsqlDb), - golog.WithTableName(logTable), - ) - if err != nil { - return nil, err - } - } - if c.config.MongoDb != nil { - c.log, err = golog.NewApiClient( - golog.WithMongoClient(c.config.MongoDb), - golog.WithDatabaseName(c.config.DatabaseName), - golog.WithCollectionName(logTable), - ) + if c.config.GormClient.Db != nil { + c.logClient, err = golog.NewApiClient(&golog.ApiClientConfig{ + GormClient: c.config.GormClient, + TableName: logTable, + LogClient: c.config.LogClient, + LogDebug: c.config.LogDebug, + }) if err != nil { return nil, err } diff --git a/const.go b/const.go index 506dd99..0942802 100644 --- a/const.go +++ b/const.go @@ -8,4 +8,4 @@ const ( logTable = "jd" ) -const Version = "1.0.4" +const Version = "1.0.5" diff --git a/go.mod b/go.mod index a01c1fe..ae744e7 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,10 @@ module go.dtapp.net/jd go 1.19 require ( - go.dtapp.net/dorm v1.0.17 - go.dtapp.net/golog v1.0.24 - go.dtapp.net/gorequest v1.0.26 + go.dtapp.net/dorm v1.0.27 + go.dtapp.net/golog v1.0.29 + go.dtapp.net/gorequest v1.0.27 go.dtapp.net/gostring v1.0.6 - gorm.io/gorm v1.23.8 ) require ( @@ -37,13 +36,15 @@ require ( github.com/klauspost/compress v1.15.9 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/lib/pq v1.10.6 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.6.6 // indirect github.com/natefinch/lumberjack v2.0.0+incompatible // indirect github.com/pelletier/go-toml/v2 v2.0.2 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/rs/zerolog v1.27.0 // indirect github.com/saracen/go7z v0.0.0-20191010121135-9c09b6bd7fda // indirect github.com/saracen/solidblock v0.0.0-20190426153529-45df20abab6f // indirect github.com/sirupsen/logrus v1.9.0 // indirect @@ -62,11 +63,11 @@ require ( github.com/xdg-go/scram v1.1.1 // indirect github.com/xdg-go/stringprep v1.0.3 // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect - go.dtapp.net/goip v1.0.24 // indirect + go.dtapp.net/goip v1.0.25 // indirect go.dtapp.net/gojson v1.0.1 // indirect go.dtapp.net/gorandom v1.0.1 // indirect go.dtapp.net/gotime v1.0.5 // indirect - go.dtapp.net/gotrace_id v1.0.0 // indirect + go.dtapp.net/gotrace_id v1.0.5 // indirect go.dtapp.net/gourl v1.0.0 // indirect go.dtapp.net/goxml v1.0.1 // indirect go.mongodb.org/mongo-driver v1.10.1 // indirect @@ -82,8 +83,9 @@ require ( google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gorm.io/datatypes v1.0.7 // indirect - gorm.io/driver/mysql v1.3.5 // indirect - gorm.io/driver/postgres v1.3.8 // indirect + gorm.io/driver/mysql v1.3.6 // indirect + gorm.io/driver/postgres v1.3.9 // indirect + gorm.io/gorm v1.23.8 // indirect mellium.im/sasl v0.2.1 // indirect xorm.io/builder v0.3.12 // indirect xorm.io/xorm v1.3.1 // indirect diff --git a/go.sum b/go.sum index 3ab1243..455b216 100644 --- a/go.sum +++ b/go.sum @@ -52,6 +52,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -110,6 +111,7 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.9.10 h1:hCeNmprSNLB8B8vQKWl6DpuH0t60oEs+TAk9a7CScKc= github.com/goccy/go-json v0.9.10/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -307,6 +309,8 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -314,8 +318,9 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= @@ -412,8 +417,11 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs= +github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -499,24 +507,24 @@ github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= -go.dtapp.net/dorm v1.0.17 h1:3VQKUl05CDxFg3T1c/M8wYf2I+H+oVGBDh4NCV30nn0= -go.dtapp.net/dorm v1.0.17/go.mod h1:bHG7BmgeLaAlc56myYF63lwZAIuMeWRAqHBb/L84dLM= -go.dtapp.net/goip v1.0.24 h1:62k3xt9I/YLUwA5tLp7YC8XPskkswc4RJrvxRRxjwIY= -go.dtapp.net/goip v1.0.24/go.mod h1:tps0yoq5kSykLGDb01vuai47hzAQ6nYUPFWLdlQA2Oo= +go.dtapp.net/dorm v1.0.27 h1:TnRWVfYYjfvZ1Zi2cyb41ZmsbytB4+5fN/FVnodd2NQ= +go.dtapp.net/dorm v1.0.27/go.mod h1:bHG7BmgeLaAlc56myYF63lwZAIuMeWRAqHBb/L84dLM= +go.dtapp.net/goip v1.0.25 h1:GSgQkR7dc28TX8E1mF3wAy+EEGZ++tgqc8Q85OKZPEY= +go.dtapp.net/goip v1.0.25/go.mod h1:dKeNuWJttH4AvvYVHV0FagB6BVvFM1HGDKFxLKr+hkQ= go.dtapp.net/gojson v1.0.1 h1:MHeSGlq1KxzL7rCkm18fhwW4GNORHohdDMmxY5PupKY= go.dtapp.net/gojson v1.0.1/go.mod h1:TkkpTNxHBKxul0e7gC5MrL1K4ICFB9mQ7wHzjBah3/k= -go.dtapp.net/golog v1.0.24 h1:A26GN2fEJOsMWRb+jqG2LKRmB8aEuWFYNNXGT23VNbc= -go.dtapp.net/golog v1.0.24/go.mod h1:P1CFwGZ6xm2nLXCi0DTwO8aHNfT2dkdjz+9b2ph1TNQ= +go.dtapp.net/golog v1.0.29 h1:tkNZ2KENquglBVaim5ISj0yOeXxwmuPxgQTeUd3I75c= +go.dtapp.net/golog v1.0.29/go.mod h1:W0fqSbKfiTLZjF92TbUp6v0TlqGpKKOIvLy/O3hQXcU= go.dtapp.net/gorandom v1.0.1 h1:IWfMClh1ECPvyUjlqD7MwLq4mZdUusD1qAwAdsvEJBs= go.dtapp.net/gorandom v1.0.1/go.mod h1:ZPdgalKpvFV/ATQqR0k4ns/F/IpITAZpx6WkWirr5Y8= -go.dtapp.net/gorequest v1.0.26 h1:t+rMW7liLHz1RgY60ztWIghSkTeQePKWM0EsDG1IqMI= -go.dtapp.net/gorequest v1.0.26/go.mod h1:sDhiEPwdZnUbyDuq/3OAzA1qvpU5yo49v1fY5sVgj18= +go.dtapp.net/gorequest v1.0.27 h1:Hip1mfSZJDNcmE2iZgB3PYa0C/7BAMEJLsCaMd6t9iE= +go.dtapp.net/gorequest v1.0.27/go.mod h1:922s7pjYulKIytUMGAYS4aHU6cnzTbOQURGBPCKSxAk= go.dtapp.net/gostring v1.0.6 h1:XqNaThEfHpweLofru5sBqm1UUzc9JWsXyB/M/rTk29w= go.dtapp.net/gostring v1.0.6/go.mod h1:AMnnLjyNxH+cphxyASJGYCzWpVrkP5RncuVo8xL8s3E= go.dtapp.net/gotime v1.0.5 h1:12aNgB2ULpP6QgQHEUkLilZ4ASvhpFxMFQkBwn0par8= go.dtapp.net/gotime v1.0.5/go.mod h1:Gq7eNLr2iMLP18UNWONRq4V3Uhf/ADp4bIrS+Tc6ktY= -go.dtapp.net/gotrace_id v1.0.0 h1:nlI8KEEf2l394SCzmJxffEIiOBfR4kIOuobBhpRSV3g= -go.dtapp.net/gotrace_id v1.0.0/go.mod h1:HDwMY1vLoC759z6VGKVgCpIqwKQTDYV9DNdxiyN1OeQ= +go.dtapp.net/gotrace_id v1.0.5 h1:znUwvMcX7ADQn8f750yIb5xJa9tJ4P0fHb5tSo7EFeg= +go.dtapp.net/gotrace_id v1.0.5/go.mod h1:476T5KMJw9c6DM/rJn7y6d28hcNDv4+wew4sd+powes= go.dtapp.net/gourl v1.0.0 h1:Zbe0GiMFyyRy2+bjbVsYulakH5d58w3CDZkUPonlMoQ= go.dtapp.net/gourl v1.0.0/go.mod h1:x9A/pJ3iKDTb6Gu2RtJy2iHg56IowXIcIGQdogqpGjs= go.dtapp.net/goxml v1.0.1 h1:WODsjNpmHTtoeLsXgOjC81qRbu4aXZ3LKBHApNGaPjY= @@ -648,6 +656,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -739,17 +748,18 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/datatypes v1.0.7 h1:8NhJN4+annFjwV1WufDhFiPjdUvV1lSGUdg1UCjQIWY= gorm.io/datatypes v1.0.7/go.mod h1:l9qkCuy0CdzDEop9HKUdcnC9gHC2sRlaFtHkTzsZRqg= gorm.io/driver/mysql v1.3.2/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U= -gorm.io/driver/mysql v1.3.5 h1:iWBTVW/8Ij5AG4e0G/zqzaJblYkBI1VIL1LG2HUGsvY= -gorm.io/driver/mysql v1.3.5/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c= +gorm.io/driver/mysql v1.3.6 h1:BhX1Y/RyALb+T9bZ3t07wLnPZBukt+IRkMn8UZSNbGM= +gorm.io/driver/mysql v1.3.6/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c= gorm.io/driver/postgres v1.3.4/go.mod h1:y0vEuInFKJtijuSGu9e5bs5hzzSzPK+LancpKpvbRBw= -gorm.io/driver/postgres v1.3.8 h1:8bEphSAB69t3odsCR4NDzt581iZEWQuRM27Cg6KgfPY= -gorm.io/driver/postgres v1.3.8/go.mod h1:qB98Aj6AhRO/oyu/jmZsi/YM9g6UzVCjMxO/6frFvcA= +gorm.io/driver/postgres v1.3.9 h1:lWGiVt5CijhQAg0PWB7Od1RNcBw/jS4d2cAScBcSDXg= +gorm.io/driver/postgres v1.3.9/go.mod h1:qw/FeqjxmYqW5dBcYNBsnhQULIApQdk7YuuDPktVi1U= gorm.io/driver/sqlite v1.3.1/go.mod h1:wJx0hJspfycZ6myN38x1O/AqLtNS6c5o9TndewFbELg= gorm.io/driver/sqlite v1.3.6 h1:Fi8xNYCUplOqWiPa3/GuCeowRNBRGTf62DEmhMDHeQQ= gorm.io/driver/sqlserver v1.3.1/go.mod h1:w25Vrx2BG+CJNUu/xKbFhaKlGxT/nzRkhWCCoptX8tQ= gorm.io/driver/sqlserver v1.3.2 h1:yYt8f/xdAKLY7lCCyXxIUEgZ/WsURos3dHrx8MKFGAk= gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE= gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/request.go b/request.go index e806b09..423a653 100644 --- a/request.go +++ b/request.go @@ -13,7 +13,7 @@ func (c *Client) request(ctx context.Context, params map[string]interface{}) (go c.Sign(params) // 创建请求 - client := c.client + client := c.requestClient // 设置格式 client.SetContentTypeForm() @@ -28,11 +28,8 @@ func (c *Client) request(ctx context.Context, params map[string]interface{}) (go } // 日志 - if c.config.PgsqlDb != nil { - go c.log.GormMiddlewareCustom(ctx, gostring.ToString(params["method"]), request, Version) - } - if c.config.MongoDb != nil { - go c.log.MongoMiddlewareCustom(ctx, gostring.ToString(params["method"]), request, Version) + if c.config.GormClient.Db != nil { + go c.logClient.GormMiddlewareCustom(ctx, gostring.ToString(params["method"]), request, Version) } return request, err diff --git a/vendor/github.com/basgys/goxml2json/.gitignore b/vendor/github.com/basgys/goxml2json/.gitignore deleted file mode 100644 index 6bfad54..0000000 --- a/vendor/github.com/basgys/goxml2json/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof -/.tags diff --git a/vendor/github.com/basgys/goxml2json/LICENSE b/vendor/github.com/basgys/goxml2json/LICENSE deleted file mode 100644 index dc5a2e3..0000000 --- a/vendor/github.com/basgys/goxml2json/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Bastien Gysler - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/basgys/goxml2json/README.md b/vendor/github.com/basgys/goxml2json/README.md deleted file mode 100644 index 04e0b7f..0000000 --- a/vendor/github.com/basgys/goxml2json/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# goxml2json [![CircleCI](https://circleci.com/gh/basgys/goxml2json.svg?style=svg)](https://circleci.com/gh/basgys/goxml2json) - -Go package that converts XML to JSON - -### Install - - go get -u github.com/basgys/goxml2json - -### Importing - - import github.com/basgys/goxml2json - -### Usage - -**Code example** - -```go - package main - - import ( - "fmt" - "strings" - - xj "github.com/basgys/goxml2json" - ) - - func main() { - // xml is an io.Reader - xml := strings.NewReader(`world`) - json, err := xj.Convert(xml) - if err != nil { - panic("That's embarrassing...") - } - - fmt.Println(json.String()) - // {"hello": "world"} - } - -``` - -**Input** - -```xml - - - - bar - -``` - -**Output** - -```json - { - "osm": { - "-version": "0.6", - "-generator": "CGImap 0.0.2", - "bounds": { - "-minlat": "54.0889580", - "-minlon": "12.2487570", - "-maxlat": "54.0913900", - "-maxlon": "12.2524800" - }, - "foo": "bar" - } - } -``` - -### Contributing -Feel free to contribute to this project if you want to fix/extend/improve it. - -### Contributors - - - [DirectX](https://github.com/directx) - - [samuelhug](https://github.com/samuelhug) - -### TODO - - * Extract data types in JSON (numbers, boolean, ...) - * Categorise errors - * Option to prettify the JSON output - * Benchmark diff --git a/vendor/github.com/basgys/goxml2json/converter.go b/vendor/github.com/basgys/goxml2json/converter.go deleted file mode 100644 index 3e4cbce..0000000 --- a/vendor/github.com/basgys/goxml2json/converter.go +++ /dev/null @@ -1,25 +0,0 @@ -package xml2json - -import ( - "bytes" - "io" -) - -// Convert converts the given XML document to JSON -func Convert(r io.Reader) (*bytes.Buffer, error) { - // Decode XML document - root := &Node{} - err := NewDecoder(r).Decode(root) - if err != nil { - return nil, err - } - - // Then encode it in JSON - buf := new(bytes.Buffer) - err = NewEncoder(buf).Encode(root) - if err != nil { - return nil, err - } - - return buf, nil -} diff --git a/vendor/github.com/basgys/goxml2json/decoder.go b/vendor/github.com/basgys/goxml2json/decoder.go deleted file mode 100644 index af03356..0000000 --- a/vendor/github.com/basgys/goxml2json/decoder.go +++ /dev/null @@ -1,140 +0,0 @@ -package xml2json - -import ( - "encoding/xml" - "io" - "unicode" - - "golang.org/x/net/html/charset" -) - -const ( - attrPrefix = "-" - contentPrefix = "#" -) - -// A Decoder reads and decodes XML objects from an input stream. -type Decoder struct { - r io.Reader - err error - attributePrefix string - contentPrefix string -} - -type element struct { - parent *element - n *Node - label string -} - -func (dec *Decoder) SetAttributePrefix(prefix string) { - dec.attributePrefix = prefix -} - -func (dec *Decoder) SetContentPrefix(prefix string) { - dec.contentPrefix = prefix -} - -func (dec *Decoder) DecodeWithCustomPrefixes(root *Node, contentPrefix string, attributePrefix string) error { - dec.contentPrefix = contentPrefix - dec.attributePrefix = attributePrefix - return dec.Decode(root) -} - -// NewDecoder returns a new decoder that reads from r. -func NewDecoder(r io.Reader) *Decoder { - return &Decoder{r: r} -} - -// Decode reads the next JSON-encoded value from its -// input and stores it in the value pointed to by v. -func (dec *Decoder) Decode(root *Node) error { - - if dec.contentPrefix == "" { - dec.contentPrefix = contentPrefix - } - if dec.attributePrefix == "" { - dec.attributePrefix = attrPrefix - } - - xmlDec := xml.NewDecoder(dec.r) - - // That will convert the charset if the provided XML is non-UTF-8 - xmlDec.CharsetReader = charset.NewReaderLabel - - // Create first element from the root node - elem := &element{ - parent: nil, - n: root, - } - - for { - t, _ := xmlDec.Token() - if t == nil { - break - } - - switch se := t.(type) { - case xml.StartElement: - // Build new a new current element and link it to its parent - elem = &element{ - parent: elem, - n: &Node{}, - label: se.Name.Local, - } - - // Extract attributes as children - for _, a := range se.Attr { - elem.n.AddChild(dec.attributePrefix+a.Name.Local, &Node{Data: a.Value}) - } - case xml.CharData: - // Extract XML data (if any) - elem.n.Data = trimNonGraphic(string(xml.CharData(se))) - case xml.EndElement: - // And add it to its parent list - if elem.parent != nil { - elem.parent.n.AddChild(elem.label, elem.n) - } - - // Then change the current element to its parent - elem = elem.parent - } - } - - return nil -} - -// trimNonGraphic returns a slice of the string s, with all leading and trailing -// non graphic characters and spaces removed. -// -// Graphic characters include letters, marks, numbers, punctuation, symbols, -// and spaces, from categories L, M, N, P, S, Zs. -// Spacing characters are set by category Z and property Pattern_White_Space. -func trimNonGraphic(s string) string { - if s == "" { - return s - } - - var first *int - var last int - for i, r := range []rune(s) { - if !unicode.IsGraphic(r) || unicode.IsSpace(r) { - continue - } - - if first == nil { - f := i // copy i - first = &f - last = i - } else { - last = i - } - } - - // If first is nil, it means there are no graphic characters - if first == nil { - return "" - } - - return string([]rune(s)[*first : last+1]) -} diff --git a/vendor/github.com/basgys/goxml2json/doc.go b/vendor/github.com/basgys/goxml2json/doc.go deleted file mode 100644 index 8a68bd3..0000000 --- a/vendor/github.com/basgys/goxml2json/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package xml2json is an XML to JSON converter -package xml2json diff --git a/vendor/github.com/basgys/goxml2json/encoder.go b/vendor/github.com/basgys/goxml2json/encoder.go deleted file mode 100644 index 0a542b8..0000000 --- a/vendor/github.com/basgys/goxml2json/encoder.go +++ /dev/null @@ -1,197 +0,0 @@ -package xml2json - -import ( - "bytes" - "io" - "unicode/utf8" -) - -// An Encoder writes JSON objects to an output stream. -type Encoder struct { - w io.Writer - err error - contentPrefix string - attributePrefix string -} - -// NewEncoder returns a new encoder that writes to w. -func NewEncoder(w io.Writer) *Encoder { - return &Encoder{w: w} -} - -func (enc *Encoder) SetAttributePrefix(prefix string) { - enc.attributePrefix = prefix -} - -func (enc *Encoder) SetContentPrefix(prefix string) { - enc.contentPrefix = prefix -} - -func (enc *Encoder) EncodeWithCustomPrefixes(root *Node, contentPrefix string, attributePrefix string) error { - enc.contentPrefix = contentPrefix - enc.attributePrefix = attributePrefix - return enc.Encode(root) -} - -// Encode writes the JSON encoding of v to the stream -func (enc *Encoder) Encode(root *Node) error { - if enc.err != nil { - return enc.err - } - if root == nil { - return nil - } - if enc.contentPrefix == "" { - enc.contentPrefix = contentPrefix - } - if enc.attributePrefix == "" { - enc.attributePrefix = attrPrefix - } - - enc.err = enc.format(root, 0) - - // Terminate each value with a newline. - // This makes the output look a little nicer - // when debugging, and some kind of space - // is required if the encoded value was a number, - // so that the reader knows there aren't more - // digits coming. - enc.write("\n") - - return enc.err -} - -func (enc *Encoder) format(n *Node, lvl int) error { - if n.IsComplex() { - enc.write("{") - - // Add data as an additional attibute (if any) - if len(n.Data) > 0 { - enc.write("\"") - enc.write(enc.contentPrefix) - enc.write("content") - enc.write("\": ") - enc.write(sanitiseString(n.Data)) - enc.write(", ") - } - - i := 0 - tot := len(n.Children) - for label, children := range n.Children { - enc.write("\"") - enc.write(label) - enc.write("\": ") - - if len(children) > 1 { - // Array - enc.write("[") - for j, c := range children { - enc.format(c, lvl+1) - - if j < len(children)-1 { - enc.write(", ") - } - } - enc.write("]") - } else { - // Map - enc.format(children[0], lvl+1) - } - - if i < tot-1 { - enc.write(", ") - } - i++ - } - - enc.write("}") - } else { - // TODO : Extract data type - enc.write(sanitiseString(n.Data)) - } - - return nil -} - -func (enc *Encoder) write(s string) { - enc.w.Write([]byte(s)) -} - -// https://golang.org/src/encoding/json/encode.go?s=5584:5627#L788 -var hex = "0123456789abcdef" - -func sanitiseString(s string) string { - var buf bytes.Buffer - - buf.WriteByte('"') - start := 0 - for i := 0; i < len(s); { - if b := s[i]; b < utf8.RuneSelf { - if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' { - i++ - continue - } - if start < i { - buf.WriteString(s[start:i]) - } - switch b { - case '\\', '"': - buf.WriteByte('\\') - buf.WriteByte(b) - case '\n': - buf.WriteByte('\\') - buf.WriteByte('n') - case '\r': - buf.WriteByte('\\') - buf.WriteByte('r') - case '\t': - buf.WriteByte('\\') - buf.WriteByte('t') - default: - // This encodes bytes < 0x20 except for \n and \r, - // as well as <, > and &. The latter are escaped because they - // can lead to security holes when user-controlled strings - // are rendered into JSON and served to some browsers. - buf.WriteString(`\u00`) - buf.WriteByte(hex[b>>4]) - buf.WriteByte(hex[b&0xF]) - } - i++ - start = i - continue - } - c, size := utf8.DecodeRuneInString(s[i:]) - if c == utf8.RuneError && size == 1 { - if start < i { - buf.WriteString(s[start:i]) - } - buf.WriteString(`\ufffd`) - i += size - start = i - continue - } - // U+2028 is LINE SEPARATOR. - // U+2029 is PARAGRAPH SEPARATOR. - // They are both technically valid characters in JSON strings, - // but don't work in JSONP, which has to be evaluated as JavaScript, - // and can lead to security holes there. It is valid JSON to - // escape them, so we do so unconditionally. - // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. - if c == '\u2028' || c == '\u2029' { - if start < i { - buf.WriteString(s[start:i]) - } - buf.WriteString(`\u202`) - buf.WriteByte(hex[c&0xF]) - i += size - start = i - continue - } - i += size - } - if start < len(s) { - buf.WriteString(s[start:]) - } - buf.WriteByte('"') - return buf.String() -} diff --git a/vendor/github.com/basgys/goxml2json/struct.go b/vendor/github.com/basgys/goxml2json/struct.go deleted file mode 100644 index 1f423b1..0000000 --- a/vendor/github.com/basgys/goxml2json/struct.go +++ /dev/null @@ -1,25 +0,0 @@ -package xml2json - -// Node is a data element on a tree -type Node struct { - Children map[string]Nodes - Data string -} - -// Nodes is a list of nodes -type Nodes []*Node - -// AddChild appends a node to the list of children -func (n *Node) AddChild(s string, c *Node) { - // Lazy lazy - if n.Children == nil { - n.Children = map[string]Nodes{} - } - - n.Children[s] = append(n.Children[s], c) -} - -// IsComplex returns whether it is a complex type (has children) -func (n *Node) IsComplex() bool { - return len(n.Children) > 0 -} diff --git a/vendor/github.com/cespare/xxhash/v2/LICENSE.txt b/vendor/github.com/cespare/xxhash/v2/LICENSE.txt deleted file mode 100644 index 24b5306..0000000 --- a/vendor/github.com/cespare/xxhash/v2/LICENSE.txt +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2016 Caleb Spare - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/cespare/xxhash/v2/README.md b/vendor/github.com/cespare/xxhash/v2/README.md deleted file mode 100644 index 792b4a6..0000000 --- a/vendor/github.com/cespare/xxhash/v2/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# xxhash - -[![Go Reference](https://pkg.go.dev/badge/github.com/cespare/xxhash/v2.svg)](https://pkg.go.dev/github.com/cespare/xxhash/v2) -[![Test](https://github.com/cespare/xxhash/actions/workflows/test.yml/badge.svg)](https://github.com/cespare/xxhash/actions/workflows/test.yml) - -xxhash is a Go implementation of the 64-bit -[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a -high-quality hashing algorithm that is much faster than anything in the Go -standard library. - -This package provides a straightforward API: - -``` -func Sum64(b []byte) uint64 -func Sum64String(s string) uint64 -type Digest struct{ ... } - func New() *Digest -``` - -The `Digest` type implements hash.Hash64. Its key methods are: - -``` -func (*Digest) Write([]byte) (int, error) -func (*Digest) WriteString(string) (int, error) -func (*Digest) Sum64() uint64 -``` - -This implementation provides a fast pure-Go implementation and an even faster -assembly implementation for amd64. - -## Compatibility - -This package is in a module and the latest code is in version 2 of the module. -You need a version of Go with at least "minimal module compatibility" to use -github.com/cespare/xxhash/v2: - -* 1.9.7+ for Go 1.9 -* 1.10.3+ for Go 1.10 -* Go 1.11 or later - -I recommend using the latest release of Go. - -## Benchmarks - -Here are some quick benchmarks comparing the pure-Go and assembly -implementations of Sum64. - -| input size | purego | asm | -| --- | --- | --- | -| 5 B | 979.66 MB/s | 1291.17 MB/s | -| 100 B | 7475.26 MB/s | 7973.40 MB/s | -| 4 KB | 17573.46 MB/s | 17602.65 MB/s | -| 10 MB | 17131.46 MB/s | 17142.16 MB/s | - -These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using -the following commands under Go 1.11.2: - -``` -$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes' -$ go test -benchtime 10s -bench '/xxhash,direct,bytes' -``` - -## Projects using this package - -- [InfluxDB](https://github.com/influxdata/influxdb) -- [Prometheus](https://github.com/prometheus/prometheus) -- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics) -- [FreeCache](https://github.com/coocood/freecache) -- [FastCache](https://github.com/VictoriaMetrics/fastcache) diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash.go b/vendor/github.com/cespare/xxhash/v2/xxhash.go deleted file mode 100644 index 15c835d..0000000 --- a/vendor/github.com/cespare/xxhash/v2/xxhash.go +++ /dev/null @@ -1,235 +0,0 @@ -// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described -// at http://cyan4973.github.io/xxHash/. -package xxhash - -import ( - "encoding/binary" - "errors" - "math/bits" -) - -const ( - prime1 uint64 = 11400714785074694791 - prime2 uint64 = 14029467366897019727 - prime3 uint64 = 1609587929392839161 - prime4 uint64 = 9650029242287828579 - prime5 uint64 = 2870177450012600261 -) - -// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where -// possible in the Go code is worth a small (but measurable) performance boost -// by avoiding some MOVQs. Vars are needed for the asm and also are useful for -// convenience in the Go code in a few places where we need to intentionally -// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the -// result overflows a uint64). -var ( - prime1v = prime1 - prime2v = prime2 - prime3v = prime3 - prime4v = prime4 - prime5v = prime5 -) - -// Digest implements hash.Hash64. -type Digest struct { - v1 uint64 - v2 uint64 - v3 uint64 - v4 uint64 - total uint64 - mem [32]byte - n int // how much of mem is used -} - -// New creates a new Digest that computes the 64-bit xxHash algorithm. -func New() *Digest { - var d Digest - d.Reset() - return &d -} - -// Reset clears the Digest's state so that it can be reused. -func (d *Digest) Reset() { - d.v1 = prime1v + prime2 - d.v2 = prime2 - d.v3 = 0 - d.v4 = -prime1v - d.total = 0 - d.n = 0 -} - -// Size always returns 8 bytes. -func (d *Digest) Size() int { return 8 } - -// BlockSize always returns 32 bytes. -func (d *Digest) BlockSize() int { return 32 } - -// Write adds more data to d. It always returns len(b), nil. -func (d *Digest) Write(b []byte) (n int, err error) { - n = len(b) - d.total += uint64(n) - - if d.n+n < 32 { - // This new data doesn't even fill the current block. - copy(d.mem[d.n:], b) - d.n += n - return - } - - if d.n > 0 { - // Finish off the partial block. - copy(d.mem[d.n:], b) - d.v1 = round(d.v1, u64(d.mem[0:8])) - d.v2 = round(d.v2, u64(d.mem[8:16])) - d.v3 = round(d.v3, u64(d.mem[16:24])) - d.v4 = round(d.v4, u64(d.mem[24:32])) - b = b[32-d.n:] - d.n = 0 - } - - if len(b) >= 32 { - // One or more full blocks left. - nw := writeBlocks(d, b) - b = b[nw:] - } - - // Store any remaining partial block. - copy(d.mem[:], b) - d.n = len(b) - - return -} - -// Sum appends the current hash to b and returns the resulting slice. -func (d *Digest) Sum(b []byte) []byte { - s := d.Sum64() - return append( - b, - byte(s>>56), - byte(s>>48), - byte(s>>40), - byte(s>>32), - byte(s>>24), - byte(s>>16), - byte(s>>8), - byte(s), - ) -} - -// Sum64 returns the current hash. -func (d *Digest) Sum64() uint64 { - var h uint64 - - if d.total >= 32 { - v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4 - h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4) - h = mergeRound(h, v1) - h = mergeRound(h, v2) - h = mergeRound(h, v3) - h = mergeRound(h, v4) - } else { - h = d.v3 + prime5 - } - - h += d.total - - i, end := 0, d.n - for ; i+8 <= end; i += 8 { - k1 := round(0, u64(d.mem[i:i+8])) - h ^= k1 - h = rol27(h)*prime1 + prime4 - } - if i+4 <= end { - h ^= uint64(u32(d.mem[i:i+4])) * prime1 - h = rol23(h)*prime2 + prime3 - i += 4 - } - for i < end { - h ^= uint64(d.mem[i]) * prime5 - h = rol11(h) * prime1 - i++ - } - - h ^= h >> 33 - h *= prime2 - h ^= h >> 29 - h *= prime3 - h ^= h >> 32 - - return h -} - -const ( - magic = "xxh\x06" - marshaledSize = len(magic) + 8*5 + 32 -) - -// MarshalBinary implements the encoding.BinaryMarshaler interface. -func (d *Digest) MarshalBinary() ([]byte, error) { - b := make([]byte, 0, marshaledSize) - b = append(b, magic...) - b = appendUint64(b, d.v1) - b = appendUint64(b, d.v2) - b = appendUint64(b, d.v3) - b = appendUint64(b, d.v4) - b = appendUint64(b, d.total) - b = append(b, d.mem[:d.n]...) - b = b[:len(b)+len(d.mem)-d.n] - return b, nil -} - -// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. -func (d *Digest) UnmarshalBinary(b []byte) error { - if len(b) < len(magic) || string(b[:len(magic)]) != magic { - return errors.New("xxhash: invalid hash state identifier") - } - if len(b) != marshaledSize { - return errors.New("xxhash: invalid hash state size") - } - b = b[len(magic):] - b, d.v1 = consumeUint64(b) - b, d.v2 = consumeUint64(b) - b, d.v3 = consumeUint64(b) - b, d.v4 = consumeUint64(b) - b, d.total = consumeUint64(b) - copy(d.mem[:], b) - d.n = int(d.total % uint64(len(d.mem))) - return nil -} - -func appendUint64(b []byte, x uint64) []byte { - var a [8]byte - binary.LittleEndian.PutUint64(a[:], x) - return append(b, a[:]...) -} - -func consumeUint64(b []byte) ([]byte, uint64) { - x := u64(b) - return b[8:], x -} - -func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) } -func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) } - -func round(acc, input uint64) uint64 { - acc += input * prime2 - acc = rol31(acc) - acc *= prime1 - return acc -} - -func mergeRound(acc, val uint64) uint64 { - val = round(0, val) - acc ^= val - acc = acc*prime1 + prime4 - return acc -} - -func rol1(x uint64) uint64 { return bits.RotateLeft64(x, 1) } -func rol7(x uint64) uint64 { return bits.RotateLeft64(x, 7) } -func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) } -func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) } -func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) } -func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) } -func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) } -func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) } diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go b/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go deleted file mode 100644 index ad14b80..0000000 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build !appengine -// +build gc -// +build !purego - -package xxhash - -// Sum64 computes the 64-bit xxHash digest of b. -// -//go:noescape -func Sum64(b []byte) uint64 - -//go:noescape -func writeBlocks(d *Digest, b []byte) int diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s b/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s deleted file mode 100644 index be8db5b..0000000 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s +++ /dev/null @@ -1,215 +0,0 @@ -// +build !appengine -// +build gc -// +build !purego - -#include "textflag.h" - -// Register allocation: -// AX h -// SI pointer to advance through b -// DX n -// BX loop end -// R8 v1, k1 -// R9 v2 -// R10 v3 -// R11 v4 -// R12 tmp -// R13 prime1v -// R14 prime2v -// DI prime4v - -// round reads from and advances the buffer pointer in SI. -// It assumes that R13 has prime1v and R14 has prime2v. -#define round(r) \ - MOVQ (SI), R12 \ - ADDQ $8, SI \ - IMULQ R14, R12 \ - ADDQ R12, r \ - ROLQ $31, r \ - IMULQ R13, r - -// mergeRound applies a merge round on the two registers acc and val. -// It assumes that R13 has prime1v, R14 has prime2v, and DI has prime4v. -#define mergeRound(acc, val) \ - IMULQ R14, val \ - ROLQ $31, val \ - IMULQ R13, val \ - XORQ val, acc \ - IMULQ R13, acc \ - ADDQ DI, acc - -// func Sum64(b []byte) uint64 -TEXT ·Sum64(SB), NOSPLIT, $0-32 - // Load fixed primes. - MOVQ ·prime1v(SB), R13 - MOVQ ·prime2v(SB), R14 - MOVQ ·prime4v(SB), DI - - // Load slice. - MOVQ b_base+0(FP), SI - MOVQ b_len+8(FP), DX - LEAQ (SI)(DX*1), BX - - // The first loop limit will be len(b)-32. - SUBQ $32, BX - - // Check whether we have at least one block. - CMPQ DX, $32 - JLT noBlocks - - // Set up initial state (v1, v2, v3, v4). - MOVQ R13, R8 - ADDQ R14, R8 - MOVQ R14, R9 - XORQ R10, R10 - XORQ R11, R11 - SUBQ R13, R11 - - // Loop until SI > BX. -blockLoop: - round(R8) - round(R9) - round(R10) - round(R11) - - CMPQ SI, BX - JLE blockLoop - - MOVQ R8, AX - ROLQ $1, AX - MOVQ R9, R12 - ROLQ $7, R12 - ADDQ R12, AX - MOVQ R10, R12 - ROLQ $12, R12 - ADDQ R12, AX - MOVQ R11, R12 - ROLQ $18, R12 - ADDQ R12, AX - - mergeRound(AX, R8) - mergeRound(AX, R9) - mergeRound(AX, R10) - mergeRound(AX, R11) - - JMP afterBlocks - -noBlocks: - MOVQ ·prime5v(SB), AX - -afterBlocks: - ADDQ DX, AX - - // Right now BX has len(b)-32, and we want to loop until SI > len(b)-8. - ADDQ $24, BX - - CMPQ SI, BX - JG fourByte - -wordLoop: - // Calculate k1. - MOVQ (SI), R8 - ADDQ $8, SI - IMULQ R14, R8 - ROLQ $31, R8 - IMULQ R13, R8 - - XORQ R8, AX - ROLQ $27, AX - IMULQ R13, AX - ADDQ DI, AX - - CMPQ SI, BX - JLE wordLoop - -fourByte: - ADDQ $4, BX - CMPQ SI, BX - JG singles - - MOVL (SI), R8 - ADDQ $4, SI - IMULQ R13, R8 - XORQ R8, AX - - ROLQ $23, AX - IMULQ R14, AX - ADDQ ·prime3v(SB), AX - -singles: - ADDQ $4, BX - CMPQ SI, BX - JGE finalize - -singlesLoop: - MOVBQZX (SI), R12 - ADDQ $1, SI - IMULQ ·prime5v(SB), R12 - XORQ R12, AX - - ROLQ $11, AX - IMULQ R13, AX - - CMPQ SI, BX - JL singlesLoop - -finalize: - MOVQ AX, R12 - SHRQ $33, R12 - XORQ R12, AX - IMULQ R14, AX - MOVQ AX, R12 - SHRQ $29, R12 - XORQ R12, AX - IMULQ ·prime3v(SB), AX - MOVQ AX, R12 - SHRQ $32, R12 - XORQ R12, AX - - MOVQ AX, ret+24(FP) - RET - -// writeBlocks uses the same registers as above except that it uses AX to store -// the d pointer. - -// func writeBlocks(d *Digest, b []byte) int -TEXT ·writeBlocks(SB), NOSPLIT, $0-40 - // Load fixed primes needed for round. - MOVQ ·prime1v(SB), R13 - MOVQ ·prime2v(SB), R14 - - // Load slice. - MOVQ b_base+8(FP), SI - MOVQ b_len+16(FP), DX - LEAQ (SI)(DX*1), BX - SUBQ $32, BX - - // Load vN from d. - MOVQ d+0(FP), AX - MOVQ 0(AX), R8 // v1 - MOVQ 8(AX), R9 // v2 - MOVQ 16(AX), R10 // v3 - MOVQ 24(AX), R11 // v4 - - // We don't need to check the loop condition here; this function is - // always called with at least one block of data to process. -blockLoop: - round(R8) - round(R9) - round(R10) - round(R11) - - CMPQ SI, BX - JLE blockLoop - - // Copy vN back to d. - MOVQ R8, 0(AX) - MOVQ R9, 8(AX) - MOVQ R10, 16(AX) - MOVQ R11, 24(AX) - - // The number of bytes written is SI minus the old base pointer. - SUBQ b_base+8(FP), SI - MOVQ SI, ret+32(FP) - - RET diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_other.go b/vendor/github.com/cespare/xxhash/v2/xxhash_other.go deleted file mode 100644 index 4a5a821..0000000 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_other.go +++ /dev/null @@ -1,76 +0,0 @@ -// +build !amd64 appengine !gc purego - -package xxhash - -// Sum64 computes the 64-bit xxHash digest of b. -func Sum64(b []byte) uint64 { - // A simpler version would be - // d := New() - // d.Write(b) - // return d.Sum64() - // but this is faster, particularly for small inputs. - - n := len(b) - var h uint64 - - if n >= 32 { - v1 := prime1v + prime2 - v2 := prime2 - v3 := uint64(0) - v4 := -prime1v - for len(b) >= 32 { - v1 = round(v1, u64(b[0:8:len(b)])) - v2 = round(v2, u64(b[8:16:len(b)])) - v3 = round(v3, u64(b[16:24:len(b)])) - v4 = round(v4, u64(b[24:32:len(b)])) - b = b[32:len(b):len(b)] - } - h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4) - h = mergeRound(h, v1) - h = mergeRound(h, v2) - h = mergeRound(h, v3) - h = mergeRound(h, v4) - } else { - h = prime5 - } - - h += uint64(n) - - i, end := 0, len(b) - for ; i+8 <= end; i += 8 { - k1 := round(0, u64(b[i:i+8:len(b)])) - h ^= k1 - h = rol27(h)*prime1 + prime4 - } - if i+4 <= end { - h ^= uint64(u32(b[i:i+4:len(b)])) * prime1 - h = rol23(h)*prime2 + prime3 - i += 4 - } - for ; i < end; i++ { - h ^= uint64(b[i]) * prime5 - h = rol11(h) * prime1 - } - - h ^= h >> 33 - h *= prime2 - h ^= h >> 29 - h *= prime3 - h ^= h >> 32 - - return h -} - -func writeBlocks(d *Digest, b []byte) int { - v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4 - n := len(b) - for len(b) >= 32 { - v1 = round(v1, u64(b[0:8:len(b)])) - v2 = round(v2, u64(b[8:16:len(b)])) - v3 = round(v3, u64(b[16:24:len(b)])) - v4 = round(v4, u64(b[24:32:len(b)])) - b = b[32:len(b):len(b)] - } - d.v1, d.v2, d.v3, d.v4 = v1, v2, v3, v4 - return n - len(b) -} diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go b/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go deleted file mode 100644 index fc9bea7..0000000 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go +++ /dev/null @@ -1,15 +0,0 @@ -// +build appengine - -// This file contains the safe implementations of otherwise unsafe-using code. - -package xxhash - -// Sum64String computes the 64-bit xxHash digest of s. -func Sum64String(s string) uint64 { - return Sum64([]byte(s)) -} - -// WriteString adds more data to d. It always returns len(s), nil. -func (d *Digest) WriteString(s string) (n int, err error) { - return d.Write([]byte(s)) -} diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go b/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go deleted file mode 100644 index 376e0ca..0000000 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go +++ /dev/null @@ -1,57 +0,0 @@ -// +build !appengine - -// This file encapsulates usage of unsafe. -// xxhash_safe.go contains the safe implementations. - -package xxhash - -import ( - "unsafe" -) - -// In the future it's possible that compiler optimizations will make these -// XxxString functions unnecessary by realizing that calls such as -// Sum64([]byte(s)) don't need to copy s. See https://golang.org/issue/2205. -// If that happens, even if we keep these functions they can be replaced with -// the trivial safe code. - -// NOTE: The usual way of doing an unsafe string-to-[]byte conversion is: -// -// var b []byte -// bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) -// bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data -// bh.Len = len(s) -// bh.Cap = len(s) -// -// Unfortunately, as of Go 1.15.3 the inliner's cost model assigns a high enough -// weight to this sequence of expressions that any function that uses it will -// not be inlined. Instead, the functions below use a different unsafe -// conversion designed to minimize the inliner weight and allow both to be -// inlined. There is also a test (TestInlining) which verifies that these are -// inlined. -// -// See https://github.com/golang/go/issues/42739 for discussion. - -// Sum64String computes the 64-bit xxHash digest of s. -// It may be faster than Sum64([]byte(s)) by avoiding a copy. -func Sum64String(s string) uint64 { - b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})) - return Sum64(b) -} - -// WriteString adds more data to d. It always returns len(s), nil. -// It may be faster than Write([]byte(s)) by avoiding a copy. -func (d *Digest) WriteString(s string) (n int, err error) { - d.Write(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))) - // d.Write always returns len(s), nil. - // Ignoring the return output and returning these fixed values buys a - // savings of 6 in the inliner's cost model. - return len(s), nil -} - -// sliceHeader is similar to reflect.SliceHeader, but it assumes that the layout -// of the first two words is the same as the layout of a string. -type sliceHeader struct { - s string - cap int -} diff --git a/vendor/github.com/dgryski/go-rendezvous/LICENSE b/vendor/github.com/dgryski/go-rendezvous/LICENSE deleted file mode 100644 index 22080f7..0000000 --- a/vendor/github.com/dgryski/go-rendezvous/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017-2020 Damian Gryski - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/dgryski/go-rendezvous/rdv.go b/vendor/github.com/dgryski/go-rendezvous/rdv.go deleted file mode 100644 index 7a6f820..0000000 --- a/vendor/github.com/dgryski/go-rendezvous/rdv.go +++ /dev/null @@ -1,79 +0,0 @@ -package rendezvous - -type Rendezvous struct { - nodes map[string]int - nstr []string - nhash []uint64 - hash Hasher -} - -type Hasher func(s string) uint64 - -func New(nodes []string, hash Hasher) *Rendezvous { - r := &Rendezvous{ - nodes: make(map[string]int, len(nodes)), - nstr: make([]string, len(nodes)), - nhash: make([]uint64, len(nodes)), - hash: hash, - } - - for i, n := range nodes { - r.nodes[n] = i - r.nstr[i] = n - r.nhash[i] = hash(n) - } - - return r -} - -func (r *Rendezvous) Lookup(k string) string { - // short-circuit if we're empty - if len(r.nodes) == 0 { - return "" - } - - khash := r.hash(k) - - var midx int - var mhash = xorshiftMult64(khash ^ r.nhash[0]) - - for i, nhash := range r.nhash[1:] { - if h := xorshiftMult64(khash ^ nhash); h > mhash { - midx = i + 1 - mhash = h - } - } - - return r.nstr[midx] -} - -func (r *Rendezvous) Add(node string) { - r.nodes[node] = len(r.nstr) - r.nstr = append(r.nstr, node) - r.nhash = append(r.nhash, r.hash(node)) -} - -func (r *Rendezvous) Remove(node string) { - // find index of node to remove - nidx := r.nodes[node] - - // remove from the slices - l := len(r.nstr) - r.nstr[nidx] = r.nstr[l] - r.nstr = r.nstr[:l] - - r.nhash[nidx] = r.nhash[l] - r.nhash = r.nhash[:l] - - // update the map - delete(r.nodes, node) - moved := r.nstr[nidx] - r.nodes[moved] = nidx -} - -func xorshiftMult64(x uint64) uint64 { - x ^= x >> 12 // a - x ^= x << 25 // b - x ^= x >> 27 // c - return x * 2685821657736338717 -} diff --git a/vendor/github.com/gin-contrib/sse/.travis.yml b/vendor/github.com/gin-contrib/sse/.travis.yml deleted file mode 100644 index d0e8fcf..0000000 --- a/vendor/github.com/gin-contrib/sse/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: go -sudo: false -go: - - 1.8.x - - 1.9.x - - 1.10.x - - 1.11.x - - 1.12.x - - master - -git: - depth: 10 - -matrix: - fast_finish: true - include: - - go: 1.11.x - env: GO111MODULE=on - - go: 1.12.x - env: GO111MODULE=on - -script: - - go test -v -covermode=count -coverprofile=coverage.out - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/gin-contrib/sse/LICENSE b/vendor/github.com/gin-contrib/sse/LICENSE deleted file mode 100644 index 1ff7f37..0000000 --- a/vendor/github.com/gin-contrib/sse/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Manuel Martínez-Almeida - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/gin-contrib/sse/README.md b/vendor/github.com/gin-contrib/sse/README.md deleted file mode 100644 index c9c49cf..0000000 --- a/vendor/github.com/gin-contrib/sse/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# Server-Sent Events - -[![GoDoc](https://godoc.org/github.com/gin-contrib/sse?status.svg)](https://godoc.org/github.com/gin-contrib/sse) -[![Build Status](https://travis-ci.org/gin-contrib/sse.svg)](https://travis-ci.org/gin-contrib/sse) -[![codecov](https://codecov.io/gh/gin-contrib/sse/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-contrib/sse) -[![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/sse)](https://goreportcard.com/report/github.com/gin-contrib/sse) - -Server-sent events (SSE) is a technology where a browser receives automatic updates from a server via HTTP connection. The Server-Sent Events EventSource API is [standardized as part of HTML5[1] by the W3C](http://www.w3.org/TR/2009/WD-eventsource-20091029/). - -- [Read this great SSE introduction by the HTML5Rocks guys](http://www.html5rocks.com/en/tutorials/eventsource/basics/) -- [Browser support](http://caniuse.com/#feat=eventsource) - -## Sample code - -```go -import "github.com/gin-contrib/sse" - -func httpHandler(w http.ResponseWriter, req *http.Request) { - // data can be a primitive like a string, an integer or a float - sse.Encode(w, sse.Event{ - Event: "message", - Data: "some data\nmore data", - }) - - // also a complex type, like a map, a struct or a slice - sse.Encode(w, sse.Event{ - Id: "124", - Event: "message", - Data: map[string]interface{}{ - "user": "manu", - "date": time.Now().Unix(), - "content": "hi!", - }, - }) -} -``` -``` -event: message -data: some data\\nmore data - -id: 124 -event: message -data: {"content":"hi!","date":1431540810,"user":"manu"} - -``` - -## Content-Type - -```go -fmt.Println(sse.ContentType) -``` -``` -text/event-stream -``` - -## Decoding support - -There is a client-side implementation of SSE coming soon. diff --git a/vendor/github.com/gin-contrib/sse/sse-decoder.go b/vendor/github.com/gin-contrib/sse/sse-decoder.go deleted file mode 100644 index fd49b9c..0000000 --- a/vendor/github.com/gin-contrib/sse/sse-decoder.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package sse - -import ( - "bytes" - "io" - "io/ioutil" -) - -type decoder struct { - events []Event -} - -func Decode(r io.Reader) ([]Event, error) { - var dec decoder - return dec.decode(r) -} - -func (d *decoder) dispatchEvent(event Event, data string) { - dataLength := len(data) - if dataLength > 0 { - //If the data buffer's last character is a U+000A LINE FEED (LF) character, then remove the last character from the data buffer. - data = data[:dataLength-1] - dataLength-- - } - if dataLength == 0 && event.Event == "" { - return - } - if event.Event == "" { - event.Event = "message" - } - event.Data = data - d.events = append(d.events, event) -} - -func (d *decoder) decode(r io.Reader) ([]Event, error) { - buf, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - var currentEvent Event - var dataBuffer *bytes.Buffer = new(bytes.Buffer) - // TODO (and unit tests) - // Lines must be separated by either a U+000D CARRIAGE RETURN U+000A LINE FEED (CRLF) character pair, - // a single U+000A LINE FEED (LF) character, - // or a single U+000D CARRIAGE RETURN (CR) character. - lines := bytes.Split(buf, []byte{'\n'}) - for _, line := range lines { - if len(line) == 0 { - // If the line is empty (a blank line). Dispatch the event. - d.dispatchEvent(currentEvent, dataBuffer.String()) - - // reset current event and data buffer - currentEvent = Event{} - dataBuffer.Reset() - continue - } - if line[0] == byte(':') { - // If the line starts with a U+003A COLON character (:), ignore the line. - continue - } - - var field, value []byte - colonIndex := bytes.IndexRune(line, ':') - if colonIndex != -1 { - // If the line contains a U+003A COLON character character (:) - // Collect the characters on the line before the first U+003A COLON character (:), - // and let field be that string. - field = line[:colonIndex] - // Collect the characters on the line after the first U+003A COLON character (:), - // and let value be that string. - value = line[colonIndex+1:] - // If value starts with a single U+0020 SPACE character, remove it from value. - if len(value) > 0 && value[0] == ' ' { - value = value[1:] - } - } else { - // Otherwise, the string is not empty but does not contain a U+003A COLON character character (:) - // Use the whole line as the field name, and the empty string as the field value. - field = line - value = []byte{} - } - // The steps to process the field given a field name and a field value depend on the field name, - // as given in the following list. Field names must be compared literally, - // with no case folding performed. - switch string(field) { - case "event": - // Set the event name buffer to field value. - currentEvent.Event = string(value) - case "id": - // Set the event stream's last event ID to the field value. - currentEvent.Id = string(value) - case "retry": - // If the field value consists of only characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), - // then interpret the field value as an integer in base ten, and set the event stream's reconnection time to that integer. - // Otherwise, ignore the field. - currentEvent.Id = string(value) - case "data": - // Append the field value to the data buffer, - dataBuffer.Write(value) - // then append a single U+000A LINE FEED (LF) character to the data buffer. - dataBuffer.WriteString("\n") - default: - //Otherwise. The field is ignored. - continue - } - } - // Once the end of the file is reached, the user agent must dispatch the event one final time. - d.dispatchEvent(currentEvent, dataBuffer.String()) - - return d.events, nil -} diff --git a/vendor/github.com/gin-contrib/sse/sse-encoder.go b/vendor/github.com/gin-contrib/sse/sse-encoder.go deleted file mode 100644 index f9c8087..0000000 --- a/vendor/github.com/gin-contrib/sse/sse-encoder.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package sse - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "reflect" - "strconv" - "strings" -) - -// Server-Sent Events -// W3C Working Draft 29 October 2009 -// http://www.w3.org/TR/2009/WD-eventsource-20091029/ - -const ContentType = "text/event-stream" - -var contentType = []string{ContentType} -var noCache = []string{"no-cache"} - -var fieldReplacer = strings.NewReplacer( - "\n", "\\n", - "\r", "\\r") - -var dataReplacer = strings.NewReplacer( - "\n", "\ndata:", - "\r", "\\r") - -type Event struct { - Event string - Id string - Retry uint - Data interface{} -} - -func Encode(writer io.Writer, event Event) error { - w := checkWriter(writer) - writeId(w, event.Id) - writeEvent(w, event.Event) - writeRetry(w, event.Retry) - return writeData(w, event.Data) -} - -func writeId(w stringWriter, id string) { - if len(id) > 0 { - w.WriteString("id:") - fieldReplacer.WriteString(w, id) - w.WriteString("\n") - } -} - -func writeEvent(w stringWriter, event string) { - if len(event) > 0 { - w.WriteString("event:") - fieldReplacer.WriteString(w, event) - w.WriteString("\n") - } -} - -func writeRetry(w stringWriter, retry uint) { - if retry > 0 { - w.WriteString("retry:") - w.WriteString(strconv.FormatUint(uint64(retry), 10)) - w.WriteString("\n") - } -} - -func writeData(w stringWriter, data interface{}) error { - w.WriteString("data:") - switch kindOfData(data) { - case reflect.Struct, reflect.Slice, reflect.Map: - err := json.NewEncoder(w).Encode(data) - if err != nil { - return err - } - w.WriteString("\n") - default: - dataReplacer.WriteString(w, fmt.Sprint(data)) - w.WriteString("\n\n") - } - return nil -} - -func (r Event) Render(w http.ResponseWriter) error { - r.WriteContentType(w) - return Encode(w, r) -} - -func (r Event) WriteContentType(w http.ResponseWriter) { - header := w.Header() - header["Content-Type"] = contentType - - if _, exist := header["Cache-Control"]; !exist { - header["Cache-Control"] = noCache - } -} - -func kindOfData(data interface{}) reflect.Kind { - value := reflect.ValueOf(data) - valueType := value.Kind() - if valueType == reflect.Ptr { - valueType = value.Elem().Kind() - } - return valueType -} diff --git a/vendor/github.com/gin-contrib/sse/writer.go b/vendor/github.com/gin-contrib/sse/writer.go deleted file mode 100644 index 6f9806c..0000000 --- a/vendor/github.com/gin-contrib/sse/writer.go +++ /dev/null @@ -1,24 +0,0 @@ -package sse - -import "io" - -type stringWriter interface { - io.Writer - WriteString(string) (int, error) -} - -type stringWrapper struct { - io.Writer -} - -func (w stringWrapper) WriteString(str string) (int, error) { - return w.Writer.Write([]byte(str)) -} - -func checkWriter(writer io.Writer) stringWriter { - if w, ok := writer.(stringWriter); ok { - return w - } else { - return stringWrapper{writer} - } -} diff --git a/vendor/github.com/gin-gonic/gin/.gitignore b/vendor/github.com/gin-gonic/gin/.gitignore deleted file mode 100644 index bdd50c9..0000000 --- a/vendor/github.com/gin-gonic/gin/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -vendor/* -!vendor/vendor.json -coverage.out -count.out -test -profile.out -tmp.out diff --git a/vendor/github.com/gin-gonic/gin/.golangci.yml b/vendor/github.com/gin-gonic/gin/.golangci.yml deleted file mode 100644 index c5e1de3..0000000 --- a/vendor/github.com/gin-gonic/gin/.golangci.yml +++ /dev/null @@ -1,39 +0,0 @@ -run: - timeout: 5m -linters: - enable: - - asciicheck - - depguard - - dogsled - - durationcheck - - errcheck - - errorlint - - exportloopref - - gci - - gofmt - - goimports - - gosec - - misspell - - nakedret - - nilerr - - nolintlint - - revive - - wastedassign -issues: - exclude-rules: - - linters: - - structcheck - - unused - text: "`data` is unused" - - linters: - - staticcheck - text: "SA1019:" - - linters: - - revive - text: "var-naming:" - - linters: - - revive - text: "exported:" - - path: _test\.go - linters: - - gosec # security is not make sense in tests diff --git a/vendor/github.com/gin-gonic/gin/.goreleaser.yaml b/vendor/github.com/gin-gonic/gin/.goreleaser.yaml deleted file mode 100644 index e435e56..0000000 --- a/vendor/github.com/gin-gonic/gin/.goreleaser.yaml +++ /dev/null @@ -1,57 +0,0 @@ -project_name: gin - -builds: - - - # If true, skip the build. - # Useful for library projects. - # Default is false - skip: true - -changelog: - # Set it to true if you wish to skip the changelog generation. - # This may result in an empty release notes on GitHub/GitLab/Gitea. - skip: false - - # Changelog generation implementation to use. - # - # Valid options are: - # - `git`: uses `git log`; - # - `github`: uses the compare GitHub API, appending the author login to the changelog. - # - `gitlab`: uses the compare GitLab API, appending the author name and email to the changelog. - # - `github-native`: uses the GitHub release notes generation API, disables the groups feature. - # - # Defaults to `git`. - use: git - - # Sorts the changelog by the commit's messages. - # Could either be asc, desc or empty - # Default is empty - sort: asc - - # Group commits messages by given regex and title. - # Order value defines the order of the groups. - # Proving no regex means all commits will be grouped under the default group. - # Groups are disabled when using github-native, as it already groups things by itself. - # - # Default is no groups. - groups: - - title: Features - regexp: "^.*feat[(\\w)]*:+.*$" - order: 0 - - title: 'Bug fixes' - regexp: "^.*fix[(\\w)]*:+.*$" - order: 1 - - title: 'Enhancements' - regexp: "^.*chore[(\\w)]*:+.*$" - order: 2 - - title: Others - order: 999 - - filters: - # Commit messages matching the regexp listed here will be removed from - # the changelog - # Default is empty - exclude: - - '^docs' - - 'CICD' - - typo diff --git a/vendor/github.com/gin-gonic/gin/AUTHORS.md b/vendor/github.com/gin-gonic/gin/AUTHORS.md deleted file mode 100644 index b4773ef..0000000 --- a/vendor/github.com/gin-gonic/gin/AUTHORS.md +++ /dev/null @@ -1,406 +0,0 @@ -List of all the awesome people working to make Gin the best Web Framework in Go. - -## gin 1.x series authors - -**Gin Core Team:** Bo-Yi Wu (@appleboy), thinkerou (@thinkerou), Javier Provecho (@javierprovecho) - -## gin 0.x series authors - -**Maintainers:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho) - ------- - -People and companies, who have contributed, in alphabetical order. - -- 178inaba <178inaba@users.noreply.github.com> -- A. F -- ABHISHEK SONI -- Abhishek Chanda -- Abner Chen -- AcoNCodes -- Adam Dratwinski -- Adam Mckaig -- Adam Zielinski -- Adonis -- Alan Wang -- Albin Gilles -- Aleksandr Didenko -- Alessandro (Ale) Segala <43508+ItalyPaleAle@users.noreply.github.com> -- Alex -- Alexander -- Alexander Lokhman -- Alexander Melentyev <55826637+alexander-melentyev@users.noreply.github.com> -- Alexander Nyquist -- Allen Ren -- AllinGo -- Ammar Bandukwala -- An Xiao (Luffy) -- Andre Dublin <81dublin@gmail.com> -- Andrew Szeto -- Andrey Abramov -- Andrey Nering -- Andrey Smirnov -- Andrii Bubis -- André Bazaglia -- Andy Pan -- Antoine GIRARD -- Anup Kumar Panwar <1anuppanwar@gmail.com> -- Aravinth Sundaram -- Artem -- Ashwani -- Aurelien Regat-Barrel -- Austin Heap -- Barnabus -- Bo-Yi Wu -- Boris Borshevsky -- Boyi Wu -- BradyBromley <51128276+BradyBromley@users.noreply.github.com> -- Brendan Fosberry -- Brian Wigginton -- Carlos Eduardo -- Chad Russell -- Charles -- Christian Muehlhaeuser -- Christian Persson -- Christopher Harrington -- Damon Zhao -- Dan Markham -- Dang Nguyen -- Daniel Krom -- Daniel M. Lambea -- Danieliu -- David Irvine -- David Zhang -- Davor Kapsa -- DeathKing -- Dennis Cho <47404603+forest747@users.noreply.github.com> -- Dmitry Dorogin -- Dmitry Kutakov -- Dmitry Sedykh -- Don2Quixote <35610661+Don2Quixote@users.noreply.github.com> -- Donn Pebe -- Dustin Decker -- Eason Lin -- Edward Betts -- Egor Seredin <4819888+agmt@users.noreply.github.com> -- Emmanuel Goh -- Equim -- Eren A. Akyol -- Eric_Lee -- Erik Bender -- Ethan Kan -- Evgeny Persienko -- Faisal Alam -- Fareed Dudhia -- Filip Figiel -- Florian Polster -- Frank Bille -- Franz Bettag -- Ganlv -- Gaozhen Ying -- George Gabolaev -- George Kirilenko -- Georges Varouchas -- Gordon Tyler -- Harindu Perera -- Helios <674876158@qq.com> -- Henry Kwan -- Henry Yee -- Himanshu Mishra -- Hiroyuki Tanaka -- Ibraheem Ahmed -- Ignacio Galindo -- Igor H. Vieira -- Ildar1111 <54001462+Ildar1111@users.noreply.github.com> -- Iskander (Alex) Sharipov -- Ismail Gjevori -- Ivan Chen -- JINNOUCHI Yasushi -- James Pettyjohn -- Jamie Stackhouse -- Jason Lee -- Javier Provecho -- Javier Provecho -- Javier Provecho -- Javier Provecho Fernandez -- Javier Provecho Fernandez -- Jean-Christophe Lebreton -- Jeff -- Jeremy Loy -- Jim Filippou -- Jimmy Pettersson -- John Bampton -- Johnny Dallas -- Johnny Dallas -- Jonathan (JC) Chen -- Josep Jesus Bigorra Algaba <42377845+averageflow@users.noreply.github.com> -- Josh Horowitz -- Joshua Loper -- Julien Schmidt -- Jun Kimura -- Justin Beckwith -- Justin Israel -- Justin Mayhew -- Jérôme Laforge -- Kacper Bąk <56700396+53jk1@users.noreply.github.com> -- Kamron Batman -- Kane Rogers -- Kaushik Neelichetty -- Keiji Yoshida -- Kel Cecil -- Kevin Mulvey -- Kevin Zhu -- Kirill Motkov -- Klemen Sever -- Kristoffer A. Iversen -- Krzysztof Szafrański -- Kumar McMillan -- Kyle Mcgill -- Lanco <35420416+lancoLiu@users.noreply.github.com> -- Levi Olson -- Lin Kao-Yuan -- Linus Unnebäck -- Lucas Clemente -- Ludwig Valda Vasquez -- Luis GG -- MW Lim -- Maksimov Sergey -- Manjusaka -- Manu MA -- Manu MA -- Manu Mtz-Almeida -- Manu Mtz.-Almeida -- Manuel Alonso -- Mara Kim -- Mario Kostelac -- Martin Karlsch -- Matt Newberry -- Matt Williams -- Matthieu MOREL -- Max Hilbrunner -- Maxime Soulé -- MetalBreaker -- Michael Puncel -- MichaelDeSteven <51652084+MichaelDeSteven@users.noreply.github.com> -- Mike <38686456+icy4ever@users.noreply.github.com> -- Mike Stipicevic -- Miki Tebeka -- Miles -- Mirza Ceric -- Mykyta Semenistyi -- Naoki Takano -- Ngalim Siregar -- Ni Hao -- Nick Gerakines -- Nikifor Seryakov -- Notealot <714804968@qq.com> -- Olivier Mengué -- Olivier Robardet -- Pablo Moncada -- Pablo Moncada -- Panmax <967168@qq.com> -- Peperoncino <2wua4nlyi@gmail.com> -- Philipp Meinen -- Pierre Massat -- Qt -- Quentin ROYER -- README Bot <35302948+codetriage-readme-bot@users.noreply.github.com> -- Rafal Zajac -- Rahul Datta Roy -- Rajiv Kilaparti -- Raphael Gavache -- Ray Rodriguez -- Regner Blok-Andersen -- Remco -- Rex Lee(李俊) -- Richard Lee -- Riverside -- Robert Wilkinson -- Rogier Lommers -- Rohan Pai -- Romain Beuque -- Roman Belyakovsky -- Roman Zaynetdinov <627197+zaynetro@users.noreply.github.com> -- Roman Zaynetdinov -- Ronald Petty -- Ross Wolf <31489089+rw-access@users.noreply.github.com> -- Roy Lou -- Rubi <14269809+codenoid@users.noreply.github.com> -- Ryan <46182144+ryanker@users.noreply.github.com> -- Ryan J. Yoder -- SRK.Lyu -- Sai -- Samuel Abreu -- Santhosh Kumar -- Sasha Melentyev -- Sasha Myasoedov -- Segev Finer -- Sergey Egorov -- Sergey Fedchenko -- Sergey Gonimar -- Sergey Ponomarev -- Serica <943914044@qq.com> -- Shamus Taylor -- Shilin Wang -- Shuo -- Skuli Oskarsson -- Snawoot -- Sridhar Ratnakumar -- Steeve Chailloux -- Sudhir Mishra -- Suhas Karanth -- TaeJun Park -- Tatsuya Hoshino -- Tevic -- Tevin Jeffrey -- The Gitter Badger -- Thibault Jamet -- Thomas Boerger -- Thomas Schaffer -- Tommy Chu -- Tudor Roman -- Uwe Dauernheim -- Valentine Oragbakosi -- Vas N -- Vasilyuk Vasiliy -- Victor Castell -- Vince Yuan -- Vyacheslav Dubinin -- Waynerv -- Weilin Shi <934587911@qq.com> -- Xudong Cai -- Yasuhiro Matsumoto -- Yehezkiel Syamsuhadi -- Yoshiki Nakagawa -- Yoshiyuki Kinjo -- Yue Yang -- ZYunH -- Zach Newburgh -- Zasda Yusuf Mikail -- ZhangYunHao -- ZhiFeng Hu -- Zhu Xi -- a2tt -- ahuigo <1781999+ahuigo@users.noreply.github.com> -- ali -- aljun -- andrea -- andriikushch -- anoty -- awkj -- axiaoxin <254606826@qq.com> -- bbiao -- bestgopher <84328409@qq.com> -- betahu -- bigwheel -- bn4t <17193640+bn4t@users.noreply.github.com> -- bullgare -- chainhelen -- chenyang929 -- chriswhelix -- collinmsn <4130944@qq.com> -- cssivision -- danielalves -- delphinus -- dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> -- dickeyxxx -- edebernis -- error10 -- esplo -- eudore <30709860+eudore@users.noreply.github.com> -- ffhelicopter <32922889+ffhelicopter@users.noreply.github.com> -- filikos <11477309+filikos@users.noreply.github.com> -- forging2012 -- goqihoo -- grapeVine -- guonaihong -- heige -- heige -- hellojukay -- henrylee2cn -- htobenothing -- iamhesir <78344375+iamhesir@users.noreply.github.com> -- ijaa -- ishanray -- ishanray -- itcloudy <272685110@qq.com> -- jarodsong6 -- jasonrhansen -- jincheng9 -- joeADSP <75027008+joeADSP@users.noreply.github.com> -- junfengye -- kaiiak -- kebo -- keke <19yamashita15@gmail.com> -- kishor kunal raj <68464660+kishorkunal-raj@users.noreply.github.com> -- kyledinh -- lantw44 -- likakuli <1154584512@qq.com> -- linfangrong -- linzi <873804682@qq.com> -- llgoer -- long-road <13412081338@163.com> -- mbesancon -- mehdy -- metal A-wing -- micanzhang -- minarc -- mllu -- mopemoepe -- msoedov -- mstmdev -- novaeye -- olebedev -- phithon -- pjgg -- qm012 <67568757+qm012@users.noreply.github.com> -- raymonder jin -- rns -- root@andrea:~# -- sekky0905 <20237968+sekky0905@users.noreply.github.com> -- senhtry -- shadrus -- silasb -- solos -- songjiayang -- sope -- srt180 <30768686+srt180@users.noreply.github.com> -- stackerzzq -- sunshineplan -- syssam -- techjanitor -- techjanitor -- thinkerou -- thinkgo <49174849+thinkgos@users.noreply.github.com> -- tsirolnik -- tyltr <31768692+tylitianrui@users.noreply.github.com> -- vinhha96 -- voidman -- vz -- wei -- weibaohui -- whirosan -- willnewrelic -- wssccc -- wuhuizuo -- xyb -- y-yagi -- yiranzai -- youzeliang -- yugu -- yuyabe -- zebozhuang -- zero11-0203 <93071220+zero11-0203@users.noreply.github.com> -- zesani <7sin@outlook.co.th> -- zhanweidu -- zhing -- ziheng -- zzjin -- 森 優太 <59682979+uta-mori@users.noreply.github.com> -- 杰哥 <858806258@qq.com> -- 涛叔 -- 市民233 -- 尹宝强 -- 梦溪笔谈 -- 飞雪无情 -- 寻寻觅觅的Gopher diff --git a/vendor/github.com/gin-gonic/gin/BENCHMARKS.md b/vendor/github.com/gin-gonic/gin/BENCHMARKS.md deleted file mode 100644 index c11ee99..0000000 --- a/vendor/github.com/gin-gonic/gin/BENCHMARKS.md +++ /dev/null @@ -1,666 +0,0 @@ - -# Benchmark System - -**VM HOST:** Travis -**Machine:** Ubuntu 16.04.6 LTS x64 -**Date:** May 04th, 2020 -**Version:** Gin v1.6.3 -**Go Version:** 1.14.2 linux/amd64 -**Source:** [Go HTTP Router Benchmark](https://github.com/gin-gonic/go-http-routing-benchmark) -**Result:** [See the gist](https://gist.github.com/appleboy/b5f2ecfaf50824ae9c64dcfb9165ae5e) or [Travis result](https://travis-ci.org/github/gin-gonic/go-http-routing-benchmark/jobs/682947061) - -## Static Routes: 157 - -```sh -Gin: 34936 Bytes - -HttpServeMux: 14512 Bytes -Ace: 30680 Bytes -Aero: 34536 Bytes -Bear: 30456 Bytes -Beego: 98456 Bytes -Bone: 40224 Bytes -Chi: 83608 Bytes -Denco: 10216 Bytes -Echo: 80328 Bytes -GocraftWeb: 55288 Bytes -Goji: 29744 Bytes -Gojiv2: 105840 Bytes -GoJsonRest: 137496 Bytes -GoRestful: 816936 Bytes -GorillaMux: 585632 Bytes -GowwwRouter: 24968 Bytes -HttpRouter: 21712 Bytes -HttpTreeMux: 73448 Bytes -Kocha: 115472 Bytes -LARS: 30640 Bytes -Macaron: 38592 Bytes -Martini: 310864 Bytes -Pat: 19696 Bytes -Possum: 89920 Bytes -R2router: 23712 Bytes -Rivet: 24608 Bytes -Tango: 28264 Bytes -TigerTonic: 78768 Bytes -Traffic: 538976 Bytes -Vulcan: 369960 Bytes -``` - -## GithubAPI Routes: 203 - -```sh -Gin: 58512 Bytes - -Ace: 48688 Bytes -Aero: 318568 Bytes -Bear: 84248 Bytes -Beego: 150936 Bytes -Bone: 100976 Bytes -Chi: 95112 Bytes -Denco: 36736 Bytes -Echo: 100296 Bytes -GocraftWeb: 95432 Bytes -Goji: 49680 Bytes -Gojiv2: 104704 Bytes -GoJsonRest: 141976 Bytes -GoRestful: 1241656 Bytes -GorillaMux: 1322784 Bytes -GowwwRouter: 80008 Bytes -HttpRouter: 37144 Bytes -HttpTreeMux: 78800 Bytes -Kocha: 785120 Bytes -LARS: 48600 Bytes -Macaron: 92784 Bytes -Martini: 485264 Bytes -Pat: 21200 Bytes -Possum: 85312 Bytes -R2router: 47104 Bytes -Rivet: 42840 Bytes -Tango: 54840 Bytes -TigerTonic: 95264 Bytes -Traffic: 921744 Bytes -Vulcan: 425992 Bytes -``` - -## GPlusAPI Routes: 13 - -```sh -Gin: 4384 Bytes - -Ace: 3712 Bytes -Aero: 26056 Bytes -Bear: 7112 Bytes -Beego: 10272 Bytes -Bone: 6688 Bytes -Chi: 8024 Bytes -Denco: 3264 Bytes -Echo: 9688 Bytes -GocraftWeb: 7496 Bytes -Goji: 3152 Bytes -Gojiv2: 7376 Bytes -GoJsonRest: 11400 Bytes -GoRestful: 74328 Bytes -GorillaMux: 66208 Bytes -GowwwRouter: 5744 Bytes -HttpRouter: 2808 Bytes -HttpTreeMux: 7440 Bytes -Kocha: 128880 Bytes -LARS: 3656 Bytes -Macaron: 8656 Bytes -Martini: 23920 Bytes -Pat: 1856 Bytes -Possum: 7248 Bytes -R2router: 3928 Bytes -Rivet: 3064 Bytes -Tango: 5168 Bytes -TigerTonic: 9408 Bytes -Traffic: 46400 Bytes -Vulcan: 25544 Bytes -``` - -## ParseAPI Routes: 26 - -```sh -Gin: 7776 Bytes - -Ace: 6704 Bytes -Aero: 28488 Bytes -Bear: 12320 Bytes -Beego: 19280 Bytes -Bone: 11440 Bytes -Chi: 9744 Bytes -Denco: 4192 Bytes -Echo: 11664 Bytes -GocraftWeb: 12800 Bytes -Goji: 5680 Bytes -Gojiv2: 14464 Bytes -GoJsonRest: 14072 Bytes -GoRestful: 116264 Bytes -GorillaMux: 105880 Bytes -GowwwRouter: 9344 Bytes -HttpRouter: 5072 Bytes -HttpTreeMux: 7848 Bytes -Kocha: 181712 Bytes -LARS: 6632 Bytes -Macaron: 13648 Bytes -Martini: 45888 Bytes -Pat: 2560 Bytes -Possum: 9200 Bytes -R2router: 7056 Bytes -Rivet: 5680 Bytes -Tango: 8920 Bytes -TigerTonic: 9840 Bytes -Traffic: 79096 Bytes -Vulcan: 44504 Bytes -``` - -## Static Routes - -```sh -BenchmarkGin_StaticAll 62169 19319 ns/op 0 B/op 0 allocs/op - -BenchmarkAce_StaticAll 65428 18313 ns/op 0 B/op 0 allocs/op -BenchmarkAero_StaticAll 121132 9632 ns/op 0 B/op 0 allocs/op -BenchmarkHttpServeMux_StaticAll 52626 22758 ns/op 0 B/op 0 allocs/op -BenchmarkBeego_StaticAll 9962 179058 ns/op 55264 B/op 471 allocs/op -BenchmarkBear_StaticAll 14894 80966 ns/op 20272 B/op 469 allocs/op -BenchmarkBone_StaticAll 18718 64065 ns/op 0 B/op 0 allocs/op -BenchmarkChi_StaticAll 10000 149827 ns/op 67824 B/op 471 allocs/op -BenchmarkDenco_StaticAll 211393 5680 ns/op 0 B/op 0 allocs/op -BenchmarkEcho_StaticAll 49341 24343 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_StaticAll 10000 126209 ns/op 46312 B/op 785 allocs/op -BenchmarkGoji_StaticAll 27956 43174 ns/op 0 B/op 0 allocs/op -BenchmarkGojiv2_StaticAll 3430 370718 ns/op 205984 B/op 1570 allocs/op -BenchmarkGoJsonRest_StaticAll 9134 188888 ns/op 51653 B/op 1727 allocs/op -BenchmarkGoRestful_StaticAll 706 1703330 ns/op 613280 B/op 2053 allocs/op -BenchmarkGorillaMux_StaticAll 1268 924083 ns/op 153233 B/op 1413 allocs/op -BenchmarkGowwwRouter_StaticAll 63374 18935 ns/op 0 B/op 0 allocs/op -BenchmarkHttpRouter_StaticAll 109938 10902 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_StaticAll 109166 10861 ns/op 0 B/op 0 allocs/op -BenchmarkKocha_StaticAll 92258 12992 ns/op 0 B/op 0 allocs/op -BenchmarkLARS_StaticAll 65200 18387 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_StaticAll 5671 291501 ns/op 115553 B/op 1256 allocs/op -BenchmarkMartini_StaticAll 807 1460498 ns/op 125444 B/op 1717 allocs/op -BenchmarkPat_StaticAll 513 2342396 ns/op 602832 B/op 12559 allocs/op -BenchmarkPossum_StaticAll 10000 128270 ns/op 65312 B/op 471 allocs/op -BenchmarkR2router_StaticAll 16726 71760 ns/op 22608 B/op 628 allocs/op -BenchmarkRivet_StaticAll 41722 28723 ns/op 0 B/op 0 allocs/op -BenchmarkTango_StaticAll 7606 205082 ns/op 39209 B/op 1256 allocs/op -BenchmarkTigerTonic_StaticAll 26247 45806 ns/op 7376 B/op 157 allocs/op -BenchmarkTraffic_StaticAll 550 2284518 ns/op 754864 B/op 14601 allocs/op -BenchmarkVulcan_StaticAll 10000 131343 ns/op 15386 B/op 471 allocs/op -``` - -## Micro Benchmarks - -```sh -BenchmarkGin_Param 18785022 63.9 ns/op 0 B/op 0 allocs/op - -BenchmarkAce_Param 14689765 81.5 ns/op 0 B/op 0 allocs/op -BenchmarkAero_Param 23094770 51.2 ns/op 0 B/op 0 allocs/op -BenchmarkBear_Param 1417045 845 ns/op 456 B/op 5 allocs/op -BenchmarkBeego_Param 1000000 1080 ns/op 352 B/op 3 allocs/op -BenchmarkBone_Param 1000000 1463 ns/op 816 B/op 6 allocs/op -BenchmarkChi_Param 1378756 885 ns/op 432 B/op 3 allocs/op -BenchmarkDenco_Param 8557899 143 ns/op 32 B/op 1 allocs/op -BenchmarkEcho_Param 16433347 75.5 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_Param 1000000 1218 ns/op 648 B/op 8 allocs/op -BenchmarkGoji_Param 1921248 617 ns/op 336 B/op 2 allocs/op -BenchmarkGojiv2_Param 561848 2156 ns/op 1328 B/op 11 allocs/op -BenchmarkGoJsonRest_Param 1000000 1358 ns/op 649 B/op 13 allocs/op -BenchmarkGoRestful_Param 224857 5307 ns/op 4192 B/op 14 allocs/op -BenchmarkGorillaMux_Param 498313 2459 ns/op 1280 B/op 10 allocs/op -BenchmarkGowwwRouter_Param 1864354 654 ns/op 432 B/op 3 allocs/op -BenchmarkHttpRouter_Param 26269074 47.7 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_Param 2109829 557 ns/op 352 B/op 3 allocs/op -BenchmarkKocha_Param 5050216 243 ns/op 56 B/op 3 allocs/op -BenchmarkLARS_Param 19811712 59.9 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_Param 662746 2329 ns/op 1072 B/op 10 allocs/op -BenchmarkMartini_Param 279902 4260 ns/op 1072 B/op 10 allocs/op -BenchmarkPat_Param 1000000 1382 ns/op 536 B/op 11 allocs/op -BenchmarkPossum_Param 1000000 1014 ns/op 496 B/op 5 allocs/op -BenchmarkR2router_Param 1712559 707 ns/op 432 B/op 5 allocs/op -BenchmarkRivet_Param 6648086 182 ns/op 48 B/op 1 allocs/op -BenchmarkTango_Param 1221504 994 ns/op 248 B/op 8 allocs/op -BenchmarkTigerTonic_Param 891661 2261 ns/op 776 B/op 16 allocs/op -BenchmarkTraffic_Param 350059 3598 ns/op 1856 B/op 21 allocs/op -BenchmarkVulcan_Param 2517823 472 ns/op 98 B/op 3 allocs/op -BenchmarkAce_Param5 9214365 130 ns/op 0 B/op 0 allocs/op -BenchmarkAero_Param5 15369013 77.9 ns/op 0 B/op 0 allocs/op -BenchmarkBear_Param5 1000000 1113 ns/op 501 B/op 5 allocs/op -BenchmarkBeego_Param5 1000000 1269 ns/op 352 B/op 3 allocs/op -BenchmarkBone_Param5 986820 1873 ns/op 864 B/op 6 allocs/op -BenchmarkChi_Param5 1000000 1156 ns/op 432 B/op 3 allocs/op -BenchmarkDenco_Param5 3036331 400 ns/op 160 B/op 1 allocs/op -BenchmarkEcho_Param5 6447133 186 ns/op 0 B/op 0 allocs/op -BenchmarkGin_Param5 10786068 110 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_Param5 844820 1944 ns/op 920 B/op 11 allocs/op -BenchmarkGoji_Param5 1474965 827 ns/op 336 B/op 2 allocs/op -BenchmarkGojiv2_Param5 442820 2516 ns/op 1392 B/op 11 allocs/op -BenchmarkGoJsonRest_Param5 507555 2711 ns/op 1097 B/op 16 allocs/op -BenchmarkGoRestful_Param5 216481 6093 ns/op 4288 B/op 14 allocs/op -BenchmarkGorillaMux_Param5 314402 3628 ns/op 1344 B/op 10 allocs/op -BenchmarkGowwwRouter_Param5 1624660 733 ns/op 432 B/op 3 allocs/op -BenchmarkHttpRouter_Param5 13167324 92.0 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_Param5 1000000 1295 ns/op 576 B/op 6 allocs/op -BenchmarkKocha_Param5 1000000 1138 ns/op 440 B/op 10 allocs/op -BenchmarkLARS_Param5 11580613 105 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_Param5 473596 2755 ns/op 1072 B/op 10 allocs/op -BenchmarkMartini_Param5 230756 5111 ns/op 1232 B/op 11 allocs/op -BenchmarkPat_Param5 469190 3370 ns/op 888 B/op 29 allocs/op -BenchmarkPossum_Param5 1000000 1002 ns/op 496 B/op 5 allocs/op -BenchmarkR2router_Param5 1422129 844 ns/op 432 B/op 5 allocs/op -BenchmarkRivet_Param5 2263789 539 ns/op 240 B/op 1 allocs/op -BenchmarkTango_Param5 1000000 1256 ns/op 360 B/op 8 allocs/op -BenchmarkTigerTonic_Param5 175500 7492 ns/op 2279 B/op 39 allocs/op -BenchmarkTraffic_Param5 233631 5816 ns/op 2208 B/op 27 allocs/op -BenchmarkVulcan_Param5 1923416 629 ns/op 98 B/op 3 allocs/op -BenchmarkAce_Param20 4321266 281 ns/op 0 B/op 0 allocs/op -BenchmarkAero_Param20 31501641 35.2 ns/op 0 B/op 0 allocs/op -BenchmarkBear_Param20 335204 3489 ns/op 1665 B/op 5 allocs/op -BenchmarkBeego_Param20 503674 2860 ns/op 352 B/op 3 allocs/op -BenchmarkBone_Param20 298922 4741 ns/op 2031 B/op 6 allocs/op -BenchmarkChi_Param20 878181 1957 ns/op 432 B/op 3 allocs/op -BenchmarkDenco_Param20 1000000 1360 ns/op 640 B/op 1 allocs/op -BenchmarkEcho_Param20 2104946 580 ns/op 0 B/op 0 allocs/op -BenchmarkGin_Param20 4167204 290 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_Param20 173064 7514 ns/op 3796 B/op 15 allocs/op -BenchmarkGoji_Param20 458778 2651 ns/op 1247 B/op 2 allocs/op -BenchmarkGojiv2_Param20 364862 3178 ns/op 1632 B/op 11 allocs/op -BenchmarkGoJsonRest_Param20 125514 9760 ns/op 4485 B/op 20 allocs/op -BenchmarkGoRestful_Param20 101217 11964 ns/op 6715 B/op 18 allocs/op -BenchmarkGorillaMux_Param20 147654 8132 ns/op 3452 B/op 12 allocs/op -BenchmarkGowwwRouter_Param20 1000000 1225 ns/op 432 B/op 3 allocs/op -BenchmarkHttpRouter_Param20 4920895 247 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_Param20 173202 6605 ns/op 3196 B/op 10 allocs/op -BenchmarkKocha_Param20 345988 3620 ns/op 1808 B/op 27 allocs/op -BenchmarkLARS_Param20 4592326 262 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_Param20 166492 7286 ns/op 2924 B/op 12 allocs/op -BenchmarkMartini_Param20 122162 10653 ns/op 3595 B/op 13 allocs/op -BenchmarkPat_Param20 78630 15239 ns/op 4424 B/op 93 allocs/op -BenchmarkPossum_Param20 1000000 1008 ns/op 496 B/op 5 allocs/op -BenchmarkR2router_Param20 294981 4587 ns/op 2284 B/op 7 allocs/op -BenchmarkRivet_Param20 691798 2090 ns/op 1024 B/op 1 allocs/op -BenchmarkTango_Param20 842440 2505 ns/op 856 B/op 8 allocs/op -BenchmarkTigerTonic_Param20 38614 31509 ns/op 9870 B/op 119 allocs/op -BenchmarkTraffic_Param20 57633 21107 ns/op 7853 B/op 47 allocs/op -BenchmarkVulcan_Param20 1000000 1178 ns/op 98 B/op 3 allocs/op -BenchmarkAce_ParamWrite 7330743 180 ns/op 8 B/op 1 allocs/op -BenchmarkAero_ParamWrite 13833598 86.7 ns/op 0 B/op 0 allocs/op -BenchmarkBear_ParamWrite 1363321 867 ns/op 456 B/op 5 allocs/op -BenchmarkBeego_ParamWrite 1000000 1104 ns/op 360 B/op 4 allocs/op -BenchmarkBone_ParamWrite 1000000 1475 ns/op 816 B/op 6 allocs/op -BenchmarkChi_ParamWrite 1320590 892 ns/op 432 B/op 3 allocs/op -BenchmarkDenco_ParamWrite 7093605 172 ns/op 32 B/op 1 allocs/op -BenchmarkEcho_ParamWrite 8434424 161 ns/op 8 B/op 1 allocs/op -BenchmarkGin_ParamWrite 10377034 118 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_ParamWrite 1000000 1266 ns/op 656 B/op 9 allocs/op -BenchmarkGoji_ParamWrite 1874168 654 ns/op 336 B/op 2 allocs/op -BenchmarkGojiv2_ParamWrite 459032 2352 ns/op 1360 B/op 13 allocs/op -BenchmarkGoJsonRest_ParamWrite 499434 2145 ns/op 1128 B/op 18 allocs/op -BenchmarkGoRestful_ParamWrite 241087 5470 ns/op 4200 B/op 15 allocs/op -BenchmarkGorillaMux_ParamWrite 425686 2522 ns/op 1280 B/op 10 allocs/op -BenchmarkGowwwRouter_ParamWrite 922172 1778 ns/op 976 B/op 8 allocs/op -BenchmarkHttpRouter_ParamWrite 15392049 77.7 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_ParamWrite 1973385 597 ns/op 352 B/op 3 allocs/op -BenchmarkKocha_ParamWrite 4262500 281 ns/op 56 B/op 3 allocs/op -BenchmarkLARS_ParamWrite 10764410 113 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_ParamWrite 486769 2726 ns/op 1176 B/op 14 allocs/op -BenchmarkMartini_ParamWrite 264804 4842 ns/op 1176 B/op 14 allocs/op -BenchmarkPat_ParamWrite 735116 2047 ns/op 960 B/op 15 allocs/op -BenchmarkPossum_ParamWrite 1000000 1004 ns/op 496 B/op 5 allocs/op -BenchmarkR2router_ParamWrite 1592136 768 ns/op 432 B/op 5 allocs/op -BenchmarkRivet_ParamWrite 3582051 339 ns/op 112 B/op 2 allocs/op -BenchmarkTango_ParamWrite 2237337 534 ns/op 136 B/op 4 allocs/op -BenchmarkTigerTonic_ParamWrite 439608 3136 ns/op 1216 B/op 21 allocs/op -BenchmarkTraffic_ParamWrite 306979 4328 ns/op 2280 B/op 25 allocs/op -BenchmarkVulcan_ParamWrite 2529973 472 ns/op 98 B/op 3 allocs/op -``` - -## GitHub - -```sh -BenchmarkGin_GithubStatic 15629472 76.7 ns/op 0 B/op 0 allocs/op - -BenchmarkAce_GithubStatic 15542612 75.9 ns/op 0 B/op 0 allocs/op -BenchmarkAero_GithubStatic 24777151 48.5 ns/op 0 B/op 0 allocs/op -BenchmarkBear_GithubStatic 2788894 435 ns/op 120 B/op 3 allocs/op -BenchmarkBeego_GithubStatic 1000000 1064 ns/op 352 B/op 3 allocs/op -BenchmarkBone_GithubStatic 93507 12838 ns/op 2880 B/op 60 allocs/op -BenchmarkChi_GithubStatic 1387743 860 ns/op 432 B/op 3 allocs/op -BenchmarkDenco_GithubStatic 39384996 30.4 ns/op 0 B/op 0 allocs/op -BenchmarkEcho_GithubStatic 12076382 99.1 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_GithubStatic 1596495 756 ns/op 296 B/op 5 allocs/op -BenchmarkGoji_GithubStatic 6364876 189 ns/op 0 B/op 0 allocs/op -BenchmarkGojiv2_GithubStatic 550202 2098 ns/op 1312 B/op 10 allocs/op -BenchmarkGoRestful_GithubStatic 102183 12552 ns/op 4256 B/op 13 allocs/op -BenchmarkGoJsonRest_GithubStatic 1000000 1029 ns/op 329 B/op 11 allocs/op -BenchmarkGorillaMux_GithubStatic 255552 5190 ns/op 976 B/op 9 allocs/op -BenchmarkGowwwRouter_GithubStatic 15531916 77.1 ns/op 0 B/op 0 allocs/op -BenchmarkHttpRouter_GithubStatic 27920724 43.1 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_GithubStatic 21448953 55.8 ns/op 0 B/op 0 allocs/op -BenchmarkKocha_GithubStatic 21405310 56.0 ns/op 0 B/op 0 allocs/op -BenchmarkLARS_GithubStatic 13625156 89.0 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_GithubStatic 1000000 1747 ns/op 736 B/op 8 allocs/op -BenchmarkMartini_GithubStatic 187186 7326 ns/op 768 B/op 9 allocs/op -BenchmarkPat_GithubStatic 109143 11563 ns/op 3648 B/op 76 allocs/op -BenchmarkPossum_GithubStatic 1575898 770 ns/op 416 B/op 3 allocs/op -BenchmarkR2router_GithubStatic 3046231 404 ns/op 144 B/op 4 allocs/op -BenchmarkRivet_GithubStatic 11484826 105 ns/op 0 B/op 0 allocs/op -BenchmarkTango_GithubStatic 1000000 1153 ns/op 248 B/op 8 allocs/op -BenchmarkTigerTonic_GithubStatic 4929780 249 ns/op 48 B/op 1 allocs/op -BenchmarkTraffic_GithubStatic 106351 11819 ns/op 4664 B/op 90 allocs/op -BenchmarkVulcan_GithubStatic 1613271 722 ns/op 98 B/op 3 allocs/op -BenchmarkAce_GithubParam 8386032 143 ns/op 0 B/op 0 allocs/op -BenchmarkAero_GithubParam 11816200 102 ns/op 0 B/op 0 allocs/op -BenchmarkBear_GithubParam 1000000 1012 ns/op 496 B/op 5 allocs/op -BenchmarkBeego_GithubParam 1000000 1157 ns/op 352 B/op 3 allocs/op -BenchmarkBone_GithubParam 184653 6912 ns/op 1888 B/op 19 allocs/op -BenchmarkChi_GithubParam 1000000 1102 ns/op 432 B/op 3 allocs/op -BenchmarkDenco_GithubParam 3484798 352 ns/op 128 B/op 1 allocs/op -BenchmarkEcho_GithubParam 6337380 189 ns/op 0 B/op 0 allocs/op -BenchmarkGin_GithubParam 9132032 131 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_GithubParam 1000000 1446 ns/op 712 B/op 9 allocs/op -BenchmarkGoji_GithubParam 1248640 977 ns/op 336 B/op 2 allocs/op -BenchmarkGojiv2_GithubParam 383233 2784 ns/op 1408 B/op 13 allocs/op -BenchmarkGoJsonRest_GithubParam 1000000 1991 ns/op 713 B/op 14 allocs/op -BenchmarkGoRestful_GithubParam 76414 16015 ns/op 4352 B/op 16 allocs/op -BenchmarkGorillaMux_GithubParam 150026 7663 ns/op 1296 B/op 10 allocs/op -BenchmarkGowwwRouter_GithubParam 1592044 751 ns/op 432 B/op 3 allocs/op -BenchmarkHttpRouter_GithubParam 10420628 115 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_GithubParam 1403755 835 ns/op 384 B/op 4 allocs/op -BenchmarkKocha_GithubParam 2286170 533 ns/op 128 B/op 5 allocs/op -BenchmarkLARS_GithubParam 9540374 129 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_GithubParam 533154 2742 ns/op 1072 B/op 10 allocs/op -BenchmarkMartini_GithubParam 119397 9638 ns/op 1152 B/op 11 allocs/op -BenchmarkPat_GithubParam 150675 8858 ns/op 2408 B/op 48 allocs/op -BenchmarkPossum_GithubParam 1000000 1001 ns/op 496 B/op 5 allocs/op -BenchmarkR2router_GithubParam 1602886 761 ns/op 432 B/op 5 allocs/op -BenchmarkRivet_GithubParam 2986579 409 ns/op 96 B/op 1 allocs/op -BenchmarkTango_GithubParam 1000000 1356 ns/op 344 B/op 8 allocs/op -BenchmarkTigerTonic_GithubParam 388899 3429 ns/op 1176 B/op 22 allocs/op -BenchmarkTraffic_GithubParam 123160 9734 ns/op 2816 B/op 40 allocs/op -BenchmarkVulcan_GithubParam 1000000 1138 ns/op 98 B/op 3 allocs/op -BenchmarkAce_GithubAll 40543 29670 ns/op 0 B/op 0 allocs/op -BenchmarkAero_GithubAll 57632 20648 ns/op 0 B/op 0 allocs/op -BenchmarkBear_GithubAll 9234 216179 ns/op 86448 B/op 943 allocs/op -BenchmarkBeego_GithubAll 7407 243496 ns/op 71456 B/op 609 allocs/op -BenchmarkBone_GithubAll 420 2922835 ns/op 720160 B/op 8620 allocs/op -BenchmarkChi_GithubAll 7620 238331 ns/op 87696 B/op 609 allocs/op -BenchmarkDenco_GithubAll 18355 64494 ns/op 20224 B/op 167 allocs/op -BenchmarkEcho_GithubAll 31251 38479 ns/op 0 B/op 0 allocs/op -BenchmarkGin_GithubAll 43550 27364 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_GithubAll 4117 300062 ns/op 131656 B/op 1686 allocs/op -BenchmarkGoji_GithubAll 3274 416158 ns/op 56112 B/op 334 allocs/op -BenchmarkGojiv2_GithubAll 1402 870518 ns/op 352720 B/op 4321 allocs/op -BenchmarkGoJsonRest_GithubAll 2976 401507 ns/op 134371 B/op 2737 allocs/op -BenchmarkGoRestful_GithubAll 410 2913158 ns/op 910144 B/op 2938 allocs/op -BenchmarkGorillaMux_GithubAll 346 3384987 ns/op 251650 B/op 1994 allocs/op -BenchmarkGowwwRouter_GithubAll 10000 143025 ns/op 72144 B/op 501 allocs/op -BenchmarkHttpRouter_GithubAll 55938 21360 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_GithubAll 10000 153944 ns/op 65856 B/op 671 allocs/op -BenchmarkKocha_GithubAll 10000 106315 ns/op 23304 B/op 843 allocs/op -BenchmarkLARS_GithubAll 47779 25084 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_GithubAll 3266 371907 ns/op 149409 B/op 1624 allocs/op -BenchmarkMartini_GithubAll 331 3444706 ns/op 226551 B/op 2325 allocs/op -BenchmarkPat_GithubAll 273 4381818 ns/op 1483152 B/op 26963 allocs/op -BenchmarkPossum_GithubAll 10000 164367 ns/op 84448 B/op 609 allocs/op -BenchmarkR2router_GithubAll 10000 160220 ns/op 77328 B/op 979 allocs/op -BenchmarkRivet_GithubAll 14625 82453 ns/op 16272 B/op 167 allocs/op -BenchmarkTango_GithubAll 6255 279611 ns/op 63826 B/op 1618 allocs/op -BenchmarkTigerTonic_GithubAll 2008 687874 ns/op 193856 B/op 4474 allocs/op -BenchmarkTraffic_GithubAll 355 3478508 ns/op 820744 B/op 14114 allocs/op -BenchmarkVulcan_GithubAll 6885 193333 ns/op 19894 B/op 609 allocs/op -``` - -## Google+ - -```sh -BenchmarkGin_GPlusStatic 19247326 62.2 ns/op 0 B/op 0 allocs/op - -BenchmarkAce_GPlusStatic 20235060 59.2 ns/op 0 B/op 0 allocs/op -BenchmarkAero_GPlusStatic 31978935 37.6 ns/op 0 B/op 0 allocs/op -BenchmarkBear_GPlusStatic 3516523 341 ns/op 104 B/op 3 allocs/op -BenchmarkBeego_GPlusStatic 1212036 991 ns/op 352 B/op 3 allocs/op -BenchmarkBone_GPlusStatic 6736242 183 ns/op 32 B/op 1 allocs/op -BenchmarkChi_GPlusStatic 1490640 814 ns/op 432 B/op 3 allocs/op -BenchmarkDenco_GPlusStatic 55006856 21.8 ns/op 0 B/op 0 allocs/op -BenchmarkEcho_GPlusStatic 17688258 67.9 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_GPlusStatic 1829181 666 ns/op 280 B/op 5 allocs/op -BenchmarkGoji_GPlusStatic 9147451 130 ns/op 0 B/op 0 allocs/op -BenchmarkGojiv2_GPlusStatic 594015 2063 ns/op 1312 B/op 10 allocs/op -BenchmarkGoJsonRest_GPlusStatic 1264906 950 ns/op 329 B/op 11 allocs/op -BenchmarkGoRestful_GPlusStatic 231558 5341 ns/op 3872 B/op 13 allocs/op -BenchmarkGorillaMux_GPlusStatic 908418 1809 ns/op 976 B/op 9 allocs/op -BenchmarkGowwwRouter_GPlusStatic 40684604 29.5 ns/op 0 B/op 0 allocs/op -BenchmarkHttpRouter_GPlusStatic 46742804 25.7 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_GPlusStatic 32567161 36.9 ns/op 0 B/op 0 allocs/op -BenchmarkKocha_GPlusStatic 33800060 35.3 ns/op 0 B/op 0 allocs/op -BenchmarkLARS_GPlusStatic 20431858 60.0 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_GPlusStatic 1000000 1745 ns/op 736 B/op 8 allocs/op -BenchmarkMartini_GPlusStatic 442248 3619 ns/op 768 B/op 9 allocs/op -BenchmarkPat_GPlusStatic 4328004 292 ns/op 96 B/op 2 allocs/op -BenchmarkPossum_GPlusStatic 1570753 763 ns/op 416 B/op 3 allocs/op -BenchmarkR2router_GPlusStatic 3339474 355 ns/op 144 B/op 4 allocs/op -BenchmarkRivet_GPlusStatic 18570961 64.7 ns/op 0 B/op 0 allocs/op -BenchmarkTango_GPlusStatic 1388702 860 ns/op 200 B/op 8 allocs/op -BenchmarkTigerTonic_GPlusStatic 7803543 159 ns/op 32 B/op 1 allocs/op -BenchmarkTraffic_GPlusStatic 878605 2171 ns/op 1112 B/op 16 allocs/op -BenchmarkVulcan_GPlusStatic 2742446 437 ns/op 98 B/op 3 allocs/op -BenchmarkAce_GPlusParam 11626975 105 ns/op 0 B/op 0 allocs/op -BenchmarkAero_GPlusParam 16914322 71.6 ns/op 0 B/op 0 allocs/op -BenchmarkBear_GPlusParam 1405173 832 ns/op 480 B/op 5 allocs/op -BenchmarkBeego_GPlusParam 1000000 1075 ns/op 352 B/op 3 allocs/op -BenchmarkBone_GPlusParam 1000000 1557 ns/op 816 B/op 6 allocs/op -BenchmarkChi_GPlusParam 1347926 894 ns/op 432 B/op 3 allocs/op -BenchmarkDenco_GPlusParam 5513000 212 ns/op 64 B/op 1 allocs/op -BenchmarkEcho_GPlusParam 11884383 101 ns/op 0 B/op 0 allocs/op -BenchmarkGin_GPlusParam 12898952 93.1 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_GPlusParam 1000000 1194 ns/op 648 B/op 8 allocs/op -BenchmarkGoji_GPlusParam 1857229 645 ns/op 336 B/op 2 allocs/op -BenchmarkGojiv2_GPlusParam 520939 2322 ns/op 1328 B/op 11 allocs/op -BenchmarkGoJsonRest_GPlusParam 1000000 1536 ns/op 649 B/op 13 allocs/op -BenchmarkGoRestful_GPlusParam 205449 5800 ns/op 4192 B/op 14 allocs/op -BenchmarkGorillaMux_GPlusParam 395310 3188 ns/op 1280 B/op 10 allocs/op -BenchmarkGowwwRouter_GPlusParam 1851798 667 ns/op 432 B/op 3 allocs/op -BenchmarkHttpRouter_GPlusParam 18420789 65.2 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_GPlusParam 1878463 629 ns/op 352 B/op 3 allocs/op -BenchmarkKocha_GPlusParam 4495610 273 ns/op 56 B/op 3 allocs/op -BenchmarkLARS_GPlusParam 14615976 83.2 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_GPlusParam 584145 2549 ns/op 1072 B/op 10 allocs/op -BenchmarkMartini_GPlusParam 250501 4583 ns/op 1072 B/op 10 allocs/op -BenchmarkPat_GPlusParam 1000000 1645 ns/op 576 B/op 11 allocs/op -BenchmarkPossum_GPlusParam 1000000 1008 ns/op 496 B/op 5 allocs/op -BenchmarkR2router_GPlusParam 1708191 688 ns/op 432 B/op 5 allocs/op -BenchmarkRivet_GPlusParam 5795014 211 ns/op 48 B/op 1 allocs/op -BenchmarkTango_GPlusParam 1000000 1091 ns/op 264 B/op 8 allocs/op -BenchmarkTigerTonic_GPlusParam 760221 2489 ns/op 856 B/op 16 allocs/op -BenchmarkTraffic_GPlusParam 309774 4039 ns/op 1872 B/op 21 allocs/op -BenchmarkVulcan_GPlusParam 1935730 623 ns/op 98 B/op 3 allocs/op -BenchmarkAce_GPlus2Params 9158314 134 ns/op 0 B/op 0 allocs/op -BenchmarkAero_GPlus2Params 11300517 107 ns/op 0 B/op 0 allocs/op -BenchmarkBear_GPlus2Params 1239238 961 ns/op 496 B/op 5 allocs/op -BenchmarkBeego_GPlus2Params 1000000 1202 ns/op 352 B/op 3 allocs/op -BenchmarkBone_GPlus2Params 335576 3725 ns/op 1168 B/op 10 allocs/op -BenchmarkChi_GPlus2Params 1000000 1014 ns/op 432 B/op 3 allocs/op -BenchmarkDenco_GPlus2Params 4394598 280 ns/op 64 B/op 1 allocs/op -BenchmarkEcho_GPlus2Params 7851861 154 ns/op 0 B/op 0 allocs/op -BenchmarkGin_GPlus2Params 9958588 120 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_GPlus2Params 1000000 1433 ns/op 712 B/op 9 allocs/op -BenchmarkGoji_GPlus2Params 1325134 909 ns/op 336 B/op 2 allocs/op -BenchmarkGojiv2_GPlus2Params 405955 2870 ns/op 1408 B/op 14 allocs/op -BenchmarkGoJsonRest_GPlus2Params 977038 1987 ns/op 713 B/op 14 allocs/op -BenchmarkGoRestful_GPlus2Params 205018 6142 ns/op 4384 B/op 16 allocs/op -BenchmarkGorillaMux_GPlus2Params 205641 6015 ns/op 1296 B/op 10 allocs/op -BenchmarkGowwwRouter_GPlus2Params 1748542 684 ns/op 432 B/op 3 allocs/op -BenchmarkHttpRouter_GPlus2Params 14047102 87.7 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_GPlus2Params 1418673 828 ns/op 384 B/op 4 allocs/op -BenchmarkKocha_GPlus2Params 2334562 520 ns/op 128 B/op 5 allocs/op -BenchmarkLARS_GPlus2Params 11954094 101 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_GPlus2Params 491552 2890 ns/op 1072 B/op 10 allocs/op -BenchmarkMartini_GPlus2Params 120532 9545 ns/op 1200 B/op 13 allocs/op -BenchmarkPat_GPlus2Params 194739 6766 ns/op 2168 B/op 33 allocs/op -BenchmarkPossum_GPlus2Params 1201224 1009 ns/op 496 B/op 5 allocs/op -BenchmarkR2router_GPlus2Params 1575535 756 ns/op 432 B/op 5 allocs/op -BenchmarkRivet_GPlus2Params 3698930 325 ns/op 96 B/op 1 allocs/op -BenchmarkTango_GPlus2Params 1000000 1212 ns/op 344 B/op 8 allocs/op -BenchmarkTigerTonic_GPlus2Params 349350 3660 ns/op 1200 B/op 22 allocs/op -BenchmarkTraffic_GPlus2Params 169714 7862 ns/op 2248 B/op 28 allocs/op -BenchmarkVulcan_GPlus2Params 1222288 974 ns/op 98 B/op 3 allocs/op -BenchmarkAce_GPlusAll 845606 1398 ns/op 0 B/op 0 allocs/op -BenchmarkAero_GPlusAll 1000000 1009 ns/op 0 B/op 0 allocs/op -BenchmarkBear_GPlusAll 103830 11386 ns/op 5488 B/op 61 allocs/op -BenchmarkBeego_GPlusAll 82653 14784 ns/op 4576 B/op 39 allocs/op -BenchmarkBone_GPlusAll 36601 33123 ns/op 11744 B/op 109 allocs/op -BenchmarkChi_GPlusAll 95264 12831 ns/op 5616 B/op 39 allocs/op -BenchmarkDenco_GPlusAll 567681 2950 ns/op 672 B/op 11 allocs/op -BenchmarkEcho_GPlusAll 720366 1665 ns/op 0 B/op 0 allocs/op -BenchmarkGin_GPlusAll 1000000 1185 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_GPlusAll 71575 16365 ns/op 8040 B/op 103 allocs/op -BenchmarkGoji_GPlusAll 136352 9191 ns/op 3696 B/op 22 allocs/op -BenchmarkGojiv2_GPlusAll 38006 31802 ns/op 17616 B/op 154 allocs/op -BenchmarkGoJsonRest_GPlusAll 57238 21561 ns/op 8117 B/op 170 allocs/op -BenchmarkGoRestful_GPlusAll 15147 79276 ns/op 55520 B/op 192 allocs/op -BenchmarkGorillaMux_GPlusAll 24446 48410 ns/op 16112 B/op 128 allocs/op -BenchmarkGowwwRouter_GPlusAll 150112 7770 ns/op 4752 B/op 33 allocs/op -BenchmarkHttpRouter_GPlusAll 1367820 878 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_GPlusAll 166628 8004 ns/op 4032 B/op 38 allocs/op -BenchmarkKocha_GPlusAll 265694 4570 ns/op 976 B/op 43 allocs/op -BenchmarkLARS_GPlusAll 1000000 1068 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_GPlusAll 54564 23305 ns/op 9568 B/op 104 allocs/op -BenchmarkMartini_GPlusAll 16274 73845 ns/op 14016 B/op 145 allocs/op -BenchmarkPat_GPlusAll 27181 44478 ns/op 15264 B/op 271 allocs/op -BenchmarkPossum_GPlusAll 122587 10277 ns/op 5408 B/op 39 allocs/op -BenchmarkR2router_GPlusAll 130137 9297 ns/op 5040 B/op 63 allocs/op -BenchmarkRivet_GPlusAll 532438 3323 ns/op 768 B/op 11 allocs/op -BenchmarkTango_GPlusAll 86054 14531 ns/op 3656 B/op 104 allocs/op -BenchmarkTigerTonic_GPlusAll 33936 35356 ns/op 11600 B/op 242 allocs/op -BenchmarkTraffic_GPlusAll 17833 68181 ns/op 26248 B/op 341 allocs/op -BenchmarkVulcan_GPlusAll 120109 9861 ns/op 1274 B/op 39 allocs/op -``` - -## Parse.com - -```sh -BenchmarkGin_ParseStatic 18877833 63.5 ns/op 0 B/op 0 allocs/op - -BenchmarkAce_ParseStatic 19663731 60.8 ns/op 0 B/op 0 allocs/op -BenchmarkAero_ParseStatic 28967341 41.5 ns/op 0 B/op 0 allocs/op -BenchmarkBear_ParseStatic 3006984 402 ns/op 120 B/op 3 allocs/op -BenchmarkBeego_ParseStatic 1000000 1031 ns/op 352 B/op 3 allocs/op -BenchmarkBone_ParseStatic 1782482 675 ns/op 144 B/op 3 allocs/op -BenchmarkChi_ParseStatic 1453261 819 ns/op 432 B/op 3 allocs/op -BenchmarkDenco_ParseStatic 45023595 26.5 ns/op 0 B/op 0 allocs/op -BenchmarkEcho_ParseStatic 17330470 69.3 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_ParseStatic 1644006 731 ns/op 296 B/op 5 allocs/op -BenchmarkGoji_ParseStatic 7026930 170 ns/op 0 B/op 0 allocs/op -BenchmarkGojiv2_ParseStatic 517618 2037 ns/op 1312 B/op 10 allocs/op -BenchmarkGoJsonRest_ParseStatic 1227080 975 ns/op 329 B/op 11 allocs/op -BenchmarkGoRestful_ParseStatic 192458 6659 ns/op 4256 B/op 13 allocs/op -BenchmarkGorillaMux_ParseStatic 744062 2109 ns/op 976 B/op 9 allocs/op -BenchmarkGowwwRouter_ParseStatic 37781062 31.8 ns/op 0 B/op 0 allocs/op -BenchmarkHttpRouter_ParseStatic 45311223 26.5 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_ParseStatic 21383475 56.1 ns/op 0 B/op 0 allocs/op -BenchmarkKocha_ParseStatic 29953290 40.1 ns/op 0 B/op 0 allocs/op -BenchmarkLARS_ParseStatic 20036196 62.7 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_ParseStatic 1000000 1740 ns/op 736 B/op 8 allocs/op -BenchmarkMartini_ParseStatic 404156 3801 ns/op 768 B/op 9 allocs/op -BenchmarkPat_ParseStatic 1547180 772 ns/op 240 B/op 5 allocs/op -BenchmarkPossum_ParseStatic 1608991 757 ns/op 416 B/op 3 allocs/op -BenchmarkR2router_ParseStatic 3177936 385 ns/op 144 B/op 4 allocs/op -BenchmarkRivet_ParseStatic 17783205 67.4 ns/op 0 B/op 0 allocs/op -BenchmarkTango_ParseStatic 1210777 990 ns/op 248 B/op 8 allocs/op -BenchmarkTigerTonic_ParseStatic 5316440 231 ns/op 48 B/op 1 allocs/op -BenchmarkTraffic_ParseStatic 496050 2539 ns/op 1256 B/op 19 allocs/op -BenchmarkVulcan_ParseStatic 2462798 488 ns/op 98 B/op 3 allocs/op -BenchmarkAce_ParseParam 13393669 89.6 ns/op 0 B/op 0 allocs/op -BenchmarkAero_ParseParam 19836619 60.4 ns/op 0 B/op 0 allocs/op -BenchmarkBear_ParseParam 1405954 864 ns/op 467 B/op 5 allocs/op -BenchmarkBeego_ParseParam 1000000 1065 ns/op 352 B/op 3 allocs/op -BenchmarkBone_ParseParam 1000000 1698 ns/op 896 B/op 7 allocs/op -BenchmarkChi_ParseParam 1356037 873 ns/op 432 B/op 3 allocs/op -BenchmarkDenco_ParseParam 6241392 204 ns/op 64 B/op 1 allocs/op -BenchmarkEcho_ParseParam 14088100 85.1 ns/op 0 B/op 0 allocs/op -BenchmarkGin_ParseParam 17426064 68.9 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_ParseParam 1000000 1254 ns/op 664 B/op 8 allocs/op -BenchmarkGoji_ParseParam 1682574 713 ns/op 336 B/op 2 allocs/op -BenchmarkGojiv2_ParseParam 502224 2333 ns/op 1360 B/op 12 allocs/op -BenchmarkGoJsonRest_ParseParam 1000000 1401 ns/op 649 B/op 13 allocs/op -BenchmarkGoRestful_ParseParam 182623 7097 ns/op 4576 B/op 14 allocs/op -BenchmarkGorillaMux_ParseParam 482332 2477 ns/op 1280 B/op 10 allocs/op -BenchmarkGowwwRouter_ParseParam 1834873 657 ns/op 432 B/op 3 allocs/op -BenchmarkHttpRouter_ParseParam 23593393 51.0 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_ParseParam 2100160 574 ns/op 352 B/op 3 allocs/op -BenchmarkKocha_ParseParam 4837220 252 ns/op 56 B/op 3 allocs/op -BenchmarkLARS_ParseParam 18411192 66.2 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_ParseParam 571870 2398 ns/op 1072 B/op 10 allocs/op -BenchmarkMartini_ParseParam 286262 4268 ns/op 1072 B/op 10 allocs/op -BenchmarkPat_ParseParam 692906 2157 ns/op 992 B/op 15 allocs/op -BenchmarkPossum_ParseParam 1000000 1011 ns/op 496 B/op 5 allocs/op -BenchmarkR2router_ParseParam 1722735 697 ns/op 432 B/op 5 allocs/op -BenchmarkRivet_ParseParam 6058054 203 ns/op 48 B/op 1 allocs/op -BenchmarkTango_ParseParam 1000000 1061 ns/op 280 B/op 8 allocs/op -BenchmarkTigerTonic_ParseParam 890275 2277 ns/op 784 B/op 15 allocs/op -BenchmarkTraffic_ParseParam 351322 3543 ns/op 1896 B/op 21 allocs/op -BenchmarkVulcan_ParseParam 2076544 572 ns/op 98 B/op 3 allocs/op -BenchmarkAce_Parse2Params 11718074 101 ns/op 0 B/op 0 allocs/op -BenchmarkAero_Parse2Params 16264988 73.4 ns/op 0 B/op 0 allocs/op -BenchmarkBear_Parse2Params 1238322 973 ns/op 496 B/op 5 allocs/op -BenchmarkBeego_Parse2Params 1000000 1120 ns/op 352 B/op 3 allocs/op -BenchmarkBone_Parse2Params 1000000 1632 ns/op 848 B/op 6 allocs/op -BenchmarkChi_Parse2Params 1239477 955 ns/op 432 B/op 3 allocs/op -BenchmarkDenco_Parse2Params 4944133 245 ns/op 64 B/op 1 allocs/op -BenchmarkEcho_Parse2Params 10518286 114 ns/op 0 B/op 0 allocs/op -BenchmarkGin_Parse2Params 14505195 82.7 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_Parse2Params 1000000 1437 ns/op 712 B/op 9 allocs/op -BenchmarkGoji_Parse2Params 1689883 707 ns/op 336 B/op 2 allocs/op -BenchmarkGojiv2_Parse2Params 502334 2308 ns/op 1344 B/op 11 allocs/op -BenchmarkGoJsonRest_Parse2Params 1000000 1771 ns/op 713 B/op 14 allocs/op -BenchmarkGoRestful_Parse2Params 159092 7583 ns/op 4928 B/op 14 allocs/op -BenchmarkGorillaMux_Parse2Params 417548 2980 ns/op 1296 B/op 10 allocs/op -BenchmarkGowwwRouter_Parse2Params 1751737 686 ns/op 432 B/op 3 allocs/op -BenchmarkHttpRouter_Parse2Params 18089204 66.3 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_Parse2Params 1556986 777 ns/op 384 B/op 4 allocs/op -BenchmarkKocha_Parse2Params 2493082 485 ns/op 128 B/op 5 allocs/op -BenchmarkLARS_Parse2Params 15350108 78.5 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_Parse2Params 530974 2605 ns/op 1072 B/op 10 allocs/op -BenchmarkMartini_Parse2Params 247069 4673 ns/op 1152 B/op 11 allocs/op -BenchmarkPat_Parse2Params 816295 2126 ns/op 752 B/op 16 allocs/op -BenchmarkPossum_Parse2Params 1000000 1002 ns/op 496 B/op 5 allocs/op -BenchmarkR2router_Parse2Params 1569771 733 ns/op 432 B/op 5 allocs/op -BenchmarkRivet_Parse2Params 4080546 295 ns/op 96 B/op 1 allocs/op -BenchmarkTango_Parse2Params 1000000 1121 ns/op 312 B/op 8 allocs/op -BenchmarkTigerTonic_Parse2Params 399556 3470 ns/op 1168 B/op 22 allocs/op -BenchmarkTraffic_Parse2Params 314194 4159 ns/op 1944 B/op 22 allocs/op -BenchmarkVulcan_Parse2Params 1827559 664 ns/op 98 B/op 3 allocs/op -BenchmarkAce_ParseAll 478395 2503 ns/op 0 B/op 0 allocs/op -BenchmarkAero_ParseAll 715392 1658 ns/op 0 B/op 0 allocs/op -BenchmarkBear_ParseAll 59191 20124 ns/op 8928 B/op 110 allocs/op -BenchmarkBeego_ParseAll 45507 27266 ns/op 9152 B/op 78 allocs/op -BenchmarkBone_ParseAll 29328 41459 ns/op 16208 B/op 147 allocs/op -BenchmarkChi_ParseAll 48531 25053 ns/op 11232 B/op 78 allocs/op -BenchmarkDenco_ParseAll 325532 4284 ns/op 928 B/op 16 allocs/op -BenchmarkEcho_ParseAll 433771 2759 ns/op 0 B/op 0 allocs/op -BenchmarkGin_ParseAll 576316 2082 ns/op 0 B/op 0 allocs/op -BenchmarkGocraftWeb_ParseAll 41500 29692 ns/op 13728 B/op 181 allocs/op -BenchmarkGoji_ParseAll 80833 15563 ns/op 5376 B/op 32 allocs/op -BenchmarkGojiv2_ParseAll 19836 60335 ns/op 34448 B/op 277 allocs/op -BenchmarkGoJsonRest_ParseAll 32210 38027 ns/op 13866 B/op 321 allocs/op -BenchmarkGoRestful_ParseAll 6644 190842 ns/op 117600 B/op 354 allocs/op -BenchmarkGorillaMux_ParseAll 12634 95894 ns/op 30288 B/op 250 allocs/op -BenchmarkGowwwRouter_ParseAll 98152 12159 ns/op 6912 B/op 48 allocs/op -BenchmarkHttpRouter_ParseAll 933208 1273 ns/op 0 B/op 0 allocs/op -BenchmarkHttpTreeMux_ParseAll 107191 11554 ns/op 5728 B/op 51 allocs/op -BenchmarkKocha_ParseAll 184862 6225 ns/op 1112 B/op 54 allocs/op -BenchmarkLARS_ParseAll 644546 1858 ns/op 0 B/op 0 allocs/op -BenchmarkMacaron_ParseAll 26145 46484 ns/op 19136 B/op 208 allocs/op -BenchmarkMartini_ParseAll 10000 121838 ns/op 25072 B/op 253 allocs/op -BenchmarkPat_ParseAll 25417 47196 ns/op 15216 B/op 308 allocs/op -BenchmarkPossum_ParseAll 58550 20735 ns/op 10816 B/op 78 allocs/op -BenchmarkR2router_ParseAll 72732 16584 ns/op 8352 B/op 120 allocs/op -BenchmarkRivet_ParseAll 281365 4968 ns/op 912 B/op 16 allocs/op -BenchmarkTango_ParseAll 42831 28668 ns/op 7168 B/op 208 allocs/op -BenchmarkTigerTonic_ParseAll 23774 49972 ns/op 16048 B/op 332 allocs/op -BenchmarkTraffic_ParseAll 10000 104679 ns/op 45520 B/op 605 allocs/op -BenchmarkVulcan_ParseAll 64810 18108 ns/op 2548 B/op 78 allocs/op -``` diff --git a/vendor/github.com/gin-gonic/gin/CHANGELOG.md b/vendor/github.com/gin-gonic/gin/CHANGELOG.md deleted file mode 100644 index 1bc51a8..0000000 --- a/vendor/github.com/gin-gonic/gin/CHANGELOG.md +++ /dev/null @@ -1,502 +0,0 @@ -# Gin ChangeLog - -## Gin v1.8.1 - -### ENHANCEMENTS - -* feat(context): add ContextWithFallback feature flag [#3172](https://github.com/gin-gonic/gin/pull/3172) - -## Gin v1.8.0 - -## Break Changes - -* TrustedProxies: Add default IPv6 support and refactor [#2967](https://github.com/gin-gonic/gin/pull/2967). Please replace `RemoteIP() (net.IP, bool)` with `RemoteIP() net.IP` -* gin.Context with fallback value from gin.Context.Request.Context() [#2751](https://github.com/gin-gonic/gin/pull/2751) - -### BUGFIXES - -* Fixed SetOutput() panics on go 1.17 [#2861](https://github.com/gin-gonic/gin/pull/2861) -* Fix: wrong when wildcard follows named param [#2983](https://github.com/gin-gonic/gin/pull/2983) -* Fix: missing sameSite when do context.reset() [#3123](https://github.com/gin-gonic/gin/pull/3123) - -### ENHANCEMENTS - -* Use Header() instead of deprecated HeaderMap [#2694](https://github.com/gin-gonic/gin/pull/2694) -* RouterGroup.Handle regular match optimization of http method [#2685](https://github.com/gin-gonic/gin/pull/2685) -* Add support go-json, another drop-in json replacement [#2680](https://github.com/gin-gonic/gin/pull/2680) -* Use errors.New to replace fmt.Errorf will much better [#2707](https://github.com/gin-gonic/gin/pull/2707) -* Use Duration.Truncate for truncating precision [#2711](https://github.com/gin-gonic/gin/pull/2711) -* Get client IP when using Cloudflare [#2723](https://github.com/gin-gonic/gin/pull/2723) -* Optimize code adjust [#2700](https://github.com/gin-gonic/gin/pull/2700/files) -* Optimize code and reduce code cyclomatic complexity [#2737](https://github.com/gin-gonic/gin/pull/2737) -* Improve sliceValidateError.Error performance [#2765](https://github.com/gin-gonic/gin/pull/2765) -* Support custom struct tag [#2720](https://github.com/gin-gonic/gin/pull/2720) -* Improve router group tests [#2787](https://github.com/gin-gonic/gin/pull/2787) -* Fallback Context.Deadline() Context.Done() Context.Err() to Context.Request.Context() [#2769](https://github.com/gin-gonic/gin/pull/2769) -* Some codes optimize [#2830](https://github.com/gin-gonic/gin/pull/2830) [#2834](https://github.com/gin-gonic/gin/pull/2834) [#2838](https://github.com/gin-gonic/gin/pull/2838) [#2837](https://github.com/gin-gonic/gin/pull/2837) [#2788](https://github.com/gin-gonic/gin/pull/2788) [#2848](https://github.com/gin-gonic/gin/pull/2848) [#2851](https://github.com/gin-gonic/gin/pull/2851) [#2701](https://github.com/gin-gonic/gin/pull/2701) -* TrustedProxies: Add default IPv6 support and refactor [#2967](https://github.com/gin-gonic/gin/pull/2967) -* Test(route): expose performRequest func [#3012](https://github.com/gin-gonic/gin/pull/3012) -* Support h2c with prior knowledge [#1398](https://github.com/gin-gonic/gin/pull/1398) -* Feat attachment filename support utf8 [#3071](https://github.com/gin-gonic/gin/pull/3071) -* Feat: add StaticFileFS [#2749](https://github.com/gin-gonic/gin/pull/2749) -* Feat(context): return GIN Context from Value method [#2825](https://github.com/gin-gonic/gin/pull/2825) -* Feat: automatically SetMode to TestMode when run go test [#3139](https://github.com/gin-gonic/gin/pull/3139) -* Add TOML bining for gin [#3081](https://github.com/gin-gonic/gin/pull/3081) -* IPv6 add default trusted proxies [#3033](https://github.com/gin-gonic/gin/pull/3033) - -### DOCS - -* Add note about nomsgpack tag to the readme [#2703](https://github.com/gin-gonic/gin/pull/2703) - -## Gin v1.7.7 - -### BUGFIXES - -* Fixed X-Forwarded-For unsafe handling of CVE-2020-28483 [#2844](https://github.com/gin-gonic/gin/pull/2844), closed issue [#2862](https://github.com/gin-gonic/gin/issues/2862). -* Tree: updated the code logic for `latestNode` [#2897](https://github.com/gin-gonic/gin/pull/2897), closed issue [#2894](https://github.com/gin-gonic/gin/issues/2894) [#2878](https://github.com/gin-gonic/gin/issues/2878). -* Tree: fixed the misplacement of adding slashes [#2847](https://github.com/gin-gonic/gin/pull/2847), closed issue [#2843](https://github.com/gin-gonic/gin/issues/2843). -* Tree: fixed tsr with mixed static and wildcard paths [#2924](https://github.com/gin-gonic/gin/pull/2924), closed issue [#2918](https://github.com/gin-gonic/gin/issues/2918). - -### ENHANCEMENTS - -* TrustedProxies: make it backward-compatible [#2887](https://github.com/gin-gonic/gin/pull/2887), closed issue [#2819](https://github.com/gin-gonic/gin/issues/2819). -* TrustedPlatform: provide custom options for another CDN services [#2906](https://github.com/gin-gonic/gin/pull/2906). - -### DOCS - -* NoMethod: added usage annotation ([#2832](https://github.com/gin-gonic/gin/pull/2832#issuecomment-929954463)). - -## Gin v1.7.6 - -### BUGFIXES - -* bump new release to fix v1.7.5 release error by using v1.7.4 codes. - -## Gin v1.7.4 - -### BUGFIXES - -* bump new release to fix checksum mismatch - -## Gin v1.7.3 - -### BUGFIXES - -* fix level 1 router match [#2767](https://github.com/gin-gonic/gin/issues/2767), [#2796](https://github.com/gin-gonic/gin/issues/2796) - -## Gin v1.7.2 - -### BUGFIXES - -* Fix conflict between param and exact path [#2706](https://github.com/gin-gonic/gin/issues/2706). Close issue [#2682](https://github.com/gin-gonic/gin/issues/2682) [#2696](https://github.com/gin-gonic/gin/issues/2696). - -## Gin v1.7.1 - -### BUGFIXES - -* fix: data race with trustedCIDRs from [#2674](https://github.com/gin-gonic/gin/issues/2674)([#2675](https://github.com/gin-gonic/gin/pull/2675)) - -## Gin v1.7.0 - -### BUGFIXES - -* fix compile error from [#2572](https://github.com/gin-gonic/gin/pull/2572) ([#2600](https://github.com/gin-gonic/gin/pull/2600)) -* fix: print headers without Authorization header on broken pipe ([#2528](https://github.com/gin-gonic/gin/pull/2528)) -* fix(tree): reassign fullpath when register new node ([#2366](https://github.com/gin-gonic/gin/pull/2366)) - -### ENHANCEMENTS - -* Support params and exact routes without creating conflicts ([#2663](https://github.com/gin-gonic/gin/pull/2663)) -* chore: improve render string performance ([#2365](https://github.com/gin-gonic/gin/pull/2365)) -* Sync route tree to httprouter latest code ([#2368](https://github.com/gin-gonic/gin/pull/2368)) -* chore: rename getQueryCache/getFormCache to initQueryCache/initFormCa ([#2375](https://github.com/gin-gonic/gin/pull/2375)) -* chore(performance): improve countParams ([#2378](https://github.com/gin-gonic/gin/pull/2378)) -* Remove some functions that have the same effect as the bytes package ([#2387](https://github.com/gin-gonic/gin/pull/2387)) -* update:SetMode function ([#2321](https://github.com/gin-gonic/gin/pull/2321)) -* remove a unused type SecureJSONPrefix ([#2391](https://github.com/gin-gonic/gin/pull/2391)) -* Add a redirect sample for POST method ([#2389](https://github.com/gin-gonic/gin/pull/2389)) -* Add CustomRecovery builtin middleware ([#2322](https://github.com/gin-gonic/gin/pull/2322)) -* binding: avoid 2038 problem on 32-bit architectures ([#2450](https://github.com/gin-gonic/gin/pull/2450)) -* Prevent panic in Context.GetQuery() when there is no Request ([#2412](https://github.com/gin-gonic/gin/pull/2412)) -* Add GetUint and GetUint64 method on gin.context ([#2487](https://github.com/gin-gonic/gin/pull/2487)) -* update content-disposition header to MIME-style ([#2512](https://github.com/gin-gonic/gin/pull/2512)) -* reduce allocs and improve the render `WriteString` ([#2508](https://github.com/gin-gonic/gin/pull/2508)) -* implement ".Unwrap() error" on Error type ([#2525](https://github.com/gin-gonic/gin/pull/2525)) ([#2526](https://github.com/gin-gonic/gin/pull/2526)) -* Allow bind with a map[string]string ([#2484](https://github.com/gin-gonic/gin/pull/2484)) -* chore: update tree ([#2371](https://github.com/gin-gonic/gin/pull/2371)) -* Support binding for slice/array obj [Rewrite] ([#2302](https://github.com/gin-gonic/gin/pull/2302)) -* basic auth: fix timing oracle ([#2609](https://github.com/gin-gonic/gin/pull/2609)) -* Add mixed param and non-param paths (port of httprouter[#329](https://github.com/gin-gonic/gin/pull/329)) ([#2663](https://github.com/gin-gonic/gin/pull/2663)) -* feat(engine): add trustedproxies and remoteIP ([#2632](https://github.com/gin-gonic/gin/pull/2632)) - -## Gin v1.6.3 - -### ENHANCEMENTS - - * Improve performance: Change `*sync.RWMutex` to `sync.RWMutex` in context. [#2351](https://github.com/gin-gonic/gin/pull/2351) - -## Gin v1.6.2 - -### BUGFIXES - * fix missing initial sync.RWMutex [#2305](https://github.com/gin-gonic/gin/pull/2305) -### ENHANCEMENTS - * Add set samesite in cookie. [#2306](https://github.com/gin-gonic/gin/pull/2306) - -## Gin v1.6.1 - -### BUGFIXES - * Revert "fix accept incoming network connections" [#2294](https://github.com/gin-gonic/gin/pull/2294) - -## Gin v1.6.0 - -### BREAKING - * chore(performance): Improve performance for adding RemoveExtraSlash flag [#2159](https://github.com/gin-gonic/gin/pull/2159) - * drop support govendor [#2148](https://github.com/gin-gonic/gin/pull/2148) - * Added support for SameSite cookie flag [#1615](https://github.com/gin-gonic/gin/pull/1615) -### FEATURES - * add yaml negotiation [#2220](https://github.com/gin-gonic/gin/pull/2220) - * FileFromFS [#2112](https://github.com/gin-gonic/gin/pull/2112) -### BUGFIXES - * Unix Socket Handling [#2280](https://github.com/gin-gonic/gin/pull/2280) - * Use json marshall in context json to fix breaking new line issue. Fixes #2209 [#2228](https://github.com/gin-gonic/gin/pull/2228) - * fix accept incoming network connections [#2216](https://github.com/gin-gonic/gin/pull/2216) - * Fixed a bug in the calculation of the maximum number of parameters [#2166](https://github.com/gin-gonic/gin/pull/2166) - * [FIX] allow empty headers on DataFromReader [#2121](https://github.com/gin-gonic/gin/pull/2121) - * Add mutex for protect Context.Keys map [#1391](https://github.com/gin-gonic/gin/pull/1391) -### ENHANCEMENTS - * Add mitigation for log injection [#2277](https://github.com/gin-gonic/gin/pull/2277) - * tree: range over nodes values [#2229](https://github.com/gin-gonic/gin/pull/2229) - * tree: remove duplicate assignment [#2222](https://github.com/gin-gonic/gin/pull/2222) - * chore: upgrade go-isatty and json-iterator/go [#2215](https://github.com/gin-gonic/gin/pull/2215) - * path: sync code with httprouter [#2212](https://github.com/gin-gonic/gin/pull/2212) - * Use zero-copy approach to convert types between string and byte slice [#2206](https://github.com/gin-gonic/gin/pull/2206) - * Reuse bytes when cleaning the URL paths [#2179](https://github.com/gin-gonic/gin/pull/2179) - * tree: remove one else statement [#2177](https://github.com/gin-gonic/gin/pull/2177) - * tree: sync httprouter update (#2173) (#2172) [#2171](https://github.com/gin-gonic/gin/pull/2171) - * tree: sync part httprouter codes and reduce if/else [#2163](https://github.com/gin-gonic/gin/pull/2163) - * use http method constant [#2155](https://github.com/gin-gonic/gin/pull/2155) - * upgrade go-validator to v10 [#2149](https://github.com/gin-gonic/gin/pull/2149) - * Refactor redirect request in gin.go [#1970](https://github.com/gin-gonic/gin/pull/1970) - * Add build tag nomsgpack [#1852](https://github.com/gin-gonic/gin/pull/1852) -### DOCS - * docs(path): improve comments [#2223](https://github.com/gin-gonic/gin/pull/2223) - * Renew README to fit the modification of SetCookie method [#2217](https://github.com/gin-gonic/gin/pull/2217) - * Fix spelling [#2202](https://github.com/gin-gonic/gin/pull/2202) - * Remove broken link from README. [#2198](https://github.com/gin-gonic/gin/pull/2198) - * Update docs on Context.Done(), Context.Deadline() and Context.Err() [#2196](https://github.com/gin-gonic/gin/pull/2196) - * Update validator to v10 [#2190](https://github.com/gin-gonic/gin/pull/2190) - * upgrade go-validator to v10 for README [#2189](https://github.com/gin-gonic/gin/pull/2189) - * Update to currently output [#2188](https://github.com/gin-gonic/gin/pull/2188) - * Fix "Custom Validators" example [#2186](https://github.com/gin-gonic/gin/pull/2186) - * Add project to README [#2165](https://github.com/gin-gonic/gin/pull/2165) - * docs(benchmarks): for gin v1.5 [#2153](https://github.com/gin-gonic/gin/pull/2153) - * Changed wording for clarity in README.md [#2122](https://github.com/gin-gonic/gin/pull/2122) -### MISC - * ci support go1.14 [#2262](https://github.com/gin-gonic/gin/pull/2262) - * chore: upgrade depend version [#2231](https://github.com/gin-gonic/gin/pull/2231) - * Drop support go1.10 [#2147](https://github.com/gin-gonic/gin/pull/2147) - * fix comment in `mode.go` [#2129](https://github.com/gin-gonic/gin/pull/2129) - -## Gin v1.5.0 - -- [FIX] Use DefaultWriter and DefaultErrorWriter for debug messages [#1891](https://github.com/gin-gonic/gin/pull/1891) -- [NEW] Now you can parse the inline lowercase start structure [#1893](https://github.com/gin-gonic/gin/pull/1893) -- [FIX] Some code improvements [#1909](https://github.com/gin-gonic/gin/pull/1909) -- [FIX] Use encode replace json marshal increase json encoder speed [#1546](https://github.com/gin-gonic/gin/pull/1546) -- [NEW] Hold matched route full path in the Context [#1826](https://github.com/gin-gonic/gin/pull/1826) -- [FIX] Fix context.Params race condition on Copy() [#1841](https://github.com/gin-gonic/gin/pull/1841) -- [NEW] Add context param query cache [#1450](https://github.com/gin-gonic/gin/pull/1450) -- [FIX] Improve GetQueryMap performance [#1918](https://github.com/gin-gonic/gin/pull/1918) -- [FIX] Improve get post data [#1920](https://github.com/gin-gonic/gin/pull/1920) -- [FIX] Use context instead of x/net/context [#1922](https://github.com/gin-gonic/gin/pull/1922) -- [FIX] Attempt to fix PostForm cache bug [#1931](https://github.com/gin-gonic/gin/pull/1931) -- [NEW] Add support of multipart multi files [#1949](https://github.com/gin-gonic/gin/pull/1949) -- [NEW] Support bind http header param [#1957](https://github.com/gin-gonic/gin/pull/1957) -- [FIX] Drop support for go1.8 and go1.9 [#1933](https://github.com/gin-gonic/gin/pull/1933) -- [FIX] Bugfix for the FullPath feature [#1919](https://github.com/gin-gonic/gin/pull/1919) -- [FIX] Gin1.5 bytes.Buffer to strings.Builder [#1939](https://github.com/gin-gonic/gin/pull/1939) -- [FIX] Upgrade github.com/ugorji/go/codec [#1969](https://github.com/gin-gonic/gin/pull/1969) -- [NEW] Support bind unix time [#1980](https://github.com/gin-gonic/gin/pull/1980) -- [FIX] Simplify code [#2004](https://github.com/gin-gonic/gin/pull/2004) -- [NEW] Support negative Content-Length in DataFromReader [#1981](https://github.com/gin-gonic/gin/pull/1981) -- [FIX] Identify terminal on a RISC-V architecture for auto-colored logs [#2019](https://github.com/gin-gonic/gin/pull/2019) -- [BREAKING] `Context.JSONP()` now expects a semicolon (`;`) at the end [#2007](https://github.com/gin-gonic/gin/pull/2007) -- [BREAKING] Upgrade default `binding.Validator` to v9 (see [its changelog](https://github.com/go-playground/validator/releases/tag/v9.0.0)) [#1015](https://github.com/gin-gonic/gin/pull/1015) -- [NEW] Add `DisallowUnknownFields()` in `Context.BindJSON()` [#2028](https://github.com/gin-gonic/gin/pull/2028) -- [NEW] Use specific `net.Listener` with `Engine.RunListener()` [#2023](https://github.com/gin-gonic/gin/pull/2023) -- [FIX] Fix some typo [#2079](https://github.com/gin-gonic/gin/pull/2079) [#2080](https://github.com/gin-gonic/gin/pull/2080) -- [FIX] Relocate binding body tests [#2086](https://github.com/gin-gonic/gin/pull/2086) -- [FIX] Use Writer in Context.Status [#1606](https://github.com/gin-gonic/gin/pull/1606) -- [FIX] `Engine.RunUnix()` now returns the error if it can't change the file mode [#2093](https://github.com/gin-gonic/gin/pull/2093) -- [FIX] `RouterGroup.StaticFS()` leaked files. Now it closes them. [#2118](https://github.com/gin-gonic/gin/pull/2118) -- [FIX] `Context.Request.FormFile` leaked file. Now it closes it. [#2114](https://github.com/gin-gonic/gin/pull/2114) -- [FIX] Ignore walking on `form:"-"` mapping [#1943](https://github.com/gin-gonic/gin/pull/1943) - -### Gin v1.4.0 - -- [NEW] Support for [Go Modules](https://github.com/golang/go/wiki/Modules) [#1569](https://github.com/gin-gonic/gin/pull/1569) -- [NEW] Refactor of form mapping multipart request [#1829](https://github.com/gin-gonic/gin/pull/1829) -- [FIX] Truncate Latency precision in long running request [#1830](https://github.com/gin-gonic/gin/pull/1830) -- [FIX] IsTerm flag should not be affected by DisableConsoleColor method. [#1802](https://github.com/gin-gonic/gin/pull/1802) -- [NEW] Supporting file binding [#1264](https://github.com/gin-gonic/gin/pull/1264) -- [NEW] Add support for mapping arrays [#1797](https://github.com/gin-gonic/gin/pull/1797) -- [FIX] Readme updates [#1793](https://github.com/gin-gonic/gin/pull/1793) [#1788](https://github.com/gin-gonic/gin/pull/1788) [1789](https://github.com/gin-gonic/gin/pull/1789) -- [FIX] StaticFS: Fixed Logging two log lines on 404. [#1805](https://github.com/gin-gonic/gin/pull/1805), [#1804](https://github.com/gin-gonic/gin/pull/1804) -- [NEW] Make context.Keys available as LogFormatterParams [#1779](https://github.com/gin-gonic/gin/pull/1779) -- [NEW] Use internal/json for Marshal/Unmarshal [#1791](https://github.com/gin-gonic/gin/pull/1791) -- [NEW] Support mapping time.Duration [#1794](https://github.com/gin-gonic/gin/pull/1794) -- [NEW] Refactor form mappings [#1749](https://github.com/gin-gonic/gin/pull/1749) -- [NEW] Added flag to context.Stream indicates if client disconnected in middle of stream [#1252](https://github.com/gin-gonic/gin/pull/1252) -- [FIX] Moved [examples](https://github.com/gin-gonic/examples) to stand alone Repo [#1775](https://github.com/gin-gonic/gin/pull/1775) -- [NEW] Extend context.File to allow for the content-disposition attachments via a new method context.Attachment [#1260](https://github.com/gin-gonic/gin/pull/1260) -- [FIX] Support HTTP content negotiation wildcards [#1112](https://github.com/gin-gonic/gin/pull/1112) -- [NEW] Add prefix from X-Forwarded-Prefix in redirectTrailingSlash [#1238](https://github.com/gin-gonic/gin/pull/1238) -- [FIX] context.Copy() race condition [#1020](https://github.com/gin-gonic/gin/pull/1020) -- [NEW] Add context.HandlerNames() [#1729](https://github.com/gin-gonic/gin/pull/1729) -- [FIX] Change color methods to public in the defaultLogger. [#1771](https://github.com/gin-gonic/gin/pull/1771) -- [FIX] Update writeHeaders method to use http.Header.Set [#1722](https://github.com/gin-gonic/gin/pull/1722) -- [NEW] Add response size to LogFormatterParams [#1752](https://github.com/gin-gonic/gin/pull/1752) -- [NEW] Allow ignoring field on form mapping [#1733](https://github.com/gin-gonic/gin/pull/1733) -- [NEW] Add a function to force color in console output. [#1724](https://github.com/gin-gonic/gin/pull/1724) -- [FIX] Context.Next() - recheck len of handlers on every iteration. [#1745](https://github.com/gin-gonic/gin/pull/1745) -- [FIX] Fix all errcheck warnings [#1739](https://github.com/gin-gonic/gin/pull/1739) [#1653](https://github.com/gin-gonic/gin/pull/1653) -- [NEW] context: inherits context cancellation and deadline from http.Request context for Go>=1.7 [#1690](https://github.com/gin-gonic/gin/pull/1690) -- [NEW] Binding for URL Params [#1694](https://github.com/gin-gonic/gin/pull/1694) -- [NEW] Add LoggerWithFormatter method [#1677](https://github.com/gin-gonic/gin/pull/1677) -- [FIX] CI testing updates [#1671](https://github.com/gin-gonic/gin/pull/1671) [#1670](https://github.com/gin-gonic/gin/pull/1670) [#1682](https://github.com/gin-gonic/gin/pull/1682) [#1669](https://github.com/gin-gonic/gin/pull/1669) -- [FIX] StaticFS(): Send 404 when path does not exist [#1663](https://github.com/gin-gonic/gin/pull/1663) -- [FIX] Handle nil body for JSON binding [#1638](https://github.com/gin-gonic/gin/pull/1638) -- [FIX] Support bind uri param [#1612](https://github.com/gin-gonic/gin/pull/1612) -- [FIX] recovery: fix issue with syscall import on google app engine [#1640](https://github.com/gin-gonic/gin/pull/1640) -- [FIX] Make sure the debug log contains line breaks [#1650](https://github.com/gin-gonic/gin/pull/1650) -- [FIX] Panic stack trace being printed during recovery of broken pipe [#1089](https://github.com/gin-gonic/gin/pull/1089) [#1259](https://github.com/gin-gonic/gin/pull/1259) -- [NEW] RunFd method to run http.Server through a file descriptor [#1609](https://github.com/gin-gonic/gin/pull/1609) -- [NEW] Yaml binding support [#1618](https://github.com/gin-gonic/gin/pull/1618) -- [FIX] Pass MaxMultipartMemory when FormFile is called [#1600](https://github.com/gin-gonic/gin/pull/1600) -- [FIX] LoadHTML* tests [#1559](https://github.com/gin-gonic/gin/pull/1559) -- [FIX] Removed use of sync.pool from HandleContext [#1565](https://github.com/gin-gonic/gin/pull/1565) -- [FIX] Format output log to os.Stderr [#1571](https://github.com/gin-gonic/gin/pull/1571) -- [FIX] Make logger use a yellow background and a darkgray text for legibility [#1570](https://github.com/gin-gonic/gin/pull/1570) -- [FIX] Remove sensitive request information from panic log. [#1370](https://github.com/gin-gonic/gin/pull/1370) -- [FIX] log.Println() does not print timestamp [#829](https://github.com/gin-gonic/gin/pull/829) [#1560](https://github.com/gin-gonic/gin/pull/1560) -- [NEW] Add PureJSON renderer [#694](https://github.com/gin-gonic/gin/pull/694) -- [FIX] Add missing copyright and update if/else [#1497](https://github.com/gin-gonic/gin/pull/1497) -- [FIX] Update msgpack usage [#1498](https://github.com/gin-gonic/gin/pull/1498) -- [FIX] Use protobuf on render [#1496](https://github.com/gin-gonic/gin/pull/1496) -- [FIX] Add support for Protobuf format response [#1479](https://github.com/gin-gonic/gin/pull/1479) -- [NEW] Set default time format in form binding [#1487](https://github.com/gin-gonic/gin/pull/1487) -- [FIX] Add BindXML and ShouldBindXML [#1485](https://github.com/gin-gonic/gin/pull/1485) -- [NEW] Upgrade dependency libraries [#1491](https://github.com/gin-gonic/gin/pull/1491) - - -## Gin v1.3.0 - -- [NEW] Add [`func (*Context) QueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.QueryMap), [`func (*Context) GetQueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetQueryMap), [`func (*Context) PostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.PostFormMap) and [`func (*Context) GetPostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetPostFormMap) to support `type map[string]string` as query string or form parameters, see [#1383](https://github.com/gin-gonic/gin/pull/1383) -- [NEW] Add [`func (*Context) AsciiJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.AsciiJSON), see [#1358](https://github.com/gin-gonic/gin/pull/1358) -- [NEW] Add `Pusher()` in [`type ResponseWriter`](https://godoc.org/github.com/gin-gonic/gin#ResponseWriter) for supporting http2 push, see [#1273](https://github.com/gin-gonic/gin/pull/1273) -- [NEW] Add [`func (*Context) DataFromReader`](https://godoc.org/github.com/gin-gonic/gin#Context.DataFromReader) for serving dynamic data, see [#1304](https://github.com/gin-gonic/gin/pull/1304) -- [NEW] Add [`func (*Context) ShouldBindBodyWith`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindBodyWith) allowing to call binding multiple times, see [#1341](https://github.com/gin-gonic/gin/pull/1341) -- [NEW] Support pointers in form binding, see [#1336](https://github.com/gin-gonic/gin/pull/1336) -- [NEW] Add [`func (*Context) JSONP`](https://godoc.org/github.com/gin-gonic/gin#Context.JSONP), see [#1333](https://github.com/gin-gonic/gin/pull/1333) -- [NEW] Support default value in form binding, see [#1138](https://github.com/gin-gonic/gin/pull/1138) -- [NEW] Expose validator engine in [`type StructValidator`](https://godoc.org/github.com/gin-gonic/gin/binding#StructValidator), see [#1277](https://github.com/gin-gonic/gin/pull/1277) -- [NEW] Add [`func (*Context) ShouldBind`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBind), [`func (*Context) ShouldBindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindQuery) and [`func (*Context) ShouldBindJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindJSON), see [#1047](https://github.com/gin-gonic/gin/pull/1047) -- [NEW] Add support for `time.Time` location in form binding, see [#1117](https://github.com/gin-gonic/gin/pull/1117) -- [NEW] Add [`func (*Context) BindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.BindQuery), see [#1029](https://github.com/gin-gonic/gin/pull/1029) -- [NEW] Make [jsonite](https://github.com/json-iterator/go) optional with build tags, see [#1026](https://github.com/gin-gonic/gin/pull/1026) -- [NEW] Show query string in logger, see [#999](https://github.com/gin-gonic/gin/pull/999) -- [NEW] Add [`func (*Context) SecureJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.SecureJSON), see [#987](https://github.com/gin-gonic/gin/pull/987) and [#993](https://github.com/gin-gonic/gin/pull/993) -- [DEPRECATE] `func (*Context) GetCookie` for [`func (*Context) Cookie`](https://godoc.org/github.com/gin-gonic/gin#Context.Cookie) -- [FIX] Don't display color tags if [`func DisableConsoleColor`](https://godoc.org/github.com/gin-gonic/gin#DisableConsoleColor) called, see [#1072](https://github.com/gin-gonic/gin/pull/1072) -- [FIX] Gin Mode `""` when calling [`func Mode`](https://godoc.org/github.com/gin-gonic/gin#Mode) now returns `const DebugMode`, see [#1250](https://github.com/gin-gonic/gin/pull/1250) -- [FIX] `Flush()` now doesn't overwrite `responseWriter` status code, see [#1460](https://github.com/gin-gonic/gin/pull/1460) - -## Gin 1.2.0 - -- [NEW] Switch from godeps to govendor -- [NEW] Add support for Let's Encrypt via gin-gonic/autotls -- [NEW] Improve README examples and add extra at examples folder -- [NEW] Improved support with App Engine -- [NEW] Add custom template delimiters, see #860 -- [NEW] Add Template Func Maps, see #962 -- [NEW] Add \*context.Handler(), see #928 -- [NEW] Add \*context.GetRawData() -- [NEW] Add \*context.GetHeader() (request) -- [NEW] Add \*context.AbortWithStatusJSON() (JSON content type) -- [NEW] Add \*context.Keys type cast helpers -- [NEW] Add \*context.ShouldBindWith() -- [NEW] Add \*context.MustBindWith() -- [NEW] Add \*engine.SetFuncMap() -- [DEPRECATE] On next release: \*context.BindWith(), see #855 -- [FIX] Refactor render -- [FIX] Reworked tests -- [FIX] logger now supports cygwin -- [FIX] Use X-Forwarded-For before X-Real-Ip -- [FIX] time.Time binding (#904) - -## Gin 1.1.4 - -- [NEW] Support google appengine for IsTerminal func - -## Gin 1.1.3 - -- [FIX] Reverted Logger: skip ANSI color commands - -## Gin 1.1 - -- [NEW] Implement QueryArray and PostArray methods -- [NEW] Refactor GetQuery and GetPostForm -- [NEW] Add contribution guide -- [FIX] Corrected typos in README -- [FIX] Removed additional Iota -- [FIX] Changed imports to gopkg instead of github in README (#733) -- [FIX] Logger: skip ANSI color commands if output is not a tty - -## Gin 1.0rc2 (...) - -- [PERFORMANCE] Fast path for writing Content-Type. -- [PERFORMANCE] Much faster 404 routing -- [PERFORMANCE] Allocation optimizations -- [PERFORMANCE] Faster root tree lookup -- [PERFORMANCE] Zero overhead, String() and JSON() rendering. -- [PERFORMANCE] Faster ClientIP parsing -- [PERFORMANCE] Much faster SSE implementation -- [NEW] Benchmarks suite -- [NEW] Bind validation can be disabled and replaced with custom validators. -- [NEW] More flexible HTML render -- [NEW] Multipart and PostForm bindings -- [NEW] Adds method to return all the registered routes -- [NEW] Context.HandlerName() returns the main handler's name -- [NEW] Adds Error.IsType() helper -- [FIX] Binding multipart form -- [FIX] Integration tests -- [FIX] Crash when binding non struct object in Context. -- [FIX] RunTLS() implementation -- [FIX] Logger() unit tests -- [FIX] Adds SetHTMLTemplate() warning -- [FIX] Context.IsAborted() -- [FIX] More unit tests -- [FIX] JSON, XML, HTML renders accept custom content-types -- [FIX] gin.AbortIndex is unexported -- [FIX] Better approach to avoid directory listing in StaticFS() -- [FIX] Context.ClientIP() always returns the IP with trimmed spaces. -- [FIX] Better warning when running in debug mode. -- [FIX] Google App Engine integration. debugPrint does not use os.Stdout -- [FIX] Fixes integer overflow in error type -- [FIX] Error implements the json.Marshaller interface -- [FIX] MIT license in every file - - -## Gin 1.0rc1 (May 22, 2015) - -- [PERFORMANCE] Zero allocation router -- [PERFORMANCE] Faster JSON, XML and text rendering -- [PERFORMANCE] Custom hand optimized HttpRouter for Gin -- [PERFORMANCE] Misc code optimizations. Inlining, tail call optimizations -- [NEW] Built-in support for golang.org/x/net/context -- [NEW] Any(path, handler). Create a route that matches any path -- [NEW] Refactored rendering pipeline (faster and static typed) -- [NEW] Refactored errors API -- [NEW] IndentedJSON() prints pretty JSON -- [NEW] Added gin.DefaultWriter -- [NEW] UNIX socket support -- [NEW] RouterGroup.BasePath is exposed -- [NEW] JSON validation using go-validate-yourself (very powerful options) -- [NEW] Completed suite of unit tests -- [NEW] HTTP streaming with c.Stream() -- [NEW] StaticFile() creates a router for serving just one file. -- [NEW] StaticFS() has an option to disable directory listing. -- [NEW] StaticFS() for serving static files through virtual filesystems -- [NEW] Server-Sent Events native support -- [NEW] WrapF() and WrapH() helpers for wrapping http.HandlerFunc and http.Handler -- [NEW] Added LoggerWithWriter() middleware -- [NEW] Added RecoveryWithWriter() middleware -- [NEW] Added DefaultPostFormValue() -- [NEW] Added DefaultFormValue() -- [NEW] Added DefaultParamValue() -- [FIX] BasicAuth() when using custom realm -- [FIX] Bug when serving static files in nested routing group -- [FIX] Redirect using built-in http.Redirect() -- [FIX] Logger when printing the requested path -- [FIX] Documentation typos -- [FIX] Context.Engine renamed to Context.engine -- [FIX] Better debugging messages -- [FIX] ErrorLogger -- [FIX] Debug HTTP render -- [FIX] Refactored binding and render modules -- [FIX] Refactored Context initialization -- [FIX] Refactored BasicAuth() -- [FIX] NoMethod/NoRoute handlers -- [FIX] Hijacking http -- [FIX] Better support for Google App Engine (using log instead of fmt) - - -## Gin 0.6 (Mar 9, 2015) - -- [NEW] Support multipart/form-data -- [NEW] NoMethod handler -- [NEW] Validate sub structures -- [NEW] Support for HTTP Realm Auth -- [FIX] Unsigned integers in binding -- [FIX] Improve color logger - - -## Gin 0.5 (Feb 7, 2015) - -- [NEW] Content Negotiation -- [FIX] Solved security bug that allow a client to spoof ip -- [FIX] Fix unexported/ignored fields in binding - - -## Gin 0.4 (Aug 21, 2014) - -- [NEW] Development mode -- [NEW] Unit tests -- [NEW] Add Content.Redirect() -- [FIX] Deferring WriteHeader() -- [FIX] Improved documentation for model binding - - -## Gin 0.3 (Jul 18, 2014) - -- [PERFORMANCE] Normal log and error log are printed in the same call. -- [PERFORMANCE] Improve performance of NoRouter() -- [PERFORMANCE] Improve context's memory locality, reduce CPU cache faults. -- [NEW] Flexible rendering API -- [NEW] Add Context.File() -- [NEW] Add shortcut RunTLS() for http.ListenAndServeTLS -- [FIX] Rename NotFound404() to NoRoute() -- [FIX] Errors in context are purged -- [FIX] Adds HEAD method in Static file serving -- [FIX] Refactors Static() file serving -- [FIX] Using keyed initialization to fix app-engine integration -- [FIX] Can't unmarshal JSON array, #63 -- [FIX] Renaming Context.Req to Context.Request -- [FIX] Check application/x-www-form-urlencoded when parsing form - - -## Gin 0.2b (Jul 08, 2014) -- [PERFORMANCE] Using sync.Pool to allocatio/gc overhead -- [NEW] Travis CI integration -- [NEW] Completely new logger -- [NEW] New API for serving static files. gin.Static() -- [NEW] gin.H() can be serialized into XML -- [NEW] Typed errors. Errors can be typed. Internet/external/custom. -- [NEW] Support for Godeps -- [NEW] Travis/Godocs badges in README -- [NEW] New Bind() and BindWith() methods for parsing request body. -- [NEW] Add Content.Copy() -- [NEW] Add context.LastError() -- [NEW] Add shortcut for OPTIONS HTTP method -- [FIX] Tons of README fixes -- [FIX] Header is written before body -- [FIX] BasicAuth() and changes API a little bit -- [FIX] Recovery() middleware only prints panics -- [FIX] Context.Get() does not panic anymore. Use MustGet() instead. -- [FIX] Multiple http.WriteHeader() in NotFound handlers -- [FIX] Engine.Run() panics if http server can't be set up -- [FIX] Crash when route path doesn't start with '/' -- [FIX] Do not update header when status code is negative -- [FIX] Setting response headers before calling WriteHeader in context.String() -- [FIX] Add MIT license -- [FIX] Changes behaviour of ErrorLogger() and Logger() diff --git a/vendor/github.com/gin-gonic/gin/CODE_OF_CONDUCT.md b/vendor/github.com/gin-gonic/gin/CODE_OF_CONDUCT.md deleted file mode 100644 index 4ea14f3..0000000 --- a/vendor/github.com/gin-gonic/gin/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,46 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at teamgingonic@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/gin-gonic/gin/CONTRIBUTING.md b/vendor/github.com/gin-gonic/gin/CONTRIBUTING.md deleted file mode 100644 index d1c723c..0000000 --- a/vendor/github.com/gin-gonic/gin/CONTRIBUTING.md +++ /dev/null @@ -1,13 +0,0 @@ -## Contributing - -- With issues: - - Use the search tool before opening a new issue. - - Please provide source code and commit sha if you found a bug. - - Review existing issues and provide feedback or react to them. - -- With pull requests: - - Open your pull request against `master` - - Your pull request should have no more than two commits, if not you should squash them. - - It should pass all tests in the available continuous integration systems such as GitHub Actions. - - You should add/modify tests to cover your proposed code changes. - - If your pull request contains a new feature, please document it on the README. diff --git a/vendor/github.com/gin-gonic/gin/LICENSE b/vendor/github.com/gin-gonic/gin/LICENSE deleted file mode 100644 index 1ff7f37..0000000 --- a/vendor/github.com/gin-gonic/gin/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Manuel Martínez-Almeida - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/gin-gonic/gin/Makefile b/vendor/github.com/gin-gonic/gin/Makefile deleted file mode 100644 index 5d55b44..0000000 --- a/vendor/github.com/gin-gonic/gin/Makefile +++ /dev/null @@ -1,77 +0,0 @@ -GO ?= go -GOFMT ?= gofmt "-s" -GO_VERSION=$(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2) -PACKAGES ?= $(shell $(GO) list ./...) -VETPACKAGES ?= $(shell $(GO) list ./... | grep -v /examples/) -GOFILES := $(shell find . -name "*.go") -TESTFOLDER := $(shell $(GO) list ./... | grep -E 'gin$$|binding$$|render$$' | grep -v examples) -TESTTAGS ?= "" - -.PHONY: test -test: - echo "mode: count" > coverage.out - for d in $(TESTFOLDER); do \ - $(GO) test -tags $(TESTTAGS) -v -covermode=count -coverprofile=profile.out $$d > tmp.out; \ - cat tmp.out; \ - if grep -q "^--- FAIL" tmp.out; then \ - rm tmp.out; \ - exit 1; \ - elif grep -q "build failed" tmp.out; then \ - rm tmp.out; \ - exit 1; \ - elif grep -q "setup failed" tmp.out; then \ - rm tmp.out; \ - exit 1; \ - fi; \ - if [ -f profile.out ]; then \ - cat profile.out | grep -v "mode:" >> coverage.out; \ - rm profile.out; \ - fi; \ - done - -.PHONY: fmt -fmt: - $(GOFMT) -w $(GOFILES) - -.PHONY: fmt-check -fmt-check: - @diff=$$($(GOFMT) -d $(GOFILES)); \ - if [ -n "$$diff" ]; then \ - echo "Please run 'make fmt' and commit the result:"; \ - echo "$${diff}"; \ - exit 1; \ - fi; - -vet: - $(GO) vet $(VETPACKAGES) - -.PHONY: lint -lint: - @hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u golang.org/x/lint/golint; \ - fi - for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done; - -.PHONY: misspell-check -misspell-check: - @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u github.com/client9/misspell/cmd/misspell; \ - fi - misspell -error $(GOFILES) - -.PHONY: misspell -misspell: - @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u github.com/client9/misspell/cmd/misspell; \ - fi - misspell -w $(GOFILES) - -.PHONY: tools -tools: - @if [ $(GO_VERSION) -gt 15 ]; then \ - $(GO) install golang.org/x/lint/golint@latest; \ - $(GO) install github.com/client9/misspell/cmd/misspell@latest; \ - elif [ $(GO_VERSION) -lt 16 ]; then \ - $(GO) install golang.org/x/lint/golint; \ - $(GO) install github.com/client9/misspell/cmd/misspell; \ - fi diff --git a/vendor/github.com/gin-gonic/gin/README.md b/vendor/github.com/gin-gonic/gin/README.md deleted file mode 100644 index 5cc8321..0000000 --- a/vendor/github.com/gin-gonic/gin/README.md +++ /dev/null @@ -1,2348 +0,0 @@ -# Gin Web Framework - - - -[![Build Status](https://github.com/gin-gonic/gin/workflows/Run%20Tests/badge.svg?branch=master)](https://github.com/gin-gonic/gin/actions?query=branch%3Amaster) -[![codecov](https://codecov.io/gh/gin-gonic/gin/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-gonic/gin) -[![Go Report Card](https://goreportcard.com/badge/github.com/gin-gonic/gin)](https://goreportcard.com/report/github.com/gin-gonic/gin) -[![GoDoc](https://pkg.go.dev/badge/github.com/gin-gonic/gin?status.svg)](https://pkg.go.dev/github.com/gin-gonic/gin?tab=doc) -[![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![Sourcegraph](https://sourcegraph.com/github.com/gin-gonic/gin/-/badge.svg)](https://sourcegraph.com/github.com/gin-gonic/gin?badge) -[![Open Source Helpers](https://www.codetriage.com/gin-gonic/gin/badges/users.svg)](https://www.codetriage.com/gin-gonic/gin) -[![Release](https://img.shields.io/github/release/gin-gonic/gin.svg?style=flat-square)](https://github.com/gin-gonic/gin/releases) -[![TODOs](https://badgen.net/https/api.tickgit.com/badgen/github.com/gin-gonic/gin)](https://www.tickgit.com/browse?repo=github.com/gin-gonic/gin) - -Gin is a web framework written in Go (Golang). It features a martini-like API with performance that is up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin. - - -## Contents - -- [Gin Web Framework](#gin-web-framework) - - [Contents](#contents) - - [Installation](#installation) - - [Quick start](#quick-start) - - [Benchmarks](#benchmarks) - - [Gin v1. stable](#gin-v1-stable) - - [Build with jsoniter/go-json](#build-with-json-replacement) - - [Build without `MsgPack` rendering feature](#build-without-msgpack-rendering-feature) - - [API Examples](#api-examples) - - [Using GET, POST, PUT, PATCH, DELETE and OPTIONS](#using-get-post-put-patch-delete-and-options) - - [Parameters in path](#parameters-in-path) - - [Querystring parameters](#querystring-parameters) - - [Multipart/Urlencoded Form](#multiparturlencoded-form) - - [Another example: query + post form](#another-example-query--post-form) - - [Map as querystring or postform parameters](#map-as-querystring-or-postform-parameters) - - [Upload files](#upload-files) - - [Single file](#single-file) - - [Multiple files](#multiple-files) - - [Grouping routes](#grouping-routes) - - [Blank Gin without middleware by default](#blank-gin-without-middleware-by-default) - - [Using middleware](#using-middleware) - - [How to write log file](#how-to-write-log-file) - - [Custom Log Format](#custom-log-format) - - [Controlling Log output coloring](#controlling-log-output-coloring) - - [Model binding and validation](#model-binding-and-validation) - - [Custom Validators](#custom-validators) - - [Only Bind Query String](#only-bind-query-string) - - [Bind Query String or Post Data](#bind-query-string-or-post-data) - - [Bind Uri](#bind-uri) - - [Bind Header](#bind-header) - - [Bind HTML checkboxes](#bind-html-checkboxes) - - [Multipart/Urlencoded binding](#multiparturlencoded-binding) - - [XML, JSON, YAML and ProtoBuf rendering](#xml-json-yaml-and-protobuf-rendering) - - [SecureJSON](#securejson) - - [JSONP](#jsonp) - - [AsciiJSON](#asciijson) - - [PureJSON](#purejson) - - [Serving static files](#serving-static-files) - - [Serving data from file](#serving-data-from-file) - - [Serving data from reader](#serving-data-from-reader) - - [HTML rendering](#html-rendering) - - [Custom Template renderer](#custom-template-renderer) - - [Custom Delimiters](#custom-delimiters) - - [Custom Template Funcs](#custom-template-funcs) - - [Multitemplate](#multitemplate) - - [Redirects](#redirects) - - [Custom Middleware](#custom-middleware) - - [Using BasicAuth() middleware](#using-basicauth-middleware) - - [Goroutines inside a middleware](#goroutines-inside-a-middleware) - - [Custom HTTP configuration](#custom-http-configuration) - - [Support Let's Encrypt](#support-lets-encrypt) - - [Run multiple service using Gin](#run-multiple-service-using-gin) - - [Graceful shutdown or restart](#graceful-shutdown-or-restart) - - [Third-party packages](#third-party-packages) - - [Manually](#manually) - - [Build a single binary with templates](#build-a-single-binary-with-templates) - - [Bind form-data request with custom struct](#bind-form-data-request-with-custom-struct) - - [Try to bind body into different structs](#try-to-bind-body-into-different-structs) - - [http2 server push](#http2-server-push) - - [Define format for the log of routes](#define-format-for-the-log-of-routes) - - [Set and get a cookie](#set-and-get-a-cookie) - - [Don't trust all proxies](#dont-trust-all-proxies) - - [Testing](#testing) - - [Users](#users) - -## Installation - -To install Gin package, you need to install Go and set your Go workspace first. - -1. You first need [Go](https://golang.org/) installed (**version 1.14+ is required**), then you can use the below Go command to install Gin. - -```sh -$ go get -u github.com/gin-gonic/gin -``` - -2. Import it in your code: - -```go -import "github.com/gin-gonic/gin" -``` - -3. (Optional) Import `net/http`. This is required for example if using constants such as `http.StatusOK`. - -```go -import "net/http" -``` - -## Quick start - -```sh -# assume the following codes in example.go file -$ cat example.go -``` - -```go -package main - -import ( - "net/http" - - "github.com/gin-gonic/gin" -) - -func main() { - r := gin.Default() - r.GET("/ping", func(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{ - "message": "pong", - }) - }) - r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080") -} -``` - -``` -# run example.go and visit 0.0.0.0:8080/ping (for windows "localhost:8080/ping") on browser -$ go run example.go -``` - -## Benchmarks - -Gin uses a custom version of [HttpRouter](https://github.com/julienschmidt/httprouter) - -[See all benchmarks](/BENCHMARKS.md) - -| Benchmark name | (1) | (2) | (3) | (4) | -| ------------------------------ | ---------:| ---------------:| ------------:| ---------------:| -| BenchmarkGin_GithubAll | **43550** | **27364 ns/op** | **0 B/op** | **0 allocs/op** | -| BenchmarkAce_GithubAll | 40543 | 29670 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkAero_GithubAll | 57632 | 20648 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkBear_GithubAll | 9234 | 216179 ns/op | 86448 B/op | 943 allocs/op | -| BenchmarkBeego_GithubAll | 7407 | 243496 ns/op | 71456 B/op | 609 allocs/op | -| BenchmarkBone_GithubAll | 420 | 2922835 ns/op | 720160 B/op | 8620 allocs/op | -| BenchmarkChi_GithubAll | 7620 | 238331 ns/op | 87696 B/op | 609 allocs/op | -| BenchmarkDenco_GithubAll | 18355 | 64494 ns/op | 20224 B/op | 167 allocs/op | -| BenchmarkEcho_GithubAll | 31251 | 38479 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkGocraftWeb_GithubAll | 4117 | 300062 ns/op | 131656 B/op | 1686 allocs/op | -| BenchmarkGoji_GithubAll | 3274 | 416158 ns/op | 56112 B/op | 334 allocs/op | -| BenchmarkGojiv2_GithubAll | 1402 | 870518 ns/op | 352720 B/op | 4321 allocs/op | -| BenchmarkGoJsonRest_GithubAll | 2976 | 401507 ns/op | 134371 B/op | 2737 allocs/op | -| BenchmarkGoRestful_GithubAll | 410 | 2913158 ns/op | 910144 B/op | 2938 allocs/op | -| BenchmarkGorillaMux_GithubAll | 346 | 3384987 ns/op | 251650 B/op | 1994 allocs/op | -| BenchmarkGowwwRouter_GithubAll | 10000 | 143025 ns/op | 72144 B/op | 501 allocs/op | -| BenchmarkHttpRouter_GithubAll | 55938 | 21360 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkHttpTreeMux_GithubAll | 10000 | 153944 ns/op | 65856 B/op | 671 allocs/op | -| BenchmarkKocha_GithubAll | 10000 | 106315 ns/op | 23304 B/op | 843 allocs/op | -| BenchmarkLARS_GithubAll | 47779 | 25084 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkMacaron_GithubAll | 3266 | 371907 ns/op | 149409 B/op | 1624 allocs/op | -| BenchmarkMartini_GithubAll | 331 | 3444706 ns/op | 226551 B/op | 2325 allocs/op | -| BenchmarkPat_GithubAll | 273 | 4381818 ns/op | 1483152 B/op | 26963 allocs/op | -| BenchmarkPossum_GithubAll | 10000 | 164367 ns/op | 84448 B/op | 609 allocs/op | -| BenchmarkR2router_GithubAll | 10000 | 160220 ns/op | 77328 B/op | 979 allocs/op | -| BenchmarkRivet_GithubAll | 14625 | 82453 ns/op | 16272 B/op | 167 allocs/op | -| BenchmarkTango_GithubAll | 6255 | 279611 ns/op | 63826 B/op | 1618 allocs/op | -| BenchmarkTigerTonic_GithubAll | 2008 | 687874 ns/op | 193856 B/op | 4474 allocs/op | -| BenchmarkTraffic_GithubAll | 355 | 3478508 ns/op | 820744 B/op | 14114 allocs/op | -| BenchmarkVulcan_GithubAll | 6885 | 193333 ns/op | 19894 B/op | 609 allocs/op | - -- (1): Total Repetitions achieved in constant time, higher means more confident result -- (2): Single Repetition Duration (ns/op), lower is better -- (3): Heap Memory (B/op), lower is better -- (4): Average Allocations per Repetition (allocs/op), lower is better - -## Gin v1. stable - -- [x] Zero allocation router. -- [x] Still the fastest http router and framework. From routing to writing. -- [x] Complete suite of unit tests. -- [x] Battle tested. -- [x] API frozen, new releases will not break your code. - -## Build with json replacement - -Gin uses `encoding/json` as default json package but you can change it by build from other tags. - -[jsoniter](https://github.com/json-iterator/go) -```sh -$ go build -tags=jsoniter . -``` -[go-json](https://github.com/goccy/go-json) -```sh -$ go build -tags=go_json . -``` - -## Build without `MsgPack` rendering feature - -Gin enables `MsgPack` rendering feature by default. But you can disable this feature by specifying `nomsgpack` build tag. - -```sh -$ go build -tags=nomsgpack . -``` - -This is useful to reduce the binary size of executable files. See the [detail information](https://github.com/gin-gonic/gin/pull/1852). - -## API Examples - -You can find a number of ready-to-run examples at [Gin examples repository](https://github.com/gin-gonic/examples). - -### Using GET, POST, PUT, PATCH, DELETE and OPTIONS - -```go -func main() { - // Creates a gin router with default middleware: - // logger and recovery (crash-free) middleware - router := gin.Default() - - router.GET("/someGet", getting) - router.POST("/somePost", posting) - router.PUT("/somePut", putting) - router.DELETE("/someDelete", deleting) - router.PATCH("/somePatch", patching) - router.HEAD("/someHead", head) - router.OPTIONS("/someOptions", options) - - // By default it serves on :8080 unless a - // PORT environment variable was defined. - router.Run() - // router.Run(":3000") for a hard coded port -} -``` - -### Parameters in path - -```go -func main() { - router := gin.Default() - - // This handler will match /user/john but will not match /user/ or /user - router.GET("/user/:name", func(c *gin.Context) { - name := c.Param("name") - c.String(http.StatusOK, "Hello %s", name) - }) - - // However, this one will match /user/john/ and also /user/john/send - // If no other routers match /user/john, it will redirect to /user/john/ - router.GET("/user/:name/*action", func(c *gin.Context) { - name := c.Param("name") - action := c.Param("action") - message := name + " is " + action - c.String(http.StatusOK, message) - }) - - // For each matched request Context will hold the route definition - router.POST("/user/:name/*action", func(c *gin.Context) { - b := c.FullPath() == "/user/:name/*action" // true - c.String(http.StatusOK, "%t", b) - }) - - // This handler will add a new router for /user/groups. - // Exact routes are resolved before param routes, regardless of the order they were defined. - // Routes starting with /user/groups are never interpreted as /user/:name/... routes - router.GET("/user/groups", func(c *gin.Context) { - c.String(http.StatusOK, "The available groups are [...]") - }) - - router.Run(":8080") -} -``` - -### Querystring parameters - -```go -func main() { - router := gin.Default() - - // Query string parameters are parsed using the existing underlying request object. - // The request responds to a url matching: /welcome?firstname=Jane&lastname=Doe - router.GET("/welcome", func(c *gin.Context) { - firstname := c.DefaultQuery("firstname", "Guest") - lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname") - - c.String(http.StatusOK, "Hello %s %s", firstname, lastname) - }) - router.Run(":8080") -} -``` - -### Multipart/Urlencoded Form - -```go -func main() { - router := gin.Default() - - router.POST("/form_post", func(c *gin.Context) { - message := c.PostForm("message") - nick := c.DefaultPostForm("nick", "anonymous") - - c.JSON(http.StatusOK, gin.H{ - "status": "posted", - "message": message, - "nick": nick, - }) - }) - router.Run(":8080") -} -``` - -### Another example: query + post form - -``` -POST /post?id=1234&page=1 HTTP/1.1 -Content-Type: application/x-www-form-urlencoded - -name=manu&message=this_is_great -``` - -```go -func main() { - router := gin.Default() - - router.POST("/post", func(c *gin.Context) { - - id := c.Query("id") - page := c.DefaultQuery("page", "0") - name := c.PostForm("name") - message := c.PostForm("message") - - fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message) - }) - router.Run(":8080") -} -``` - -``` -id: 1234; page: 1; name: manu; message: this_is_great -``` - -### Map as querystring or postform parameters - -``` -POST /post?ids[a]=1234&ids[b]=hello HTTP/1.1 -Content-Type: application/x-www-form-urlencoded - -names[first]=thinkerou&names[second]=tianou -``` - -```go -func main() { - router := gin.Default() - - router.POST("/post", func(c *gin.Context) { - - ids := c.QueryMap("ids") - names := c.PostFormMap("names") - - fmt.Printf("ids: %v; names: %v", ids, names) - }) - router.Run(":8080") -} -``` - -``` -ids: map[b:hello a:1234]; names: map[second:tianou first:thinkerou] -``` - -### Upload files - -#### Single file - -References issue [#774](https://github.com/gin-gonic/gin/issues/774) and detail [example code](https://github.com/gin-gonic/examples/tree/master/upload-file/single). - -`file.Filename` **SHOULD NOT** be trusted. See [`Content-Disposition` on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#Directives) and [#1693](https://github.com/gin-gonic/gin/issues/1693) - -> The filename is always optional and must not be used blindly by the application: path information should be stripped, and conversion to the server file system rules should be done. - -```go -func main() { - router := gin.Default() - // Set a lower memory limit for multipart forms (default is 32 MiB) - router.MaxMultipartMemory = 8 << 20 // 8 MiB - router.POST("/upload", func(c *gin.Context) { - // Single file - file, _ := c.FormFile("file") - log.Println(file.Filename) - - // Upload the file to specific dst. - c.SaveUploadedFile(file, dst) - - c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) - }) - router.Run(":8080") -} -``` - -How to `curl`: - -```bash -curl -X POST http://localhost:8080/upload \ - -F "file=@/Users/appleboy/test.zip" \ - -H "Content-Type: multipart/form-data" -``` - -#### Multiple files - -See the detail [example code](https://github.com/gin-gonic/examples/tree/master/upload-file/multiple). - -```go -func main() { - router := gin.Default() - // Set a lower memory limit for multipart forms (default is 32 MiB) - router.MaxMultipartMemory = 8 << 20 // 8 MiB - router.POST("/upload", func(c *gin.Context) { - // Multipart form - form, _ := c.MultipartForm() - files := form.File["upload[]"] - - for _, file := range files { - log.Println(file.Filename) - - // Upload the file to specific dst. - c.SaveUploadedFile(file, dst) - } - c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files))) - }) - router.Run(":8080") -} -``` - -How to `curl`: - -```bash -curl -X POST http://localhost:8080/upload \ - -F "upload[]=@/Users/appleboy/test1.zip" \ - -F "upload[]=@/Users/appleboy/test2.zip" \ - -H "Content-Type: multipart/form-data" -``` - -### Grouping routes - -```go -func main() { - router := gin.Default() - - // Simple group: v1 - v1 := router.Group("/v1") - { - v1.POST("/login", loginEndpoint) - v1.POST("/submit", submitEndpoint) - v1.POST("/read", readEndpoint) - } - - // Simple group: v2 - v2 := router.Group("/v2") - { - v2.POST("/login", loginEndpoint) - v2.POST("/submit", submitEndpoint) - v2.POST("/read", readEndpoint) - } - - router.Run(":8080") -} -``` - -### Blank Gin without middleware by default - -Use - -```go -r := gin.New() -``` - -instead of - -```go -// Default With the Logger and Recovery middleware already attached -r := gin.Default() -``` - - -### Using middleware -```go -func main() { - // Creates a router without any middleware by default - r := gin.New() - - // Global middleware - // Logger middleware will write the logs to gin.DefaultWriter even if you set with GIN_MODE=release. - // By default gin.DefaultWriter = os.Stdout - r.Use(gin.Logger()) - - // Recovery middleware recovers from any panics and writes a 500 if there was one. - r.Use(gin.Recovery()) - - // Per route middleware, you can add as many as you desire. - r.GET("/benchmark", MyBenchLogger(), benchEndpoint) - - // Authorization group - // authorized := r.Group("/", AuthRequired()) - // exactly the same as: - authorized := r.Group("/") - // per group middleware! in this case we use the custom created - // AuthRequired() middleware just in the "authorized" group. - authorized.Use(AuthRequired()) - { - authorized.POST("/login", loginEndpoint) - authorized.POST("/submit", submitEndpoint) - authorized.POST("/read", readEndpoint) - - // nested group - testing := authorized.Group("testing") - // visit 0.0.0.0:8080/testing/analytics - testing.GET("/analytics", analyticsEndpoint) - } - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - -### Custom Recovery behavior -```go -func main() { - // Creates a router without any middleware by default - r := gin.New() - - // Global middleware - // Logger middleware will write the logs to gin.DefaultWriter even if you set with GIN_MODE=release. - // By default gin.DefaultWriter = os.Stdout - r.Use(gin.Logger()) - - // Recovery middleware recovers from any panics and writes a 500 if there was one. - r.Use(gin.CustomRecovery(func(c *gin.Context, recovered interface{}) { - if err, ok := recovered.(string); ok { - c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) - } - c.AbortWithStatus(http.StatusInternalServerError) - })) - - r.GET("/panic", func(c *gin.Context) { - // panic with a string -- the custom middleware could save this to a database or report it to the user - panic("foo") - }) - - r.GET("/", func(c *gin.Context) { - c.String(http.StatusOK, "ohai") - }) - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - -### How to write log file -```go -func main() { - // Disable Console Color, you don't need console color when writing the logs to file. - gin.DisableConsoleColor() - - // Logging to a file. - f, _ := os.Create("gin.log") - gin.DefaultWriter = io.MultiWriter(f) - - // Use the following code if you need to write the logs to file and console at the same time. - // gin.DefaultWriter = io.MultiWriter(f, os.Stdout) - - router := gin.Default() - router.GET("/ping", func(c *gin.Context) { - c.String(http.StatusOK, "pong") - }) - -    router.Run(":8080") -} -``` - -### Custom Log Format -```go -func main() { - router := gin.New() - - // LoggerWithFormatter middleware will write the logs to gin.DefaultWriter - // By default gin.DefaultWriter = os.Stdout - router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { - - // your custom format - return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n", - param.ClientIP, - param.TimeStamp.Format(time.RFC1123), - param.Method, - param.Path, - param.Request.Proto, - param.StatusCode, - param.Latency, - param.Request.UserAgent(), - param.ErrorMessage, - ) - })) - router.Use(gin.Recovery()) - - router.GET("/ping", func(c *gin.Context) { - c.String(http.StatusOK, "pong") - }) - - router.Run(":8080") -} -``` - -**Sample Output** -``` -::1 - [Fri, 07 Dec 2018 17:04:38 JST] "GET /ping HTTP/1.1 200 122.767µs "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36" " -``` - -### Controlling Log output coloring - -By default, logs output on console should be colorized depending on the detected TTY. - -Never colorize logs: - -```go -func main() { - // Disable log's color - gin.DisableConsoleColor() - - // Creates a gin router with default middleware: - // logger and recovery (crash-free) middleware - router := gin.Default() - - router.GET("/ping", func(c *gin.Context) { - c.String(http.StatusOK, "pong") - }) - - router.Run(":8080") -} -``` - -Always colorize logs: - -```go -func main() { - // Force log's color - gin.ForceConsoleColor() - - // Creates a gin router with default middleware: - // logger and recovery (crash-free) middleware - router := gin.Default() - - router.GET("/ping", func(c *gin.Context) { - c.String(http.StatusOK, "pong") - }) - - router.Run(":8080") -} -``` - -### Model binding and validation - -To bind a request body into a type, use model binding. We currently support binding of JSON, XML, YAML, TOML and standard form values (foo=bar&boo=baz). - -Gin uses [**go-playground/validator/v10**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](https://godoc.org/github.com/go-playground/validator#hdr-Baked_In_Validators_and_Tags). - -Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set `json:"fieldname"`. - -Also, Gin provides two sets of methods for binding: -- **Type** - Must bind - - **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery`, `BindYAML`, `BindHeader`, `BindTOML` - - **Behavior** - These methods use `MustBindWith` under the hood. If there is a binding error, the request is aborted with `c.AbortWithError(400, err).SetType(ErrorTypeBind)`. This sets the response status code to 400 and the `Content-Type` header is set to `text/plain; charset=utf-8`. Note that if you try to set the response code after this, it will result in a warning `[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422`. If you wish to have greater control over the behavior, consider using the `ShouldBind` equivalent method. -- **Type** - Should bind - - **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery`, `ShouldBindYAML`, `ShouldBindHeader`, `ShouldBindTOML`, - - **Behavior** - These methods use `ShouldBindWith` under the hood. If there is a binding error, the error is returned and it is the developer's responsibility to handle the request and error appropriately. - -When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use `MustBindWith` or `ShouldBindWith`. - -You can also specify that specific fields are required. If a field is decorated with `binding:"required"` and has a empty value when binding, an error will be returned. - -```go -// Binding from JSON -type Login struct { - User string `form:"user" json:"user" xml:"user" binding:"required"` - Password string `form:"password" json:"password" xml:"password" binding:"required"` -} - -func main() { - router := gin.Default() - - // Example for binding JSON ({"user": "manu", "password": "123"}) - router.POST("/loginJSON", func(c *gin.Context) { - var json Login - if err := c.ShouldBindJSON(&json); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - if json.User != "manu" || json.Password != "123" { - c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) - return - } - - c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) - }) - - // Example for binding XML ( - // - // - // manu - // 123 - // ) - router.POST("/loginXML", func(c *gin.Context) { - var xml Login - if err := c.ShouldBindXML(&xml); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - if xml.User != "manu" || xml.Password != "123" { - c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) - return - } - - c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) - }) - - // Example for binding a HTML form (user=manu&password=123) - router.POST("/loginForm", func(c *gin.Context) { - var form Login - // This will infer what binder to use depending on the content-type header. - if err := c.ShouldBind(&form); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - if form.User != "manu" || form.Password != "123" { - c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) - return - } - - c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) - }) - - // Listen and serve on 0.0.0.0:8080 - router.Run(":8080") -} -``` - -**Sample request** -```shell -$ curl -v -X POST \ - http://localhost:8080/loginJSON \ - -H 'content-type: application/json' \ - -d '{ "user": "manu" }' -> POST /loginJSON HTTP/1.1 -> Host: localhost:8080 -> User-Agent: curl/7.51.0 -> Accept: */* -> content-type: application/json -> Content-Length: 18 -> -* upload completely sent off: 18 out of 18 bytes -< HTTP/1.1 400 Bad Request -< Content-Type: application/json; charset=utf-8 -< Date: Fri, 04 Aug 2017 03:51:31 GMT -< Content-Length: 100 -< -{"error":"Key: 'Login.Password' Error:Field validation for 'Password' failed on the 'required' tag"} -``` - -**Skip validate** - -When running the above example using the above the `curl` command, it returns error. Because the example use `binding:"required"` for `Password`. If use `binding:"-"` for `Password`, then it will not return error when running the above example again. - -### Custom Validators - -It is also possible to register custom validators. See the [example code](https://github.com/gin-gonic/examples/tree/master/custom-validation/server.go). - -```go -package main - -import ( - "net/http" - "time" - - "github.com/gin-gonic/gin" - "github.com/gin-gonic/gin/binding" - "github.com/go-playground/validator/v10" -) - -// Booking contains binded and validated data. -type Booking struct { - CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"` - CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"` -} - -var bookableDate validator.Func = func(fl validator.FieldLevel) bool { - date, ok := fl.Field().Interface().(time.Time) - if ok { - today := time.Now() - if today.After(date) { - return false - } - } - return true -} - -func main() { - route := gin.Default() - - if v, ok := binding.Validator.Engine().(*validator.Validate); ok { - v.RegisterValidation("bookabledate", bookableDate) - } - - route.GET("/bookable", getBookable) - route.Run(":8085") -} - -func getBookable(c *gin.Context) { - var b Booking - if err := c.ShouldBindWith(&b, binding.Query); err == nil { - c.JSON(http.StatusOK, gin.H{"message": "Booking dates are valid!"}) - } else { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - } -} -``` - -```console -$ curl "localhost:8085/bookable?check_in=2030-04-16&check_out=2030-04-17" -{"message":"Booking dates are valid!"} - -$ curl "localhost:8085/bookable?check_in=2030-03-10&check_out=2030-03-09" -{"error":"Key: 'Booking.CheckOut' Error:Field validation for 'CheckOut' failed on the 'gtfield' tag"} - -$ curl "localhost:8085/bookable?check_in=2000-03-09&check_out=2000-03-10" -{"error":"Key: 'Booking.CheckIn' Error:Field validation for 'CheckIn' failed on the 'bookabledate' tag"}% -``` - -[Struct level validations](https://github.com/go-playground/validator/releases/tag/v8.7) can also be registered this way. -See the [struct-lvl-validation example](https://github.com/gin-gonic/examples/tree/master/struct-lvl-validations) to learn more. - -### Only Bind Query String - -`ShouldBindQuery` function only binds the query params and not the post data. See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-315953017). - -```go -package main - -import ( - "log" - "net/http" - - "github.com/gin-gonic/gin" -) - -type Person struct { - Name string `form:"name"` - Address string `form:"address"` -} - -func main() { - route := gin.Default() - route.Any("/testing", startPage) - route.Run(":8085") -} - -func startPage(c *gin.Context) { - var person Person - if c.ShouldBindQuery(&person) == nil { - log.Println("====== Only Bind By Query String ======") - log.Println(person.Name) - log.Println(person.Address) - } - c.String(http.StatusOK, "Success") -} - -``` - -### Bind Query String or Post Data - -See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-264681292). - -```go -package main - -import ( - "log" - "net/http" - "time" - - "github.com/gin-gonic/gin" -) - -type Person struct { - Name string `form:"name"` - Address string `form:"address"` - Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"` - CreateTime time.Time `form:"createTime" time_format:"unixNano"` - UnixTime time.Time `form:"unixTime" time_format:"unix"` -} - -func main() { - route := gin.Default() - route.GET("/testing", startPage) - route.Run(":8085") -} - -func startPage(c *gin.Context) { - var person Person - // If `GET`, only `Form` binding engine (`query`) used. - // If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`). - // See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L88 - if c.ShouldBind(&person) == nil { - log.Println(person.Name) - log.Println(person.Address) - log.Println(person.Birthday) - log.Println(person.CreateTime) - log.Println(person.UnixTime) - } - - c.String(http.StatusOK, "Success") -} -``` - -Test it with: -```sh -$ curl -X GET "localhost:8085/testing?name=appleboy&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033" -``` - -### Bind Uri - -See the [detail information](https://github.com/gin-gonic/gin/issues/846). - -```go -package main - -import ( - "net/http" - - "github.com/gin-gonic/gin" -) - -type Person struct { - ID string `uri:"id" binding:"required,uuid"` - Name string `uri:"name" binding:"required"` -} - -func main() { - route := gin.Default() - route.GET("/:name/:id", func(c *gin.Context) { - var person Person - if err := c.ShouldBindUri(&person); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()}) - return - } - c.JSON(http.StatusOK, gin.H{"name": person.Name, "uuid": person.ID}) - }) - route.Run(":8088") -} -``` - -Test it with: -```sh -$ curl -v localhost:8088/thinkerou/987fbc97-4bed-5078-9f07-9141ba07c9f3 -$ curl -v localhost:8088/thinkerou/not-uuid -``` - -### Bind Header - -```go -package main - -import ( - "fmt" - "net/http" - - "github.com/gin-gonic/gin" -) - -type testHeader struct { - Rate int `header:"Rate"` - Domain string `header:"Domain"` -} - -func main() { - r := gin.Default() - r.GET("/", func(c *gin.Context) { - h := testHeader{} - - if err := c.ShouldBindHeader(&h); err != nil { - c.JSON(http.StatusOK, err) - } - - fmt.Printf("%#v\n", h) - c.JSON(http.StatusOK, gin.H{"Rate": h.Rate, "Domain": h.Domain}) - }) - - r.Run() - -// client -// curl -H "rate:300" -H "domain:music" 127.0.0.1:8080/ -// output -// {"Domain":"music","Rate":300} -} -``` - -### Bind HTML checkboxes - -See the [detail information](https://github.com/gin-gonic/gin/issues/129#issuecomment-124260092) - -main.go - -```go -... - -type myForm struct { - Colors []string `form:"colors[]"` -} - -... - -func formHandler(c *gin.Context) { - var fakeForm myForm - c.ShouldBind(&fakeForm) - c.JSON(http.StatusOK, gin.H{"color": fakeForm.Colors}) -} - -... - -``` - -form.html - -```html -
-

Check some colors

- - - - - - - -
-``` - -result: - -``` -{"color":["red","green","blue"]} -``` - -### Multipart/Urlencoded binding - -```go -type ProfileForm struct { - Name string `form:"name" binding:"required"` - Avatar *multipart.FileHeader `form:"avatar" binding:"required"` - - // or for multiple files - // Avatars []*multipart.FileHeader `form:"avatar" binding:"required"` -} - -func main() { - router := gin.Default() - router.POST("/profile", func(c *gin.Context) { - // you can bind multipart form with explicit binding declaration: - // c.ShouldBindWith(&form, binding.Form) - // or you can simply use autobinding with ShouldBind method: - var form ProfileForm - // in this case proper binding will be automatically selected - if err := c.ShouldBind(&form); err != nil { - c.String(http.StatusBadRequest, "bad request") - return - } - - err := c.SaveUploadedFile(form.Avatar, form.Avatar.Filename) - if err != nil { - c.String(http.StatusInternalServerError, "unknown error") - return - } - - // db.Save(&form) - - c.String(http.StatusOK, "ok") - }) - router.Run(":8080") -} -``` - -Test it with: -```sh -$ curl -X POST -v --form name=user --form "avatar=@./avatar.png" http://localhost:8080/profile -``` - -### XML, JSON, YAML and ProtoBuf rendering - -```go -func main() { - r := gin.Default() - - // gin.H is a shortcut for map[string]interface{} - r.GET("/someJSON", func(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) - }) - - r.GET("/moreJSON", func(c *gin.Context) { - // You also can use a struct - var msg struct { - Name string `json:"user"` - Message string - Number int - } - msg.Name = "Lena" - msg.Message = "hey" - msg.Number = 123 - // Note that msg.Name becomes "user" in the JSON - // Will output : {"user": "Lena", "Message": "hey", "Number": 123} - c.JSON(http.StatusOK, msg) - }) - - r.GET("/someXML", func(c *gin.Context) { - c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) - }) - - r.GET("/someYAML", func(c *gin.Context) { - c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) - }) - - r.GET("/someProtoBuf", func(c *gin.Context) { - reps := []int64{int64(1), int64(2)} - label := "test" - // The specific definition of protobuf is written in the testdata/protoexample file. - data := &protoexample.Test{ - Label: &label, - Reps: reps, - } - // Note that data becomes binary data in the response - // Will output protoexample.Test protobuf serialized data - c.ProtoBuf(http.StatusOK, data) - }) - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - -#### SecureJSON - -Using SecureJSON to prevent json hijacking. Default prepends `"while(1),"` to response body if the given struct is array values. - -```go -func main() { - r := gin.Default() - - // You can also use your own secure json prefix - // r.SecureJsonPrefix(")]}',\n") - - r.GET("/someJSON", func(c *gin.Context) { - names := []string{"lena", "austin", "foo"} - - // Will output : while(1);["lena","austin","foo"] - c.SecureJSON(http.StatusOK, names) - }) - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` -#### JSONP - -Using JSONP to request data from a server in a different domain. Add callback to response body if the query parameter callback exists. - -```go -func main() { - r := gin.Default() - - r.GET("/JSONP", func(c *gin.Context) { - data := gin.H{ - "foo": "bar", - } - - //callback is x - // Will output : x({\"foo\":\"bar\"}) - c.JSONP(http.StatusOK, data) - }) - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") - - // client - // curl http://127.0.0.1:8080/JSONP?callback=x -} -``` - -#### AsciiJSON - -Using AsciiJSON to Generates ASCII-only JSON with escaped non-ASCII characters. - -```go -func main() { - r := gin.Default() - - r.GET("/someJSON", func(c *gin.Context) { - data := gin.H{ - "lang": "GO语言", - "tag": "
", - } - - // will output : {"lang":"GO\u8bed\u8a00","tag":"\u003cbr\u003e"} - c.AsciiJSON(http.StatusOK, data) - }) - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - -#### PureJSON - -Normally, JSON replaces special HTML characters with their unicode entities, e.g. `<` becomes `\u003c`. If you want to encode such characters literally, you can use PureJSON instead. -This feature is unavailable in Go 1.6 and lower. - -```go -func main() { - r := gin.Default() - - // Serves unicode entities - r.GET("/json", func(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{ - "html": "Hello, world!", - }) - }) - - // Serves literal characters - r.GET("/purejson", func(c *gin.Context) { - c.PureJSON(http.StatusOK, gin.H{ - "html": "Hello, world!", - }) - }) - - // listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - -### Serving static files - -```go -func main() { - router := gin.Default() - router.Static("/assets", "./assets") - router.StaticFS("/more_static", http.Dir("my_file_system")) - router.StaticFile("/favicon.ico", "./resources/favicon.ico") - router.StaticFileFS("/more_favicon.ico", "more_favicon.ico", http.Dir("my_file_system")) - - // Listen and serve on 0.0.0.0:8080 - router.Run(":8080") -} -``` - -### Serving data from file - -```go -func main() { - router := gin.Default() - - router.GET("/local/file", func(c *gin.Context) { - c.File("local/file.go") - }) - - var fs http.FileSystem = // ... - router.GET("/fs/file", func(c *gin.Context) { - c.FileFromFS("fs/file.go", fs) - }) -} - -``` - -### Serving data from reader - -```go -func main() { - router := gin.Default() - router.GET("/someDataFromReader", func(c *gin.Context) { - response, err := http.Get("https://raw.githubusercontent.com/gin-gonic/logo/master/color.png") - if err != nil || response.StatusCode != http.StatusOK { - c.Status(http.StatusServiceUnavailable) - return - } - - reader := response.Body - defer reader.Close() - contentLength := response.ContentLength - contentType := response.Header.Get("Content-Type") - - extraHeaders := map[string]string{ - "Content-Disposition": `attachment; filename="gopher.png"`, - } - - c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders) - }) - router.Run(":8080") -} -``` - -### HTML rendering - -Using LoadHTMLGlob() or LoadHTMLFiles() - -```go -func main() { - router := gin.Default() - router.LoadHTMLGlob("templates/*") - //router.LoadHTMLFiles("templates/template1.html", "templates/template2.html") - router.GET("/index", func(c *gin.Context) { - c.HTML(http.StatusOK, "index.tmpl", gin.H{ - "title": "Main website", - }) - }) - router.Run(":8080") -} -``` - -templates/index.tmpl - -```html - -

- {{ .title }} -

- -``` - -Using templates with same name in different directories - -```go -func main() { - router := gin.Default() - router.LoadHTMLGlob("templates/**/*") - router.GET("/posts/index", func(c *gin.Context) { - c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{ - "title": "Posts", - }) - }) - router.GET("/users/index", func(c *gin.Context) { - c.HTML(http.StatusOK, "users/index.tmpl", gin.H{ - "title": "Users", - }) - }) - router.Run(":8080") -} -``` - -templates/posts/index.tmpl - -```html -{{ define "posts/index.tmpl" }} -

- {{ .title }} -

-

Using posts/index.tmpl

- -{{ end }} -``` - -templates/users/index.tmpl - -```html -{{ define "users/index.tmpl" }} -

- {{ .title }} -

-

Using users/index.tmpl

- -{{ end }} -``` - -#### Custom Template renderer - -You can also use your own html template render - -```go -import "html/template" - -func main() { - router := gin.Default() - html := template.Must(template.ParseFiles("file1", "file2")) - router.SetHTMLTemplate(html) - router.Run(":8080") -} -``` - -#### Custom Delimiters - -You may use custom delims - -```go - r := gin.Default() - r.Delims("{[{", "}]}") - r.LoadHTMLGlob("/path/to/templates") -``` - -#### Custom Template Funcs - -See the detail [example code](https://github.com/gin-gonic/examples/tree/master/template). - -main.go - -```go -import ( - "fmt" - "html/template" - "net/http" - "time" - - "github.com/gin-gonic/gin" -) - -func formatAsDate(t time.Time) string { - year, month, day := t.Date() - return fmt.Sprintf("%d/%02d/%02d", year, month, day) -} - -func main() { - router := gin.Default() - router.Delims("{[{", "}]}") - router.SetFuncMap(template.FuncMap{ - "formatAsDate": formatAsDate, - }) - router.LoadHTMLFiles("./testdata/template/raw.tmpl") - - router.GET("/raw", func(c *gin.Context) { - c.HTML(http.StatusOK, "raw.tmpl", gin.H{ - "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC), - }) - }) - - router.Run(":8080") -} - -``` - -raw.tmpl - -```html -Date: {[{.now | formatAsDate}]} -``` - -Result: -``` -Date: 2017/07/01 -``` - -### Multitemplate - -Gin allow by default use only one html.Template. Check [a multitemplate render](https://github.com/gin-contrib/multitemplate) for using features like go 1.6 `block template`. - -### Redirects - -Issuing a HTTP redirect is easy. Both internal and external locations are supported. - -```go -r.GET("/test", func(c *gin.Context) { - c.Redirect(http.StatusMovedPermanently, "http://www.google.com/") -}) -``` - -Issuing a HTTP redirect from POST. Refer to issue: [#444](https://github.com/gin-gonic/gin/issues/444) -```go -r.POST("/test", func(c *gin.Context) { - c.Redirect(http.StatusFound, "/foo") -}) -``` - -Issuing a Router redirect, use `HandleContext` like below. - -``` go -r.GET("/test", func(c *gin.Context) { - c.Request.URL.Path = "/test2" - r.HandleContext(c) -}) -r.GET("/test2", func(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{"hello": "world"}) -}) -``` - - -### Custom Middleware - -```go -func Logger() gin.HandlerFunc { - return func(c *gin.Context) { - t := time.Now() - - // Set example variable - c.Set("example", "12345") - - // before request - - c.Next() - - // after request - latency := time.Since(t) - log.Print(latency) - - // access the status we are sending - status := c.Writer.Status() - log.Println(status) - } -} - -func main() { - r := gin.New() - r.Use(Logger()) - - r.GET("/test", func(c *gin.Context) { - example := c.MustGet("example").(string) - - // it would print: "12345" - log.Println(example) - }) - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - -### Using BasicAuth() middleware - -```go -// simulate some private data -var secrets = gin.H{ - "foo": gin.H{"email": "foo@bar.com", "phone": "123433"}, - "austin": gin.H{"email": "austin@example.com", "phone": "666"}, - "lena": gin.H{"email": "lena@guapa.com", "phone": "523443"}, -} - -func main() { - r := gin.Default() - - // Group using gin.BasicAuth() middleware - // gin.Accounts is a shortcut for map[string]string - authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{ - "foo": "bar", - "austin": "1234", - "lena": "hello2", - "manu": "4321", - })) - - // /admin/secrets endpoint - // hit "localhost:8080/admin/secrets - authorized.GET("/secrets", func(c *gin.Context) { - // get user, it was set by the BasicAuth middleware - user := c.MustGet(gin.AuthUserKey).(string) - if secret, ok := secrets[user]; ok { - c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret}) - } else { - c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("}) - } - }) - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - -### Goroutines inside a middleware - -When starting new Goroutines inside a middleware or handler, you **SHOULD NOT** use the original context inside it, you have to use a read-only copy. - -```go -func main() { - r := gin.Default() - - r.GET("/long_async", func(c *gin.Context) { - // create copy to be used inside the goroutine - cCp := c.Copy() - go func() { - // simulate a long task with time.Sleep(). 5 seconds - time.Sleep(5 * time.Second) - - // note that you are using the copied context "cCp", IMPORTANT - log.Println("Done! in path " + cCp.Request.URL.Path) - }() - }) - - r.GET("/long_sync", func(c *gin.Context) { - // simulate a long task with time.Sleep(). 5 seconds - time.Sleep(5 * time.Second) - - // since we are NOT using a goroutine, we do not have to copy the context - log.Println("Done! in path " + c.Request.URL.Path) - }) - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - -### Custom HTTP configuration - -Use `http.ListenAndServe()` directly, like this: - -```go -func main() { - router := gin.Default() - http.ListenAndServe(":8080", router) -} -``` -or - -```go -func main() { - router := gin.Default() - - s := &http.Server{ - Addr: ":8080", - Handler: router, - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, - MaxHeaderBytes: 1 << 20, - } - s.ListenAndServe() -} -``` - -### Support Let's Encrypt - -example for 1-line LetsEncrypt HTTPS servers. - -```go -package main - -import ( - "log" - "net/http" - - "github.com/gin-gonic/autotls" - "github.com/gin-gonic/gin" -) - -func main() { - r := gin.Default() - - // Ping handler - r.GET("/ping", func(c *gin.Context) { - c.String(http.StatusOK, "pong") - }) - - log.Fatal(autotls.Run(r, "example1.com", "example2.com")) -} -``` - -example for custom autocert manager. - -```go -package main - -import ( - "log" - "net/http" - - "github.com/gin-gonic/autotls" - "github.com/gin-gonic/gin" - "golang.org/x/crypto/acme/autocert" -) - -func main() { - r := gin.Default() - - // Ping handler - r.GET("/ping", func(c *gin.Context) { - c.String(http.StatusOK, "pong") - }) - - m := autocert.Manager{ - Prompt: autocert.AcceptTOS, - HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"), - Cache: autocert.DirCache("/var/www/.cache"), - } - - log.Fatal(autotls.RunWithManager(r, &m)) -} -``` - -### Run multiple service using Gin - -See the [question](https://github.com/gin-gonic/gin/issues/346) and try the following example: - -```go -package main - -import ( - "log" - "net/http" - "time" - - "github.com/gin-gonic/gin" - "golang.org/x/sync/errgroup" -) - -var ( - g errgroup.Group -) - -func router01() http.Handler { - e := gin.New() - e.Use(gin.Recovery()) - e.GET("/", func(c *gin.Context) { - c.JSON( - http.StatusOK, - gin.H{ - "code": http.StatusOK, - "error": "Welcome server 01", - }, - ) - }) - - return e -} - -func router02() http.Handler { - e := gin.New() - e.Use(gin.Recovery()) - e.GET("/", func(c *gin.Context) { - c.JSON( - http.StatusOK, - gin.H{ - "code": http.StatusOK, - "error": "Welcome server 02", - }, - ) - }) - - return e -} - -func main() { - server01 := &http.Server{ - Addr: ":8080", - Handler: router01(), - ReadTimeout: 5 * time.Second, - WriteTimeout: 10 * time.Second, - } - - server02 := &http.Server{ - Addr: ":8081", - Handler: router02(), - ReadTimeout: 5 * time.Second, - WriteTimeout: 10 * time.Second, - } - - g.Go(func() error { - err := server01.ListenAndServe() - if err != nil && err != http.ErrServerClosed { - log.Fatal(err) - } - return err - }) - - g.Go(func() error { - err := server02.ListenAndServe() - if err != nil && err != http.ErrServerClosed { - log.Fatal(err) - } - return err - }) - - if err := g.Wait(); err != nil { - log.Fatal(err) - } -} -``` - -### Graceful shutdown or restart - -There are a few approaches you can use to perform a graceful shutdown or restart. You can make use of third-party packages specifically built for that, or you can manually do the same with the functions and methods from the built-in packages. - -#### Third-party packages - -We can use [fvbock/endless](https://github.com/fvbock/endless) to replace the default `ListenAndServe`. Refer to issue [#296](https://github.com/gin-gonic/gin/issues/296) for more details. - -```go -router := gin.Default() -router.GET("/", handler) -// [...] -endless.ListenAndServe(":4242", router) -``` - -Alternatives: - -* [manners](https://github.com/braintree/manners): A polite Go HTTP server that shuts down gracefully. -* [graceful](https://github.com/tylerb/graceful): Graceful is a Go package enabling graceful shutdown of an http.Handler server. -* [grace](https://github.com/facebookgo/grace): Graceful restart & zero downtime deploy for Go servers. - -#### Manually - -In case you are using Go 1.8 or a later version, you may not need to use those libraries. Consider using `http.Server`'s built-in [Shutdown()](https://golang.org/pkg/net/http/#Server.Shutdown) method for graceful shutdowns. The example below describes its usage, and we've got more examples using gin [here](https://github.com/gin-gonic/examples/tree/master/graceful-shutdown). - -```go -// +build go1.8 - -package main - -import ( - "context" - "log" - "net/http" - "os" - "os/signal" - "syscall" - "time" - - "github.com/gin-gonic/gin" -) - -func main() { - router := gin.Default() - router.GET("/", func(c *gin.Context) { - time.Sleep(5 * time.Second) - c.String(http.StatusOK, "Welcome Gin Server") - }) - - srv := &http.Server{ - Addr: ":8080", - Handler: router, - } - - // Initializing the server in a goroutine so that - // it won't block the graceful shutdown handling below - go func() { - if err := srv.ListenAndServe(); err != nil && errors.Is(err, http.ErrServerClosed) { - log.Printf("listen: %s\n", err) - } - }() - - // Wait for interrupt signal to gracefully shutdown the server with - // a timeout of 5 seconds. - quit := make(chan os.Signal) - // kill (no param) default send syscall.SIGTERM - // kill -2 is syscall.SIGINT - // kill -9 is syscall.SIGKILL but can't be caught, so don't need to add it - signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) - <-quit - log.Println("Shutting down server...") - - // The context is used to inform the server it has 5 seconds to finish - // the request it is currently handling - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - if err := srv.Shutdown(ctx); err != nil { - log.Fatal("Server forced to shutdown:", err) - } - - log.Println("Server exiting") -} -``` - -### Build a single binary with templates - -You can build a server into a single binary containing templates by using [go-assets][]. - -[go-assets]: https://github.com/jessevdk/go-assets - -```go -func main() { - r := gin.New() - - t, err := loadTemplate() - if err != nil { - panic(err) - } - r.SetHTMLTemplate(t) - - r.GET("/", func(c *gin.Context) { - c.HTML(http.StatusOK, "/html/index.tmpl",nil) - }) - r.Run(":8080") -} - -// loadTemplate loads templates embedded by go-assets-builder -func loadTemplate() (*template.Template, error) { - t := template.New("") - for name, file := range Assets.Files { - defer file.Close() - if file.IsDir() || !strings.HasSuffix(name, ".tmpl") { - continue - } - h, err := ioutil.ReadAll(file) - if err != nil { - return nil, err - } - t, err = t.New(name).Parse(string(h)) - if err != nil { - return nil, err - } - } - return t, nil -} -``` - -See a complete example in the `https://github.com/gin-gonic/examples/tree/master/assets-in-binary` directory. - -### Bind form-data request with custom struct - -The follow example using custom struct: - -```go -type StructA struct { - FieldA string `form:"field_a"` -} - -type StructB struct { - NestedStruct StructA - FieldB string `form:"field_b"` -} - -type StructC struct { - NestedStructPointer *StructA - FieldC string `form:"field_c"` -} - -type StructD struct { - NestedAnonyStruct struct { - FieldX string `form:"field_x"` - } - FieldD string `form:"field_d"` -} - -func GetDataB(c *gin.Context) { - var b StructB - c.Bind(&b) - c.JSON(http.StatusOK, gin.H{ - "a": b.NestedStruct, - "b": b.FieldB, - }) -} - -func GetDataC(c *gin.Context) { - var b StructC - c.Bind(&b) - c.JSON(http.StatusOK, gin.H{ - "a": b.NestedStructPointer, - "c": b.FieldC, - }) -} - -func GetDataD(c *gin.Context) { - var b StructD - c.Bind(&b) - c.JSON(http.StatusOK, gin.H{ - "x": b.NestedAnonyStruct, - "d": b.FieldD, - }) -} - -func main() { - r := gin.Default() - r.GET("/getb", GetDataB) - r.GET("/getc", GetDataC) - r.GET("/getd", GetDataD) - - r.Run() -} -``` - -Using the command `curl` command result: - -``` -$ curl "http://localhost:8080/getb?field_a=hello&field_b=world" -{"a":{"FieldA":"hello"},"b":"world"} -$ curl "http://localhost:8080/getc?field_a=hello&field_c=world" -{"a":{"FieldA":"hello"},"c":"world"} -$ curl "http://localhost:8080/getd?field_x=hello&field_d=world" -{"d":"world","x":{"FieldX":"hello"}} -``` - -### Try to bind body into different structs - -The normal methods for binding request body consumes `c.Request.Body` and they -cannot be called multiple times. - -```go -type formA struct { - Foo string `json:"foo" xml:"foo" binding:"required"` -} - -type formB struct { - Bar string `json:"bar" xml:"bar" binding:"required"` -} - -func SomeHandler(c *gin.Context) { - objA := formA{} - objB := formB{} - // This c.ShouldBind consumes c.Request.Body and it cannot be reused. - if errA := c.ShouldBind(&objA); errA == nil { - c.String(http.StatusOK, `the body should be formA`) - // Always an error is occurred by this because c.Request.Body is EOF now. - } else if errB := c.ShouldBind(&objB); errB == nil { - c.String(http.StatusOK, `the body should be formB`) - } else { - ... - } -} -``` - -For this, you can use `c.ShouldBindBodyWith`. - -```go -func SomeHandler(c *gin.Context) { - objA := formA{} - objB := formB{} - // This reads c.Request.Body and stores the result into the context. - if errA := c.ShouldBindBodyWith(&objA, binding.Form); errA == nil { - c.String(http.StatusOK, `the body should be formA`) - // At this time, it reuses body stored in the context. - } else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil { - c.String(http.StatusOK, `the body should be formB JSON`) - // And it can accepts other formats - } else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil { - c.String(http.StatusOK, `the body should be formB XML`) - } else { - ... - } -} -``` - -* `c.ShouldBindBodyWith` stores body into the context before binding. This has -a slight impact to performance, so you should not use this method if you are -enough to call binding at once. -* This feature is only needed for some formats -- `JSON`, `XML`, `MsgPack`, -`ProtoBuf`. For other formats, `Query`, `Form`, `FormPost`, `FormMultipart`, -can be called by `c.ShouldBind()` multiple times without any damage to -performance (See [#1341](https://github.com/gin-gonic/gin/pull/1341)). - -### Bind form-data request with custom struct and custom tag - -```go -const ( - customerTag = "url" - defaultMemory = 32 << 20 -) - -type customerBinding struct {} - -func (customerBinding) Name() string { - return "form" -} - -func (customerBinding) Bind(req *http.Request, obj interface{}) error { - if err := req.ParseForm(); err != nil { - return err - } - if err := req.ParseMultipartForm(defaultMemory); err != nil { - if err != http.ErrNotMultipart { - return err - } - } - if err := binding.MapFormWithTag(obj, req.Form, customerTag); err != nil { - return err - } - return validate(obj) -} - -func validate(obj interface{}) error { - if binding.Validator == nil { - return nil - } - return binding.Validator.ValidateStruct(obj) -} - -// Now we can do this!!! -// FormA is a external type that we can't modify it's tag -type FormA struct { - FieldA string `url:"field_a"` -} - -func ListHandler(s *Service) func(ctx *gin.Context) { - return func(ctx *gin.Context) { - var urlBinding = customerBinding{} - var opt FormA - err := ctx.MustBindWith(&opt, urlBinding) - if err != nil { - ... - } - ... - } -} -``` - -### http2 server push - -http.Pusher is supported only **go1.8+**. See the [golang blog](https://blog.golang.org/h2push) for detail information. - -```go -package main - -import ( - "html/template" - "log" - "net/http" - - "github.com/gin-gonic/gin" -) - -var html = template.Must(template.New("https").Parse(` - - - Https Test - - - -

Welcome, Ginner!

- - -`)) - -func main() { - r := gin.Default() - r.Static("/assets", "./assets") - r.SetHTMLTemplate(html) - - r.GET("/", func(c *gin.Context) { - if pusher := c.Writer.Pusher(); pusher != nil { - // use pusher.Push() to do server push - if err := pusher.Push("/assets/app.js", nil); err != nil { - log.Printf("Failed to push: %v", err) - } - } - c.HTML(http.StatusOK, "https", gin.H{ - "status": "success", - }) - }) - - // Listen and Server in https://127.0.0.1:8080 - r.RunTLS(":8080", "./testdata/server.pem", "./testdata/server.key") -} -``` - -### Define format for the log of routes - -The default log of routes is: -``` -[GIN-debug] POST /foo --> main.main.func1 (3 handlers) -[GIN-debug] GET /bar --> main.main.func2 (3 handlers) -[GIN-debug] GET /status --> main.main.func3 (3 handlers) -``` - -If you want to log this information in given format (e.g. JSON, key values or something else), then you can define this format with `gin.DebugPrintRouteFunc`. -In the example below, we log all routes with standard log package but you can use another log tools that suits of your needs. -```go -import ( - "log" - "net/http" - - "github.com/gin-gonic/gin" -) - -func main() { - r := gin.Default() - gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) { - log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers) - } - - r.POST("/foo", func(c *gin.Context) { - c.JSON(http.StatusOK, "foo") - }) - - r.GET("/bar", func(c *gin.Context) { - c.JSON(http.StatusOK, "bar") - }) - - r.GET("/status", func(c *gin.Context) { - c.JSON(http.StatusOK, "ok") - }) - - // Listen and Server in http://0.0.0.0:8080 - r.Run() -} -``` - -### Set and get a cookie - -```go -import ( - "fmt" - - "github.com/gin-gonic/gin" -) - -func main() { - - router := gin.Default() - - router.GET("/cookie", func(c *gin.Context) { - - cookie, err := c.Cookie("gin_cookie") - - if err != nil { - cookie = "NotSet" - c.SetCookie("gin_cookie", "test", 3600, "/", "localhost", false, true) - } - - fmt.Printf("Cookie value: %s \n", cookie) - }) - - router.Run() -} -``` - -## Don't trust all proxies - -Gin lets you specify which headers to hold the real client IP (if any), -as well as specifying which proxies (or direct clients) you trust to -specify one of these headers. - -Use function `SetTrustedProxies()` on your `gin.Engine` to specify network addresses -or network CIDRs from where clients which their request headers related to client -IP can be trusted. They can be IPv4 addresses, IPv4 CIDRs, IPv6 addresses or -IPv6 CIDRs. - -**Attention:** Gin trust all proxies by default if you don't specify a trusted -proxy using the function above, **this is NOT safe**. At the same time, if you don't -use any proxy, you can disable this feature by using `Engine.SetTrustedProxies(nil)`, -then `Context.ClientIP()` will return the remote address directly to avoid some -unnecessary computation. - -```go -import ( - "fmt" - - "github.com/gin-gonic/gin" -) - -func main() { - - router := gin.Default() - router.SetTrustedProxies([]string{"192.168.1.2"}) - - router.GET("/", func(c *gin.Context) { - // If the client is 192.168.1.2, use the X-Forwarded-For - // header to deduce the original client IP from the trust- - // worthy parts of that header. - // Otherwise, simply return the direct client IP - fmt.Printf("ClientIP: %s\n", c.ClientIP()) - }) - router.Run() -} -``` - -**Notice:** If you are using a CDN service, you can set the `Engine.TrustedPlatform` -to skip TrustedProxies check, it has a higher priority than TrustedProxies. -Look at the example below: -```go -import ( - "fmt" - - "github.com/gin-gonic/gin" -) - -func main() { - - router := gin.Default() - // Use predefined header gin.PlatformXXX - router.TrustedPlatform = gin.PlatformGoogleAppEngine - // Or set your own trusted request header for another trusted proxy service - // Don't set it to any suspect request header, it's unsafe - router.TrustedPlatform = "X-CDN-IP" - - router.GET("/", func(c *gin.Context) { - // If you set TrustedPlatform, ClientIP() will resolve the - // corresponding header and return IP directly - fmt.Printf("ClientIP: %s\n", c.ClientIP()) - }) - router.Run() -} -``` - -## Testing - -The `net/http/httptest` package is preferable way for HTTP testing. - -```go -package main - -import ( - "net/http" - - "github.com/gin-gonic/gin" -) - -func setupRouter() *gin.Engine { - r := gin.Default() - r.GET("/ping", func(c *gin.Context) { - c.String(http.StatusOK, "pong") - }) - return r -} - -func main() { - r := setupRouter() - r.Run(":8080") -} -``` - -Test for code example above: - -```go -package main - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestPingRoute(t *testing.T) { - router := setupRouter() - - w := httptest.NewRecorder() - req, _ := http.NewRequest(http.MethodGet, "/ping", nil) - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusOK, w.Code) - assert.Equal(t, "pong", w.Body.String()) -} -``` - -## Users - -Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework. - -* [gorush](https://github.com/appleboy/gorush): A push notification server written in Go. -* [fnproject](https://github.com/fnproject/fn): The container native, cloud agnostic serverless platform. -* [photoprism](https://github.com/photoprism/photoprism): Personal photo management powered by Go and Google TensorFlow. -* [krakend](https://github.com/devopsfaith/krakend): Ultra performant API Gateway with middlewares. -* [picfit](https://github.com/thoas/picfit): An image resizing server written in Go. -* [brigade](https://github.com/brigadecore/brigade): Event-based Scripting for Kubernetes. -* [dkron](https://github.com/distribworks/dkron): Distributed, fault tolerant job scheduling system. - diff --git a/vendor/github.com/gin-gonic/gin/any.go b/vendor/github.com/gin-gonic/gin/any.go deleted file mode 100644 index 42b1ea4..0000000 --- a/vendor/github.com/gin-gonic/gin/any.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package gin - -type any = interface{} diff --git a/vendor/github.com/gin-gonic/gin/auth.go b/vendor/github.com/gin-gonic/gin/auth.go deleted file mode 100644 index 2503c51..0000000 --- a/vendor/github.com/gin-gonic/gin/auth.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "crypto/subtle" - "encoding/base64" - "net/http" - "strconv" - - "github.com/gin-gonic/gin/internal/bytesconv" -) - -// AuthUserKey is the cookie name for user credential in basic auth. -const AuthUserKey = "user" - -// Accounts defines a key/value for user/pass list of authorized logins. -type Accounts map[string]string - -type authPair struct { - value string - user string -} - -type authPairs []authPair - -func (a authPairs) searchCredential(authValue string) (string, bool) { - if authValue == "" { - return "", false - } - for _, pair := range a { - if subtle.ConstantTimeCompare(bytesconv.StringToBytes(pair.value), bytesconv.StringToBytes(authValue)) == 1 { - return pair.user, true - } - } - return "", false -} - -// BasicAuthForRealm returns a Basic HTTP Authorization middleware. It takes as arguments a map[string]string where -// the key is the user name and the value is the password, as well as the name of the Realm. -// If the realm is empty, "Authorization Required" will be used by default. -// (see http://tools.ietf.org/html/rfc2617#section-1.2) -func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc { - if realm == "" { - realm = "Authorization Required" - } - realm = "Basic realm=" + strconv.Quote(realm) - pairs := processAccounts(accounts) - return func(c *Context) { - // Search user in the slice of allowed credentials - user, found := pairs.searchCredential(c.requestHeader("Authorization")) - if !found { - // Credentials doesn't match, we return 401 and abort handlers chain. - c.Header("WWW-Authenticate", realm) - c.AbortWithStatus(http.StatusUnauthorized) - return - } - - // The user credentials was found, set user's id to key AuthUserKey in this context, the user's id can be read later using - // c.MustGet(gin.AuthUserKey). - c.Set(AuthUserKey, user) - } -} - -// BasicAuth returns a Basic HTTP Authorization middleware. It takes as argument a map[string]string where -// the key is the user name and the value is the password. -func BasicAuth(accounts Accounts) HandlerFunc { - return BasicAuthForRealm(accounts, "") -} - -func processAccounts(accounts Accounts) authPairs { - length := len(accounts) - assert1(length > 0, "Empty list of authorized credentials") - pairs := make(authPairs, 0, length) - for user, password := range accounts { - assert1(user != "", "User can not be empty") - value := authorizationHeader(user, password) - pairs = append(pairs, authPair{ - value: value, - user: user, - }) - } - return pairs -} - -func authorizationHeader(user, password string) string { - base := user + ":" + password - return "Basic " + base64.StdEncoding.EncodeToString(bytesconv.StringToBytes(base)) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/any.go b/vendor/github.com/gin-gonic/gin/binding/any.go deleted file mode 100644 index d8251a7..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/any.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package binding - -type any = interface{} diff --git a/vendor/github.com/gin-gonic/gin/binding/binding.go b/vendor/github.com/gin-gonic/gin/binding/binding.go deleted file mode 100644 index a58924e..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/binding.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !nomsgpack -// +build !nomsgpack - -package binding - -import "net/http" - -// Content-Type MIME of the most common data formats. -const ( - MIMEJSON = "application/json" - MIMEHTML = "text/html" - MIMEXML = "application/xml" - MIMEXML2 = "text/xml" - MIMEPlain = "text/plain" - MIMEPOSTForm = "application/x-www-form-urlencoded" - MIMEMultipartPOSTForm = "multipart/form-data" - MIMEPROTOBUF = "application/x-protobuf" - MIMEMSGPACK = "application/x-msgpack" - MIMEMSGPACK2 = "application/msgpack" - MIMEYAML = "application/x-yaml" - MIMETOML = "application/toml" -) - -// Binding describes the interface which needs to be implemented for binding the -// data present in the request such as JSON request body, query parameters or -// the form POST. -type Binding interface { - Name() string - Bind(*http.Request, any) error -} - -// BindingBody adds BindBody method to Binding. BindBody is similar with Bind, -// but it reads the body from supplied bytes instead of req.Body. -type BindingBody interface { - Binding - BindBody([]byte, any) error -} - -// BindingUri adds BindUri method to Binding. BindUri is similar with Bind, -// but it reads the Params. -type BindingUri interface { - Name() string - BindUri(map[string][]string, any) error -} - -// StructValidator is the minimal interface which needs to be implemented in -// order for it to be used as the validator engine for ensuring the correctness -// of the request. Gin provides a default implementation for this using -// https://github.com/go-playground/validator/tree/v10.6.1. -type StructValidator interface { - // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. - // If the received type is a slice|array, the validation should be performed travel on every element. - // If the received type is not a struct or slice|array, any validation should be skipped and nil must be returned. - // If the received type is a struct or pointer to a struct, the validation should be performed. - // If the struct is not valid or the validation itself fails, a descriptive error should be returned. - // Otherwise nil must be returned. - ValidateStruct(any) error - - // Engine returns the underlying validator engine which powers the - // StructValidator implementation. - Engine() any -} - -// Validator is the default validator which implements the StructValidator -// interface. It uses https://github.com/go-playground/validator/tree/v10.6.1 -// under the hood. -var Validator StructValidator = &defaultValidator{} - -// These implement the Binding interface and can be used to bind the data -// present in the request to struct instances. -var ( - JSON = jsonBinding{} - XML = xmlBinding{} - Form = formBinding{} - Query = queryBinding{} - FormPost = formPostBinding{} - FormMultipart = formMultipartBinding{} - ProtoBuf = protobufBinding{} - MsgPack = msgpackBinding{} - YAML = yamlBinding{} - Uri = uriBinding{} - Header = headerBinding{} - TOML = tomlBinding{} -) - -// Default returns the appropriate Binding instance based on the HTTP method -// and the content type. -func Default(method, contentType string) Binding { - if method == http.MethodGet { - return Form - } - - switch contentType { - case MIMEJSON: - return JSON - case MIMEXML, MIMEXML2: - return XML - case MIMEPROTOBUF: - return ProtoBuf - case MIMEMSGPACK, MIMEMSGPACK2: - return MsgPack - case MIMEYAML: - return YAML - case MIMETOML: - return TOML - case MIMEMultipartPOSTForm: - return FormMultipart - default: // case MIMEPOSTForm: - return Form - } -} - -func validate(obj any) error { - if Validator == nil { - return nil - } - return Validator.ValidateStruct(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go b/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go deleted file mode 100644 index 7f6a904..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2020 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build nomsgpack -// +build nomsgpack - -package binding - -import "net/http" - -// Content-Type MIME of the most common data formats. -const ( - MIMEJSON = "application/json" - MIMEHTML = "text/html" - MIMEXML = "application/xml" - MIMEXML2 = "text/xml" - MIMEPlain = "text/plain" - MIMEPOSTForm = "application/x-www-form-urlencoded" - MIMEMultipartPOSTForm = "multipart/form-data" - MIMEPROTOBUF = "application/x-protobuf" - MIMEYAML = "application/x-yaml" - MIMETOML = "application/toml" -) - -// Binding describes the interface which needs to be implemented for binding the -// data present in the request such as JSON request body, query parameters or -// the form POST. -type Binding interface { - Name() string - Bind(*http.Request, any) error -} - -// BindingBody adds BindBody method to Binding. BindBody is similar with Bind, -// but it reads the body from supplied bytes instead of req.Body. -type BindingBody interface { - Binding - BindBody([]byte, any) error -} - -// BindingUri adds BindUri method to Binding. BindUri is similar with Bind, -// but it reads the Params. -type BindingUri interface { - Name() string - BindUri(map[string][]string, any) error -} - -// StructValidator is the minimal interface which needs to be implemented in -// order for it to be used as the validator engine for ensuring the correctness -// of the request. Gin provides a default implementation for this using -// https://github.com/go-playground/validator/tree/v10.6.1. -type StructValidator interface { - // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. - // If the received type is not a struct, any validation should be skipped and nil must be returned. - // If the received type is a struct or pointer to a struct, the validation should be performed. - // If the struct is not valid or the validation itself fails, a descriptive error should be returned. - // Otherwise nil must be returned. - ValidateStruct(any) error - - // Engine returns the underlying validator engine which powers the - // StructValidator implementation. - Engine() any -} - -// Validator is the default validator which implements the StructValidator -// interface. It uses https://github.com/go-playground/validator/tree/v10.6.1 -// under the hood. -var Validator StructValidator = &defaultValidator{} - -// These implement the Binding interface and can be used to bind the data -// present in the request to struct instances. -var ( - JSON = jsonBinding{} - XML = xmlBinding{} - Form = formBinding{} - Query = queryBinding{} - FormPost = formPostBinding{} - FormMultipart = formMultipartBinding{} - ProtoBuf = protobufBinding{} - YAML = yamlBinding{} - Uri = uriBinding{} - Header = headerBinding{} - TOML = tomlBinding{} -) - -// Default returns the appropriate Binding instance based on the HTTP method -// and the content type. -func Default(method, contentType string) Binding { - if method == "GET" { - return Form - } - - switch contentType { - case MIMEJSON: - return JSON - case MIMEXML, MIMEXML2: - return XML - case MIMEPROTOBUF: - return ProtoBuf - case MIMEYAML: - return YAML - case MIMEMultipartPOSTForm: - return FormMultipart - case MIMETOML: - return TOML - default: // case MIMEPOSTForm: - return Form - } -} - -func validate(obj any) error { - if Validator == nil { - return nil - } - return Validator.ValidateStruct(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/default_validator.go b/vendor/github.com/gin-gonic/gin/binding/default_validator.go deleted file mode 100644 index c03afe7..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/default_validator.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2017 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "fmt" - "reflect" - "strings" - "sync" - - "github.com/go-playground/validator/v10" -) - -type defaultValidator struct { - once sync.Once - validate *validator.Validate -} - -type SliceValidationError []error - -// Error concatenates all error elements in SliceValidationError into a single string separated by \n. -func (err SliceValidationError) Error() string { - n := len(err) - switch n { - case 0: - return "" - default: - var b strings.Builder - if err[0] != nil { - fmt.Fprintf(&b, "[%d]: %s", 0, err[0].Error()) - } - if n > 1 { - for i := 1; i < n; i++ { - if err[i] != nil { - b.WriteString("\n") - fmt.Fprintf(&b, "[%d]: %s", i, err[i].Error()) - } - } - } - return b.String() - } -} - -var _ StructValidator = &defaultValidator{} - -// ValidateStruct receives any kind of type, but only performed struct or pointer to struct type. -func (v *defaultValidator) ValidateStruct(obj any) error { - if obj == nil { - return nil - } - - value := reflect.ValueOf(obj) - switch value.Kind() { - case reflect.Ptr: - return v.ValidateStruct(value.Elem().Interface()) - case reflect.Struct: - return v.validateStruct(obj) - case reflect.Slice, reflect.Array: - count := value.Len() - validateRet := make(SliceValidationError, 0) - for i := 0; i < count; i++ { - if err := v.ValidateStruct(value.Index(i).Interface()); err != nil { - validateRet = append(validateRet, err) - } - } - if len(validateRet) == 0 { - return nil - } - return validateRet - default: - return nil - } -} - -// validateStruct receives struct type -func (v *defaultValidator) validateStruct(obj any) error { - v.lazyinit() - return v.validate.Struct(obj) -} - -// Engine returns the underlying validator engine which powers the default -// Validator instance. This is useful if you want to register custom validations -// or struct level validations. See validator GoDoc for more info - -// https://pkg.go.dev/github.com/go-playground/validator/v10 -func (v *defaultValidator) Engine() any { - v.lazyinit() - return v.validate -} - -func (v *defaultValidator) lazyinit() { - v.once.Do(func() { - v.validate = validator.New() - v.validate.SetTagName("binding") - }) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/form.go b/vendor/github.com/gin-gonic/gin/binding/form.go deleted file mode 100644 index b17352b..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/form.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "errors" - "net/http" -) - -const defaultMemory = 32 << 20 - -type formBinding struct{} -type formPostBinding struct{} -type formMultipartBinding struct{} - -func (formBinding) Name() string { - return "form" -} - -func (formBinding) Bind(req *http.Request, obj any) error { - if err := req.ParseForm(); err != nil { - return err - } - if err := req.ParseMultipartForm(defaultMemory); err != nil && !errors.Is(err, http.ErrNotMultipart) { - return err - } - if err := mapForm(obj, req.Form); err != nil { - return err - } - return validate(obj) -} - -func (formPostBinding) Name() string { - return "form-urlencoded" -} - -func (formPostBinding) Bind(req *http.Request, obj any) error { - if err := req.ParseForm(); err != nil { - return err - } - if err := mapForm(obj, req.PostForm); err != nil { - return err - } - return validate(obj) -} - -func (formMultipartBinding) Name() string { - return "multipart/form-data" -} - -func (formMultipartBinding) Bind(req *http.Request, obj any) error { - if err := req.ParseMultipartForm(defaultMemory); err != nil { - return err - } - if err := mappingByPtr(obj, (*multipartRequest)(req), "form"); err != nil { - return err - } - - return validate(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/form_mapping.go b/vendor/github.com/gin-gonic/gin/binding/form_mapping.go deleted file mode 100644 index 98cebfe..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/form_mapping.go +++ /dev/null @@ -1,403 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "errors" - "fmt" - "reflect" - "strconv" - "strings" - "time" - - "github.com/gin-gonic/gin/internal/bytesconv" - "github.com/gin-gonic/gin/internal/json" -) - -var ( - errUnknownType = errors.New("unknown type") - - // ErrConvertMapStringSlice can not covert to map[string][]string - ErrConvertMapStringSlice = errors.New("can not convert to map slices of strings") - - // ErrConvertToMapString can not convert to map[string]string - ErrConvertToMapString = errors.New("can not convert to map of strings") -) - -func mapURI(ptr any, m map[string][]string) error { - return mapFormByTag(ptr, m, "uri") -} - -func mapForm(ptr any, form map[string][]string) error { - return mapFormByTag(ptr, form, "form") -} - -func MapFormWithTag(ptr any, form map[string][]string, tag string) error { - return mapFormByTag(ptr, form, tag) -} - -var emptyField = reflect.StructField{} - -func mapFormByTag(ptr any, form map[string][]string, tag string) error { - // Check if ptr is a map - ptrVal := reflect.ValueOf(ptr) - var pointed any - if ptrVal.Kind() == reflect.Ptr { - ptrVal = ptrVal.Elem() - pointed = ptrVal.Interface() - } - if ptrVal.Kind() == reflect.Map && - ptrVal.Type().Key().Kind() == reflect.String { - if pointed != nil { - ptr = pointed - } - return setFormMap(ptr, form) - } - - return mappingByPtr(ptr, formSource(form), tag) -} - -// setter tries to set value on a walking by fields of a struct -type setter interface { - TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSet bool, err error) -} - -type formSource map[string][]string - -var _ setter = formSource(nil) - -// TrySet tries to set a value by request's form source (like map[string][]string) -func (form formSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSet bool, err error) { - return setByForm(value, field, form, tagValue, opt) -} - -func mappingByPtr(ptr any, setter setter, tag string) error { - _, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag) - return err -} - -func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) { - if field.Tag.Get(tag) == "-" { // just ignoring this field - return false, nil - } - - vKind := value.Kind() - - if vKind == reflect.Ptr { - var isNew bool - vPtr := value - if value.IsNil() { - isNew = true - vPtr = reflect.New(value.Type().Elem()) - } - isSet, err := mapping(vPtr.Elem(), field, setter, tag) - if err != nil { - return false, err - } - if isNew && isSet { - value.Set(vPtr) - } - return isSet, nil - } - - if vKind != reflect.Struct || !field.Anonymous { - ok, err := tryToSetValue(value, field, setter, tag) - if err != nil { - return false, err - } - if ok { - return true, nil - } - } - - if vKind == reflect.Struct { - tValue := value.Type() - - var isSet bool - for i := 0; i < value.NumField(); i++ { - sf := tValue.Field(i) - if sf.PkgPath != "" && !sf.Anonymous { // unexported - continue - } - ok, err := mapping(value.Field(i), sf, setter, tag) - if err != nil { - return false, err - } - isSet = isSet || ok - } - return isSet, nil - } - return false, nil -} - -type setOptions struct { - isDefaultExists bool - defaultValue string -} - -func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) { - var tagValue string - var setOpt setOptions - - tagValue = field.Tag.Get(tag) - tagValue, opts := head(tagValue, ",") - - if tagValue == "" { // default value is FieldName - tagValue = field.Name - } - if tagValue == "" { // when field is "emptyField" variable - return false, nil - } - - var opt string - for len(opts) > 0 { - opt, opts = head(opts, ",") - - if k, v := head(opt, "="); k == "default" { - setOpt.isDefaultExists = true - setOpt.defaultValue = v - } - } - - return setter.TrySet(value, field, tagValue, setOpt) -} - -func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSet bool, err error) { - vs, ok := form[tagValue] - if !ok && !opt.isDefaultExists { - return false, nil - } - - switch value.Kind() { - case reflect.Slice: - if !ok { - vs = []string{opt.defaultValue} - } - return true, setSlice(vs, value, field) - case reflect.Array: - if !ok { - vs = []string{opt.defaultValue} - } - if len(vs) != value.Len() { - return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String()) - } - return true, setArray(vs, value, field) - default: - var val string - if !ok { - val = opt.defaultValue - } - - if len(vs) > 0 { - val = vs[0] - } - return true, setWithProperType(val, value, field) - } -} - -func setWithProperType(val string, value reflect.Value, field reflect.StructField) error { - switch value.Kind() { - case reflect.Int: - return setIntField(val, 0, value) - case reflect.Int8: - return setIntField(val, 8, value) - case reflect.Int16: - return setIntField(val, 16, value) - case reflect.Int32: - return setIntField(val, 32, value) - case reflect.Int64: - switch value.Interface().(type) { - case time.Duration: - return setTimeDuration(val, value) - } - return setIntField(val, 64, value) - case reflect.Uint: - return setUintField(val, 0, value) - case reflect.Uint8: - return setUintField(val, 8, value) - case reflect.Uint16: - return setUintField(val, 16, value) - case reflect.Uint32: - return setUintField(val, 32, value) - case reflect.Uint64: - return setUintField(val, 64, value) - case reflect.Bool: - return setBoolField(val, value) - case reflect.Float32: - return setFloatField(val, 32, value) - case reflect.Float64: - return setFloatField(val, 64, value) - case reflect.String: - value.SetString(val) - case reflect.Struct: - switch value.Interface().(type) { - case time.Time: - return setTimeField(val, field, value) - } - return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface()) - case reflect.Map: - return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface()) - default: - return errUnknownType - } - return nil -} - -func setIntField(val string, bitSize int, field reflect.Value) error { - if val == "" { - val = "0" - } - intVal, err := strconv.ParseInt(val, 10, bitSize) - if err == nil { - field.SetInt(intVal) - } - return err -} - -func setUintField(val string, bitSize int, field reflect.Value) error { - if val == "" { - val = "0" - } - uintVal, err := strconv.ParseUint(val, 10, bitSize) - if err == nil { - field.SetUint(uintVal) - } - return err -} - -func setBoolField(val string, field reflect.Value) error { - if val == "" { - val = "false" - } - boolVal, err := strconv.ParseBool(val) - if err == nil { - field.SetBool(boolVal) - } - return err -} - -func setFloatField(val string, bitSize int, field reflect.Value) error { - if val == "" { - val = "0.0" - } - floatVal, err := strconv.ParseFloat(val, bitSize) - if err == nil { - field.SetFloat(floatVal) - } - return err -} - -func setTimeField(val string, structField reflect.StructField, value reflect.Value) error { - timeFormat := structField.Tag.Get("time_format") - if timeFormat == "" { - timeFormat = time.RFC3339 - } - - switch tf := strings.ToLower(timeFormat); tf { - case "unix", "unixnano": - tv, err := strconv.ParseInt(val, 10, 64) - if err != nil { - return err - } - - d := time.Duration(1) - if tf == "unixnano" { - d = time.Second - } - - t := time.Unix(tv/int64(d), tv%int64(d)) - value.Set(reflect.ValueOf(t)) - return nil - } - - if val == "" { - value.Set(reflect.ValueOf(time.Time{})) - return nil - } - - l := time.Local - if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC { - l = time.UTC - } - - if locTag := structField.Tag.Get("time_location"); locTag != "" { - loc, err := time.LoadLocation(locTag) - if err != nil { - return err - } - l = loc - } - - t, err := time.ParseInLocation(timeFormat, val, l) - if err != nil { - return err - } - - value.Set(reflect.ValueOf(t)) - return nil -} - -func setArray(vals []string, value reflect.Value, field reflect.StructField) error { - for i, s := range vals { - err := setWithProperType(s, value.Index(i), field) - if err != nil { - return err - } - } - return nil -} - -func setSlice(vals []string, value reflect.Value, field reflect.StructField) error { - slice := reflect.MakeSlice(value.Type(), len(vals), len(vals)) - err := setArray(vals, slice, field) - if err != nil { - return err - } - value.Set(slice) - return nil -} - -func setTimeDuration(val string, value reflect.Value) error { - d, err := time.ParseDuration(val) - if err != nil { - return err - } - value.Set(reflect.ValueOf(d)) - return nil -} - -func head(str, sep string) (head string, tail string) { - idx := strings.Index(str, sep) - if idx < 0 { - return str, "" - } - return str[:idx], str[idx+len(sep):] -} - -func setFormMap(ptr any, form map[string][]string) error { - el := reflect.TypeOf(ptr).Elem() - - if el.Kind() == reflect.Slice { - ptrMap, ok := ptr.(map[string][]string) - if !ok { - return ErrConvertMapStringSlice - } - for k, v := range form { - ptrMap[k] = v - } - - return nil - } - - ptrMap, ok := ptr.(map[string]string) - if !ok { - return ErrConvertToMapString - } - for k, v := range form { - ptrMap[k] = v[len(v)-1] // pick last - } - - return nil -} diff --git a/vendor/github.com/gin-gonic/gin/binding/header.go b/vendor/github.com/gin-gonic/gin/binding/header.go deleted file mode 100644 index 03bc78d..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/header.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2022 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "net/http" - "net/textproto" - "reflect" -) - -type headerBinding struct{} - -func (headerBinding) Name() string { - return "header" -} - -func (headerBinding) Bind(req *http.Request, obj any) error { - - if err := mapHeader(obj, req.Header); err != nil { - return err - } - - return validate(obj) -} - -func mapHeader(ptr any, h map[string][]string) error { - return mappingByPtr(ptr, headerSource(h), "header") -} - -type headerSource map[string][]string - -var _ setter = headerSource(nil) - -func (hs headerSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (bool, error) { - return setByForm(value, field, hs, textproto.CanonicalMIMEHeaderKey(tagValue), opt) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/json.go b/vendor/github.com/gin-gonic/gin/binding/json.go deleted file mode 100644 index 36eb27a..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/json.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "bytes" - "errors" - "io" - "net/http" - - "github.com/gin-gonic/gin/internal/json" -) - -// EnableDecoderUseNumber is used to call the UseNumber method on the JSON -// Decoder instance. UseNumber causes the Decoder to unmarshal a number into an -// interface{} as a Number instead of as a float64. -var EnableDecoderUseNumber = false - -// EnableDecoderDisallowUnknownFields is used to call the DisallowUnknownFields method -// on the JSON Decoder instance. DisallowUnknownFields causes the Decoder to -// return an error when the destination is a struct and the input contains object -// keys which do not match any non-ignored, exported fields in the destination. -var EnableDecoderDisallowUnknownFields = false - -type jsonBinding struct{} - -func (jsonBinding) Name() string { - return "json" -} - -func (jsonBinding) Bind(req *http.Request, obj any) error { - if req == nil || req.Body == nil { - return errors.New("invalid request") - } - return decodeJSON(req.Body, obj) -} - -func (jsonBinding) BindBody(body []byte, obj any) error { - return decodeJSON(bytes.NewReader(body), obj) -} - -func decodeJSON(r io.Reader, obj any) error { - decoder := json.NewDecoder(r) - if EnableDecoderUseNumber { - decoder.UseNumber() - } - if EnableDecoderDisallowUnknownFields { - decoder.DisallowUnknownFields() - } - if err := decoder.Decode(obj); err != nil { - return err - } - return validate(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/msgpack.go b/vendor/github.com/gin-gonic/gin/binding/msgpack.go deleted file mode 100644 index d1f035e..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/msgpack.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2017 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !nomsgpack -// +build !nomsgpack - -package binding - -import ( - "bytes" - "io" - "net/http" - - "github.com/ugorji/go/codec" -) - -type msgpackBinding struct{} - -func (msgpackBinding) Name() string { - return "msgpack" -} - -func (msgpackBinding) Bind(req *http.Request, obj any) error { - return decodeMsgPack(req.Body, obj) -} - -func (msgpackBinding) BindBody(body []byte, obj any) error { - return decodeMsgPack(bytes.NewReader(body), obj) -} - -func decodeMsgPack(r io.Reader, obj any) error { - cdc := new(codec.MsgpackHandle) - if err := codec.NewDecoder(r, cdc).Decode(&obj); err != nil { - return err - } - return validate(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/multipart_form_mapping.go b/vendor/github.com/gin-gonic/gin/binding/multipart_form_mapping.go deleted file mode 100644 index 4ebe832..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/multipart_form_mapping.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2019 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "errors" - "mime/multipart" - "net/http" - "reflect" -) - -type multipartRequest http.Request - -var _ setter = (*multipartRequest)(nil) - -var ( - // ErrMultiFileHeader multipart.FileHeader invalid - ErrMultiFileHeader = errors.New("unsupported field type for multipart.FileHeader") - - // ErrMultiFileHeaderLenInvalid array for []*multipart.FileHeader len invalid - ErrMultiFileHeaderLenInvalid = errors.New("unsupported len of array for []*multipart.FileHeader") -) - -// TrySet tries to set a value by the multipart request with the binding a form file -func (r *multipartRequest) TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (bool, error) { - if files := r.MultipartForm.File[key]; len(files) != 0 { - return setByMultipartFormFile(value, field, files) - } - - return setByForm(value, field, r.MultipartForm.Value, key, opt) -} - -func setByMultipartFormFile(value reflect.Value, field reflect.StructField, files []*multipart.FileHeader) (isSet bool, err error) { - switch value.Kind() { - case reflect.Ptr: - switch value.Interface().(type) { - case *multipart.FileHeader: - value.Set(reflect.ValueOf(files[0])) - return true, nil - } - case reflect.Struct: - switch value.Interface().(type) { - case multipart.FileHeader: - value.Set(reflect.ValueOf(*files[0])) - return true, nil - } - case reflect.Slice: - slice := reflect.MakeSlice(value.Type(), len(files), len(files)) - isSet, err = setArrayOfMultipartFormFiles(slice, field, files) - if err != nil || !isSet { - return isSet, err - } - value.Set(slice) - return true, nil - case reflect.Array: - return setArrayOfMultipartFormFiles(value, field, files) - } - return false, ErrMultiFileHeader -} - -func setArrayOfMultipartFormFiles(value reflect.Value, field reflect.StructField, files []*multipart.FileHeader) (isSet bool, err error) { - if value.Len() != len(files) { - return false, ErrMultiFileHeaderLenInvalid - } - for i := range files { - set, err := setByMultipartFormFile(value.Index(i), field, files[i:i+1]) - if err != nil || !set { - return set, err - } - } - return true, nil -} diff --git a/vendor/github.com/gin-gonic/gin/binding/protobuf.go b/vendor/github.com/gin-gonic/gin/binding/protobuf.go deleted file mode 100644 index 44f2fdb..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/protobuf.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "errors" - "io/ioutil" - "net/http" - - "google.golang.org/protobuf/proto" -) - -type protobufBinding struct{} - -func (protobufBinding) Name() string { - return "protobuf" -} - -func (b protobufBinding) Bind(req *http.Request, obj any) error { - buf, err := ioutil.ReadAll(req.Body) - if err != nil { - return err - } - return b.BindBody(buf, obj) -} - -func (protobufBinding) BindBody(body []byte, obj any) error { - msg, ok := obj.(proto.Message) - if !ok { - return errors.New("obj is not ProtoMessage") - } - if err := proto.Unmarshal(body, msg); err != nil { - return err - } - // Here it's same to return validate(obj), but util now we can't add - // `binding:""` to the struct which automatically generate by gen-proto - return nil - // return validate(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/query.go b/vendor/github.com/gin-gonic/gin/binding/query.go deleted file mode 100644 index c958b88..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/query.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2017 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import "net/http" - -type queryBinding struct{} - -func (queryBinding) Name() string { - return "query" -} - -func (queryBinding) Bind(req *http.Request, obj any) error { - values := req.URL.Query() - if err := mapForm(obj, values); err != nil { - return err - } - return validate(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/toml.go b/vendor/github.com/gin-gonic/gin/binding/toml.go deleted file mode 100644 index a6b8a90..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/toml.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2022 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "bytes" - "io" - "net/http" - - "github.com/pelletier/go-toml/v2" -) - -type tomlBinding struct{} - -func (tomlBinding) Name() string { - return "toml" -} - -func decodeToml(r io.Reader, obj any) error { - decoder := toml.NewDecoder(r) - if err := decoder.Decode(obj); err != nil { - return err - } - return decoder.Decode(obj) -} - -func (tomlBinding) Bind(req *http.Request, obj any) error { - return decodeToml(req.Body, obj) -} - -func (tomlBinding) BindBody(body []byte, obj any) error { - return decodeToml(bytes.NewReader(body), obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/uri.go b/vendor/github.com/gin-gonic/gin/binding/uri.go deleted file mode 100644 index 2915106..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/uri.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -type uriBinding struct{} - -func (uriBinding) Name() string { - return "uri" -} - -func (uriBinding) BindUri(m map[string][]string, obj any) error { - if err := mapURI(obj, m); err != nil { - return err - } - return validate(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/xml.go b/vendor/github.com/gin-gonic/gin/binding/xml.go deleted file mode 100644 index a70f4ad..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/xml.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "bytes" - "encoding/xml" - "io" - "net/http" -) - -type xmlBinding struct{} - -func (xmlBinding) Name() string { - return "xml" -} - -func (xmlBinding) Bind(req *http.Request, obj any) error { - return decodeXML(req.Body, obj) -} - -func (xmlBinding) BindBody(body []byte, obj any) error { - return decodeXML(bytes.NewReader(body), obj) -} -func decodeXML(r io.Reader, obj any) error { - decoder := xml.NewDecoder(r) - if err := decoder.Decode(obj); err != nil { - return err - } - return validate(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/yaml.go b/vendor/github.com/gin-gonic/gin/binding/yaml.go deleted file mode 100644 index b0d36a3..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/yaml.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "bytes" - "io" - "net/http" - - "gopkg.in/yaml.v2" -) - -type yamlBinding struct{} - -func (yamlBinding) Name() string { - return "yaml" -} - -func (yamlBinding) Bind(req *http.Request, obj any) error { - return decodeYAML(req.Body, obj) -} - -func (yamlBinding) BindBody(body []byte, obj any) error { - return decodeYAML(bytes.NewReader(body), obj) -} - -func decodeYAML(r io.Reader, obj any) error { - decoder := yaml.NewDecoder(r) - if err := decoder.Decode(obj); err != nil { - return err - } - return validate(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/codecov.yml b/vendor/github.com/gin-gonic/gin/codecov.yml deleted file mode 100644 index c9c9a52..0000000 --- a/vendor/github.com/gin-gonic/gin/codecov.yml +++ /dev/null @@ -1,5 +0,0 @@ -coverage: - notify: - gitter: - default: - url: https://webhooks.gitter.im/e/d90dcdeeab2f1e357165 diff --git a/vendor/github.com/gin-gonic/gin/context.go b/vendor/github.com/gin-gonic/gin/context.go deleted file mode 100644 index b1ad95e..0000000 --- a/vendor/github.com/gin-gonic/gin/context.go +++ /dev/null @@ -1,1202 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "errors" - "io" - "io/ioutil" - "log" - "math" - "mime/multipart" - "net" - "net/http" - "net/url" - "os" - "strings" - "sync" - "time" - - "github.com/gin-contrib/sse" - "github.com/gin-gonic/gin/binding" - "github.com/gin-gonic/gin/render" -) - -// Content-Type MIME of the most common data formats. -const ( - MIMEJSON = binding.MIMEJSON - MIMEHTML = binding.MIMEHTML - MIMEXML = binding.MIMEXML - MIMEXML2 = binding.MIMEXML2 - MIMEPlain = binding.MIMEPlain - MIMEPOSTForm = binding.MIMEPOSTForm - MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm - MIMEYAML = binding.MIMEYAML - MIMETOML = binding.MIMETOML -) - -// BodyBytesKey indicates a default body bytes key. -const BodyBytesKey = "_gin-gonic/gin/bodybyteskey" - -// ContextKey is the key that a Context returns itself for. -const ContextKey = "_gin-gonic/gin/contextkey" - -// abortIndex represents a typical value used in abort functions. -const abortIndex int8 = math.MaxInt8 >> 1 - -// Context is the most important part of gin. It allows us to pass variables between middleware, -// manage the flow, validate the JSON of a request and render a JSON response for example. -type Context struct { - writermem responseWriter - Request *http.Request - Writer ResponseWriter - - Params Params - handlers HandlersChain - index int8 - fullPath string - - engine *Engine - params *Params - skippedNodes *[]skippedNode - - // This mutex protects Keys map. - mu sync.RWMutex - - // Keys is a key/value pair exclusively for the context of each request. - Keys map[string]any - - // Errors is a list of errors attached to all the handlers/middlewares who used this context. - Errors errorMsgs - - // Accepted defines a list of manually accepted formats for content negotiation. - Accepted []string - - // queryCache caches the query result from c.Request.URL.Query(). - queryCache url.Values - - // formCache caches c.Request.PostForm, which contains the parsed form data from POST, PATCH, - // or PUT body parameters. - formCache url.Values - - // SameSite allows a server to define a cookie attribute making it impossible for - // the browser to send this cookie along with cross-site requests. - sameSite http.SameSite -} - -/************************************/ -/********** CONTEXT CREATION ********/ -/************************************/ - -func (c *Context) reset() { - c.Writer = &c.writermem - c.Params = c.Params[:0] - c.handlers = nil - c.index = -1 - - c.fullPath = "" - c.Keys = nil - c.Errors = c.Errors[:0] - c.Accepted = nil - c.queryCache = nil - c.formCache = nil - c.sameSite = 0 - *c.params = (*c.params)[:0] - *c.skippedNodes = (*c.skippedNodes)[:0] -} - -// Copy returns a copy of the current context that can be safely used outside the request's scope. -// This has to be used when the context has to be passed to a goroutine. -func (c *Context) Copy() *Context { - cp := Context{ - writermem: c.writermem, - Request: c.Request, - Params: c.Params, - engine: c.engine, - } - cp.writermem.ResponseWriter = nil - cp.Writer = &cp.writermem - cp.index = abortIndex - cp.handlers = nil - cp.Keys = map[string]any{} - for k, v := range c.Keys { - cp.Keys[k] = v - } - paramCopy := make([]Param, len(cp.Params)) - copy(paramCopy, cp.Params) - cp.Params = paramCopy - return &cp -} - -// HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()", -// this function will return "main.handleGetUsers". -func (c *Context) HandlerName() string { - return nameOfFunction(c.handlers.Last()) -} - -// HandlerNames returns a list of all registered handlers for this context in descending order, -// following the semantics of HandlerName() -func (c *Context) HandlerNames() []string { - hn := make([]string, 0, len(c.handlers)) - for _, val := range c.handlers { - hn = append(hn, nameOfFunction(val)) - } - return hn -} - -// Handler returns the main handler. -func (c *Context) Handler() HandlerFunc { - return c.handlers.Last() -} - -// FullPath returns a matched route full path. For not found routes -// returns an empty string. -// router.GET("/user/:id", func(c *gin.Context) { -// c.FullPath() == "/user/:id" // true -// }) -func (c *Context) FullPath() string { - return c.fullPath -} - -/************************************/ -/*********** FLOW CONTROL ***********/ -/************************************/ - -// Next should be used only inside middleware. -// It executes the pending handlers in the chain inside the calling handler. -// See example in GitHub. -func (c *Context) Next() { - c.index++ - for c.index < int8(len(c.handlers)) { - c.handlers[c.index](c) - c.index++ - } -} - -// IsAborted returns true if the current context was aborted. -func (c *Context) IsAborted() bool { - return c.index >= abortIndex -} - -// Abort prevents pending handlers from being called. Note that this will not stop the current handler. -// Let's say you have an authorization middleware that validates that the current request is authorized. -// If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers -// for this request are not called. -func (c *Context) Abort() { - c.index = abortIndex -} - -// AbortWithStatus calls `Abort()` and writes the headers with the specified status code. -// For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401). -func (c *Context) AbortWithStatus(code int) { - c.Status(code) - c.Writer.WriteHeaderNow() - c.Abort() -} - -// AbortWithStatusJSON calls `Abort()` and then `JSON` internally. -// This method stops the chain, writes the status code and return a JSON body. -// It also sets the Content-Type as "application/json". -func (c *Context) AbortWithStatusJSON(code int, jsonObj any) { - c.Abort() - c.JSON(code, jsonObj) -} - -// AbortWithError calls `AbortWithStatus()` and `Error()` internally. -// This method stops the chain, writes the status code and pushes the specified error to `c.Errors`. -// See Context.Error() for more details. -func (c *Context) AbortWithError(code int, err error) *Error { - c.AbortWithStatus(code) - return c.Error(err) -} - -/************************************/ -/********* ERROR MANAGEMENT *********/ -/************************************/ - -// Error attaches an error to the current context. The error is pushed to a list of errors. -// It's a good idea to call Error for each error that occurred during the resolution of a request. -// A middleware can be used to collect all the errors and push them to a database together, -// print a log, or append it in the HTTP response. -// Error will panic if err is nil. -func (c *Context) Error(err error) *Error { - if err == nil { - panic("err is nil") - } - - var parsedError *Error - ok := errors.As(err, &parsedError) - if !ok { - parsedError = &Error{ - Err: err, - Type: ErrorTypePrivate, - } - } - - c.Errors = append(c.Errors, parsedError) - return parsedError -} - -/************************************/ -/******** METADATA MANAGEMENT********/ -/************************************/ - -// Set is used to store a new key/value pair exclusively for this context. -// It also lazy initializes c.Keys if it was not used previously. -func (c *Context) Set(key string, value any) { - c.mu.Lock() - if c.Keys == nil { - c.Keys = make(map[string]any) - } - - c.Keys[key] = value - c.mu.Unlock() -} - -// Get returns the value for the given key, ie: (value, true). -// If the value does not exist it returns (nil, false) -func (c *Context) Get(key string) (value any, exists bool) { - c.mu.RLock() - value, exists = c.Keys[key] - c.mu.RUnlock() - return -} - -// MustGet returns the value for the given key if it exists, otherwise it panics. -func (c *Context) MustGet(key string) any { - if value, exists := c.Get(key); exists { - return value - } - panic("Key \"" + key + "\" does not exist") -} - -// GetString returns the value associated with the key as a string. -func (c *Context) GetString(key string) (s string) { - if val, ok := c.Get(key); ok && val != nil { - s, _ = val.(string) - } - return -} - -// GetBool returns the value associated with the key as a boolean. -func (c *Context) GetBool(key string) (b bool) { - if val, ok := c.Get(key); ok && val != nil { - b, _ = val.(bool) - } - return -} - -// GetInt returns the value associated with the key as an integer. -func (c *Context) GetInt(key string) (i int) { - if val, ok := c.Get(key); ok && val != nil { - i, _ = val.(int) - } - return -} - -// GetInt64 returns the value associated with the key as an integer. -func (c *Context) GetInt64(key string) (i64 int64) { - if val, ok := c.Get(key); ok && val != nil { - i64, _ = val.(int64) - } - return -} - -// GetUint returns the value associated with the key as an unsigned integer. -func (c *Context) GetUint(key string) (ui uint) { - if val, ok := c.Get(key); ok && val != nil { - ui, _ = val.(uint) - } - return -} - -// GetUint64 returns the value associated with the key as an unsigned integer. -func (c *Context) GetUint64(key string) (ui64 uint64) { - if val, ok := c.Get(key); ok && val != nil { - ui64, _ = val.(uint64) - } - return -} - -// GetFloat64 returns the value associated with the key as a float64. -func (c *Context) GetFloat64(key string) (f64 float64) { - if val, ok := c.Get(key); ok && val != nil { - f64, _ = val.(float64) - } - return -} - -// GetTime returns the value associated with the key as time. -func (c *Context) GetTime(key string) (t time.Time) { - if val, ok := c.Get(key); ok && val != nil { - t, _ = val.(time.Time) - } - return -} - -// GetDuration returns the value associated with the key as a duration. -func (c *Context) GetDuration(key string) (d time.Duration) { - if val, ok := c.Get(key); ok && val != nil { - d, _ = val.(time.Duration) - } - return -} - -// GetStringSlice returns the value associated with the key as a slice of strings. -func (c *Context) GetStringSlice(key string) (ss []string) { - if val, ok := c.Get(key); ok && val != nil { - ss, _ = val.([]string) - } - return -} - -// GetStringMap returns the value associated with the key as a map of interfaces. -func (c *Context) GetStringMap(key string) (sm map[string]any) { - if val, ok := c.Get(key); ok && val != nil { - sm, _ = val.(map[string]any) - } - return -} - -// GetStringMapString returns the value associated with the key as a map of strings. -func (c *Context) GetStringMapString(key string) (sms map[string]string) { - if val, ok := c.Get(key); ok && val != nil { - sms, _ = val.(map[string]string) - } - return -} - -// GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings. -func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string) { - if val, ok := c.Get(key); ok && val != nil { - smss, _ = val.(map[string][]string) - } - return -} - -/************************************/ -/************ INPUT DATA ************/ -/************************************/ - -// Param returns the value of the URL param. -// It is a shortcut for c.Params.ByName(key) -// router.GET("/user/:id", func(c *gin.Context) { -// // a GET request to /user/john -// id := c.Param("id") // id == "john" -// }) -func (c *Context) Param(key string) string { - return c.Params.ByName(key) -} - -// AddParam adds param to context and -// replaces path param key with given value for e2e testing purposes -// Example Route: "/user/:id" -// AddParam("id", 1) -// Result: "/user/1" -func (c *Context) AddParam(key, value string) { - c.Params = append(c.Params, Param{Key: key, Value: value}) -} - -// Query returns the keyed url query value if it exists, -// otherwise it returns an empty string `("")`. -// It is shortcut for `c.Request.URL.Query().Get(key)` -// GET /path?id=1234&name=Manu&value= -// c.Query("id") == "1234" -// c.Query("name") == "Manu" -// c.Query("value") == "" -// c.Query("wtf") == "" -func (c *Context) Query(key string) (value string) { - value, _ = c.GetQuery(key) - return -} - -// DefaultQuery returns the keyed url query value if it exists, -// otherwise it returns the specified defaultValue string. -// See: Query() and GetQuery() for further information. -// GET /?name=Manu&lastname= -// c.DefaultQuery("name", "unknown") == "Manu" -// c.DefaultQuery("id", "none") == "none" -// c.DefaultQuery("lastname", "none") == "" -func (c *Context) DefaultQuery(key, defaultValue string) string { - if value, ok := c.GetQuery(key); ok { - return value - } - return defaultValue -} - -// GetQuery is like Query(), it returns the keyed url query value -// if it exists `(value, true)` (even when the value is an empty string), -// otherwise it returns `("", false)`. -// It is shortcut for `c.Request.URL.Query().Get(key)` -// GET /?name=Manu&lastname= -// ("Manu", true) == c.GetQuery("name") -// ("", false) == c.GetQuery("id") -// ("", true) == c.GetQuery("lastname") -func (c *Context) GetQuery(key string) (string, bool) { - if values, ok := c.GetQueryArray(key); ok { - return values[0], ok - } - return "", false -} - -// QueryArray returns a slice of strings for a given query key. -// The length of the slice depends on the number of params with the given key. -func (c *Context) QueryArray(key string) (values []string) { - values, _ = c.GetQueryArray(key) - return -} - -func (c *Context) initQueryCache() { - if c.queryCache == nil { - if c.Request != nil { - c.queryCache = c.Request.URL.Query() - } else { - c.queryCache = url.Values{} - } - } -} - -// GetQueryArray returns a slice of strings for a given query key, plus -// a boolean value whether at least one value exists for the given key. -func (c *Context) GetQueryArray(key string) (values []string, ok bool) { - c.initQueryCache() - values, ok = c.queryCache[key] - return -} - -// QueryMap returns a map for a given query key. -func (c *Context) QueryMap(key string) (dicts map[string]string) { - dicts, _ = c.GetQueryMap(key) - return -} - -// GetQueryMap returns a map for a given query key, plus a boolean value -// whether at least one value exists for the given key. -func (c *Context) GetQueryMap(key string) (map[string]string, bool) { - c.initQueryCache() - return c.get(c.queryCache, key) -} - -// PostForm returns the specified key from a POST urlencoded form or multipart form -// when it exists, otherwise it returns an empty string `("")`. -func (c *Context) PostForm(key string) (value string) { - value, _ = c.GetPostForm(key) - return -} - -// DefaultPostForm returns the specified key from a POST urlencoded form or multipart form -// when it exists, otherwise it returns the specified defaultValue string. -// See: PostForm() and GetPostForm() for further information. -func (c *Context) DefaultPostForm(key, defaultValue string) string { - if value, ok := c.GetPostForm(key); ok { - return value - } - return defaultValue -} - -// GetPostForm is like PostForm(key). It returns the specified key from a POST urlencoded -// form or multipart form when it exists `(value, true)` (even when the value is an empty string), -// otherwise it returns ("", false). -// For example, during a PATCH request to update the user's email: -// email=mail@example.com --> ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com" -// email= --> ("", true) := GetPostForm("email") // set email to "" -// --> ("", false) := GetPostForm("email") // do nothing with email -func (c *Context) GetPostForm(key string) (string, bool) { - if values, ok := c.GetPostFormArray(key); ok { - return values[0], ok - } - return "", false -} - -// PostFormArray returns a slice of strings for a given form key. -// The length of the slice depends on the number of params with the given key. -func (c *Context) PostFormArray(key string) (values []string) { - values, _ = c.GetPostFormArray(key) - return -} - -func (c *Context) initFormCache() { - if c.formCache == nil { - c.formCache = make(url.Values) - req := c.Request - if err := req.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil { - if !errors.Is(err, http.ErrNotMultipart) { - debugPrint("error on parse multipart form array: %v", err) - } - } - c.formCache = req.PostForm - } -} - -// GetPostFormArray returns a slice of strings for a given form key, plus -// a boolean value whether at least one value exists for the given key. -func (c *Context) GetPostFormArray(key string) (values []string, ok bool) { - c.initFormCache() - values, ok = c.formCache[key] - return -} - -// PostFormMap returns a map for a given form key. -func (c *Context) PostFormMap(key string) (dicts map[string]string) { - dicts, _ = c.GetPostFormMap(key) - return -} - -// GetPostFormMap returns a map for a given form key, plus a boolean value -// whether at least one value exists for the given key. -func (c *Context) GetPostFormMap(key string) (map[string]string, bool) { - c.initFormCache() - return c.get(c.formCache, key) -} - -// get is an internal method and returns a map which satisfy conditions. -func (c *Context) get(m map[string][]string, key string) (map[string]string, bool) { - dicts := make(map[string]string) - exist := false - for k, v := range m { - if i := strings.IndexByte(k, '['); i >= 1 && k[0:i] == key { - if j := strings.IndexByte(k[i+1:], ']'); j >= 1 { - exist = true - dicts[k[i+1:][:j]] = v[0] - } - } - } - return dicts, exist -} - -// FormFile returns the first file for the provided form key. -func (c *Context) FormFile(name string) (*multipart.FileHeader, error) { - if c.Request.MultipartForm == nil { - if err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil { - return nil, err - } - } - f, fh, err := c.Request.FormFile(name) - if err != nil { - return nil, err - } - f.Close() - return fh, err -} - -// MultipartForm is the parsed multipart form, including file uploads. -func (c *Context) MultipartForm() (*multipart.Form, error) { - err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory) - return c.Request.MultipartForm, err -} - -// SaveUploadedFile uploads the form file to specific dst. -func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error { - src, err := file.Open() - if err != nil { - return err - } - defer src.Close() - - out, err := os.Create(dst) - if err != nil { - return err - } - defer out.Close() - - _, err = io.Copy(out, src) - return err -} - -// Bind checks the Method and Content-Type to select a binding engine automatically, -// Depending on the "Content-Type" header different bindings are used, for example: -// "application/json" --> JSON binding -// "application/xml" --> XML binding -// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. -// It decodes the json payload into the struct specified as a pointer. -// It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid. -func (c *Context) Bind(obj any) error { - b := binding.Default(c.Request.Method, c.ContentType()) - return c.MustBindWith(obj, b) -} - -// BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON). -func (c *Context) BindJSON(obj any) error { - return c.MustBindWith(obj, binding.JSON) -} - -// BindXML is a shortcut for c.MustBindWith(obj, binding.BindXML). -func (c *Context) BindXML(obj any) error { - return c.MustBindWith(obj, binding.XML) -} - -// BindQuery is a shortcut for c.MustBindWith(obj, binding.Query). -func (c *Context) BindQuery(obj any) error { - return c.MustBindWith(obj, binding.Query) -} - -// BindYAML is a shortcut for c.MustBindWith(obj, binding.YAML). -func (c *Context) BindYAML(obj any) error { - return c.MustBindWith(obj, binding.YAML) -} - -// BindTOML is a shortcut for c.MustBindWith(obj, binding.TOML). -func (c *Context) BindTOML(obj interface{}) error { - return c.MustBindWith(obj, binding.TOML) -} - -// BindHeader is a shortcut for c.MustBindWith(obj, binding.Header). -func (c *Context) BindHeader(obj any) error { - return c.MustBindWith(obj, binding.Header) -} - -// BindUri binds the passed struct pointer using binding.Uri. -// It will abort the request with HTTP 400 if any error occurs. -func (c *Context) BindUri(obj any) error { - if err := c.ShouldBindUri(obj); err != nil { - c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck - return err - } - return nil -} - -// MustBindWith binds the passed struct pointer using the specified binding engine. -// It will abort the request with HTTP 400 if any error occurs. -// See the binding package. -func (c *Context) MustBindWith(obj any, b binding.Binding) error { - if err := c.ShouldBindWith(obj, b); err != nil { - c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck - return err - } - return nil -} - -// ShouldBind checks the Method and Content-Type to select a binding engine automatically, -// Depending on the "Content-Type" header different bindings are used, for example: -// "application/json" --> JSON binding -// "application/xml" --> XML binding -// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. -// It decodes the json payload into the struct specified as a pointer. -// Like c.Bind() but this method does not set the response status code to 400 or abort if input is not valid. -func (c *Context) ShouldBind(obj any) error { - b := binding.Default(c.Request.Method, c.ContentType()) - return c.ShouldBindWith(obj, b) -} - -// ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON). -func (c *Context) ShouldBindJSON(obj any) error { - return c.ShouldBindWith(obj, binding.JSON) -} - -// ShouldBindXML is a shortcut for c.ShouldBindWith(obj, binding.XML). -func (c *Context) ShouldBindXML(obj any) error { - return c.ShouldBindWith(obj, binding.XML) -} - -// ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, binding.Query). -func (c *Context) ShouldBindQuery(obj any) error { - return c.ShouldBindWith(obj, binding.Query) -} - -// ShouldBindYAML is a shortcut for c.ShouldBindWith(obj, binding.YAML). -func (c *Context) ShouldBindYAML(obj any) error { - return c.ShouldBindWith(obj, binding.YAML) -} - -// ShouldBindTOML is a shortcut for c.ShouldBindWith(obj, binding.TOML). -func (c *Context) ShouldBindTOML(obj interface{}) error { - return c.ShouldBindWith(obj, binding.TOML) -} - -// ShouldBindHeader is a shortcut for c.ShouldBindWith(obj, binding.Header). -func (c *Context) ShouldBindHeader(obj any) error { - return c.ShouldBindWith(obj, binding.Header) -} - -// ShouldBindUri binds the passed struct pointer using the specified binding engine. -func (c *Context) ShouldBindUri(obj any) error { - m := make(map[string][]string) - for _, v := range c.Params { - m[v.Key] = []string{v.Value} - } - return binding.Uri.BindUri(m, obj) -} - -// ShouldBindWith binds the passed struct pointer using the specified binding engine. -// See the binding package. -func (c *Context) ShouldBindWith(obj any, b binding.Binding) error { - return b.Bind(c.Request, obj) -} - -// ShouldBindBodyWith is similar with ShouldBindWith, but it stores the request -// body into the context, and reuse when it is called again. -// -// NOTE: This method reads the body before binding. So you should use -// ShouldBindWith for better performance if you need to call only once. -func (c *Context) ShouldBindBodyWith(obj any, bb binding.BindingBody) (err error) { - var body []byte - if cb, ok := c.Get(BodyBytesKey); ok { - if cbb, ok := cb.([]byte); ok { - body = cbb - } - } - if body == nil { - body, err = ioutil.ReadAll(c.Request.Body) - if err != nil { - return err - } - c.Set(BodyBytesKey, body) - } - return bb.BindBody(body, obj) -} - -// ClientIP implements one best effort algorithm to return the real client IP. -// It called c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not. -// If it is it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]). -// If the headers are not syntactically valid OR the remote IP does not correspond to a trusted proxy, -// the remote IP (coming from Request.RemoteAddr) is returned. -func (c *Context) ClientIP() string { - // Check if we're running on a trusted platform, continue running backwards if error - if c.engine.TrustedPlatform != "" { - // Developers can define their own header of Trusted Platform or use predefined constants - if addr := c.requestHeader(c.engine.TrustedPlatform); addr != "" { - return addr - } - } - - // Legacy "AppEngine" flag - if c.engine.AppEngine { - log.Println(`The AppEngine flag is going to be deprecated. Please check issues #2723 and #2739 and use 'TrustedPlatform: gin.PlatformGoogleAppEngine' instead.`) - if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" { - return addr - } - } - - // It also checks if the remoteIP is a trusted proxy or not. - // In order to perform this validation, it will see if the IP is contained within at least one of the CIDR blocks - // defined by Engine.SetTrustedProxies() - remoteIP := net.ParseIP(c.RemoteIP()) - if remoteIP == nil { - return "" - } - trusted := c.engine.isTrustedProxy(remoteIP) - - if trusted && c.engine.ForwardedByClientIP && c.engine.RemoteIPHeaders != nil { - for _, headerName := range c.engine.RemoteIPHeaders { - ip, valid := c.engine.validateHeader(c.requestHeader(headerName)) - if valid { - return ip - } - } - } - return remoteIP.String() -} - -// RemoteIP parses the IP from Request.RemoteAddr, normalizes and returns the IP (without the port). -func (c *Context) RemoteIP() string { - ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr)) - if err != nil { - return "" - } - return ip -} - -// ContentType returns the Content-Type header of the request. -func (c *Context) ContentType() string { - return filterFlags(c.requestHeader("Content-Type")) -} - -// IsWebsocket returns true if the request headers indicate that a websocket -// handshake is being initiated by the client. -func (c *Context) IsWebsocket() bool { - if strings.Contains(strings.ToLower(c.requestHeader("Connection")), "upgrade") && - strings.EqualFold(c.requestHeader("Upgrade"), "websocket") { - return true - } - return false -} - -func (c *Context) requestHeader(key string) string { - return c.Request.Header.Get(key) -} - -/************************************/ -/******** RESPONSE RENDERING ********/ -/************************************/ - -// bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function. -func bodyAllowedForStatus(status int) bool { - switch { - case status >= 100 && status <= 199: - return false - case status == http.StatusNoContent: - return false - case status == http.StatusNotModified: - return false - } - return true -} - -// Status sets the HTTP response code. -func (c *Context) Status(code int) { - c.Writer.WriteHeader(code) -} - -// Header is an intelligent shortcut for c.Writer.Header().Set(key, value). -// It writes a header in the response. -// If value == "", this method removes the header `c.Writer.Header().Del(key)` -func (c *Context) Header(key, value string) { - if value == "" { - c.Writer.Header().Del(key) - return - } - c.Writer.Header().Set(key, value) -} - -// GetHeader returns value from request headers. -func (c *Context) GetHeader(key string) string { - return c.requestHeader(key) -} - -// GetRawData returns stream data. -func (c *Context) GetRawData() ([]byte, error) { - return ioutil.ReadAll(c.Request.Body) -} - -// SetSameSite with cookie -func (c *Context) SetSameSite(samesite http.SameSite) { - c.sameSite = samesite -} - -// SetCookie adds a Set-Cookie header to the ResponseWriter's headers. -// The provided cookie must have a valid Name. Invalid cookies may be -// silently dropped. -func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) { - if path == "" { - path = "/" - } - http.SetCookie(c.Writer, &http.Cookie{ - Name: name, - Value: url.QueryEscape(value), - MaxAge: maxAge, - Path: path, - Domain: domain, - SameSite: c.sameSite, - Secure: secure, - HttpOnly: httpOnly, - }) -} - -// Cookie returns the named cookie provided in the request or -// ErrNoCookie if not found. And return the named cookie is unescaped. -// If multiple cookies match the given name, only one cookie will -// be returned. -func (c *Context) Cookie(name string) (string, error) { - cookie, err := c.Request.Cookie(name) - if err != nil { - return "", err - } - val, _ := url.QueryUnescape(cookie.Value) - return val, nil -} - -// Render writes the response headers and calls render.Render to render data. -func (c *Context) Render(code int, r render.Render) { - c.Status(code) - - if !bodyAllowedForStatus(code) { - r.WriteContentType(c.Writer) - c.Writer.WriteHeaderNow() - return - } - - if err := r.Render(c.Writer); err != nil { - panic(err) - } -} - -// HTML renders the HTTP template specified by its file name. -// It also updates the HTTP code and sets the Content-Type as "text/html". -// See http://golang.org/doc/articles/wiki/ -func (c *Context) HTML(code int, name string, obj any) { - instance := c.engine.HTMLRender.Instance(name, obj) - c.Render(code, instance) -} - -// IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body. -// It also sets the Content-Type as "application/json". -// WARNING: we recommend using this only for development purposes since printing pretty JSON is -// more CPU and bandwidth consuming. Use Context.JSON() instead. -func (c *Context) IndentedJSON(code int, obj any) { - c.Render(code, render.IndentedJSON{Data: obj}) -} - -// SecureJSON serializes the given struct as Secure JSON into the response body. -// Default prepends "while(1)," to response body if the given struct is array values. -// It also sets the Content-Type as "application/json". -func (c *Context) SecureJSON(code int, obj any) { - c.Render(code, render.SecureJSON{Prefix: c.engine.secureJSONPrefix, Data: obj}) -} - -// JSONP serializes the given struct as JSON into the response body. -// It adds padding to response body to request data from a server residing in a different domain than the client. -// It also sets the Content-Type as "application/javascript". -func (c *Context) JSONP(code int, obj any) { - callback := c.DefaultQuery("callback", "") - if callback == "" { - c.Render(code, render.JSON{Data: obj}) - return - } - c.Render(code, render.JsonpJSON{Callback: callback, Data: obj}) -} - -// JSON serializes the given struct as JSON into the response body. -// It also sets the Content-Type as "application/json". -func (c *Context) JSON(code int, obj any) { - c.Render(code, render.JSON{Data: obj}) -} - -// AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string. -// It also sets the Content-Type as "application/json". -func (c *Context) AsciiJSON(code int, obj any) { - c.Render(code, render.AsciiJSON{Data: obj}) -} - -// PureJSON serializes the given struct as JSON into the response body. -// PureJSON, unlike JSON, does not replace special html characters with their unicode entities. -func (c *Context) PureJSON(code int, obj any) { - c.Render(code, render.PureJSON{Data: obj}) -} - -// XML serializes the given struct as XML into the response body. -// It also sets the Content-Type as "application/xml". -func (c *Context) XML(code int, obj any) { - c.Render(code, render.XML{Data: obj}) -} - -// YAML serializes the given struct as YAML into the response body. -func (c *Context) YAML(code int, obj any) { - c.Render(code, render.YAML{Data: obj}) -} - -// TOML serializes the given struct as TOML into the response body. -func (c *Context) TOML(code int, obj interface{}) { - c.Render(code, render.TOML{Data: obj}) -} - -// ProtoBuf serializes the given struct as ProtoBuf into the response body. -func (c *Context) ProtoBuf(code int, obj any) { - c.Render(code, render.ProtoBuf{Data: obj}) -} - -// String writes the given string into the response body. -func (c *Context) String(code int, format string, values ...any) { - c.Render(code, render.String{Format: format, Data: values}) -} - -// Redirect returns an HTTP redirect to the specific location. -func (c *Context) Redirect(code int, location string) { - c.Render(-1, render.Redirect{ - Code: code, - Location: location, - Request: c.Request, - }) -} - -// Data writes some data into the body stream and updates the HTTP code. -func (c *Context) Data(code int, contentType string, data []byte) { - c.Render(code, render.Data{ - ContentType: contentType, - Data: data, - }) -} - -// DataFromReader writes the specified reader into the body stream and updates the HTTP code. -func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string) { - c.Render(code, render.Reader{ - Headers: extraHeaders, - ContentType: contentType, - ContentLength: contentLength, - Reader: reader, - }) -} - -// File writes the specified file into the body stream in an efficient way. -func (c *Context) File(filepath string) { - http.ServeFile(c.Writer, c.Request, filepath) -} - -// FileFromFS writes the specified file from http.FileSystem into the body stream in an efficient way. -func (c *Context) FileFromFS(filepath string, fs http.FileSystem) { - defer func(old string) { - c.Request.URL.Path = old - }(c.Request.URL.Path) - - c.Request.URL.Path = filepath - - http.FileServer(fs).ServeHTTP(c.Writer, c.Request) -} - -// FileAttachment writes the specified file into the body stream in an efficient way -// On the client side, the file will typically be downloaded with the given filename -func (c *Context) FileAttachment(filepath, filename string) { - if isASCII(filename) { - c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+filename+`"`) - } else { - c.Writer.Header().Set("Content-Disposition", `attachment; filename*=UTF-8''`+url.QueryEscape(filename)) - } - http.ServeFile(c.Writer, c.Request, filepath) -} - -// SSEvent writes a Server-Sent Event into the body stream. -func (c *Context) SSEvent(name string, message any) { - c.Render(-1, sse.Event{ - Event: name, - Data: message, - }) -} - -// Stream sends a streaming response and returns a boolean -// indicates "Is client disconnected in middle of stream" -func (c *Context) Stream(step func(w io.Writer) bool) bool { - w := c.Writer - clientGone := w.CloseNotify() - for { - select { - case <-clientGone: - return true - default: - keepOpen := step(w) - w.Flush() - if !keepOpen { - return false - } - } - } -} - -/************************************/ -/******** CONTENT NEGOTIATION *******/ -/************************************/ - -// Negotiate contains all negotiations data. -type Negotiate struct { - Offered []string - HTMLName string - HTMLData any - JSONData any - XMLData any - YAMLData any - Data any - TOMLData any -} - -// Negotiate calls different Render according to acceptable Accept format. -func (c *Context) Negotiate(code int, config Negotiate) { - switch c.NegotiateFormat(config.Offered...) { - case binding.MIMEJSON: - data := chooseData(config.JSONData, config.Data) - c.JSON(code, data) - - case binding.MIMEHTML: - data := chooseData(config.HTMLData, config.Data) - c.HTML(code, config.HTMLName, data) - - case binding.MIMEXML: - data := chooseData(config.XMLData, config.Data) - c.XML(code, data) - - case binding.MIMEYAML: - data := chooseData(config.YAMLData, config.Data) - c.YAML(code, data) - - case binding.MIMETOML: - data := chooseData(config.TOMLData, config.Data) - c.TOML(code, data) - - default: - c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) // nolint: errcheck - } -} - -// NegotiateFormat returns an acceptable Accept format. -func (c *Context) NegotiateFormat(offered ...string) string { - assert1(len(offered) > 0, "you must provide at least one offer") - - if c.Accepted == nil { - c.Accepted = parseAccept(c.requestHeader("Accept")) - } - if len(c.Accepted) == 0 { - return offered[0] - } - for _, accepted := range c.Accepted { - for _, offer := range offered { - // According to RFC 2616 and RFC 2396, non-ASCII characters are not allowed in headers, - // therefore we can just iterate over the string without casting it into []rune - i := 0 - for ; i < len(accepted); i++ { - if accepted[i] == '*' || offer[i] == '*' { - return offer - } - if accepted[i] != offer[i] { - break - } - } - if i == len(accepted) { - return offer - } - } - } - return "" -} - -// SetAccepted sets Accept header data. -func (c *Context) SetAccepted(formats ...string) { - c.Accepted = formats -} - -/************************************/ -/***** GOLANG.ORG/X/NET/CONTEXT *****/ -/************************************/ - -// Deadline returns that there is no deadline (ok==false) when c.Request has no Context. -func (c *Context) Deadline() (deadline time.Time, ok bool) { - if !c.engine.ContextWithFallback || c.Request == nil || c.Request.Context() == nil { - return - } - return c.Request.Context().Deadline() -} - -// Done returns nil (chan which will wait forever) when c.Request has no Context. -func (c *Context) Done() <-chan struct{} { - if !c.engine.ContextWithFallback || c.Request == nil || c.Request.Context() == nil { - return nil - } - return c.Request.Context().Done() -} - -// Err returns nil when c.Request has no Context. -func (c *Context) Err() error { - if !c.engine.ContextWithFallback || c.Request == nil || c.Request.Context() == nil { - return nil - } - return c.Request.Context().Err() -} - -// Value returns the value associated with this context for key, or nil -// if no value is associated with key. Successive calls to Value with -// the same key returns the same result. -func (c *Context) Value(key any) any { - if key == 0 { - return c.Request - } - if key == ContextKey { - return c - } - if keyAsString, ok := key.(string); ok { - if val, exists := c.Get(keyAsString); exists { - return val - } - } - if !c.engine.ContextWithFallback || c.Request == nil || c.Request.Context() == nil { - return nil - } - return c.Request.Context().Value(key) -} diff --git a/vendor/github.com/gin-gonic/gin/context_appengine.go b/vendor/github.com/gin-gonic/gin/context_appengine.go deleted file mode 100644 index 931313f..0000000 --- a/vendor/github.com/gin-gonic/gin/context_appengine.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build appengine -// +build appengine - -package gin - -func init() { - defaultPlatform = PlatformGoogleAppEngine -} diff --git a/vendor/github.com/gin-gonic/gin/debug.go b/vendor/github.com/gin-gonic/gin/debug.go deleted file mode 100644 index 25fd7c8..0000000 --- a/vendor/github.com/gin-gonic/gin/debug.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "fmt" - "html/template" - "runtime" - "strconv" - "strings" -) - -const ginSupportMinGoVer = 14 - -// IsDebugging returns true if the framework is running in debug mode. -// Use SetMode(gin.ReleaseMode) to disable debug mode. -func IsDebugging() bool { - return ginMode == debugCode -} - -// DebugPrintRouteFunc indicates debug log output format. -var DebugPrintRouteFunc func(httpMethod, absolutePath, handlerName string, nuHandlers int) - -func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersChain) { - if IsDebugging() { - nuHandlers := len(handlers) - handlerName := nameOfFunction(handlers.Last()) - if DebugPrintRouteFunc == nil { - debugPrint("%-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers) - } else { - DebugPrintRouteFunc(httpMethod, absolutePath, handlerName, nuHandlers) - } - } -} - -func debugPrintLoadTemplate(tmpl *template.Template) { - if IsDebugging() { - var buf strings.Builder - for _, tmpl := range tmpl.Templates() { - buf.WriteString("\t- ") - buf.WriteString(tmpl.Name()) - buf.WriteString("\n") - } - debugPrint("Loaded HTML Templates (%d): \n%s\n", len(tmpl.Templates()), buf.String()) - } -} - -func debugPrint(format string, values ...any) { - if IsDebugging() { - if !strings.HasSuffix(format, "\n") { - format += "\n" - } - fmt.Fprintf(DefaultWriter, "[GIN-debug] "+format, values...) - } -} - -func getMinVer(v string) (uint64, error) { - first := strings.IndexByte(v, '.') - last := strings.LastIndexByte(v, '.') - if first == last { - return strconv.ParseUint(v[first+1:], 10, 64) - } - return strconv.ParseUint(v[first+1:last], 10, 64) -} - -func debugPrintWARNINGDefault() { - if v, e := getMinVer(runtime.Version()); e == nil && v <= ginSupportMinGoVer { - debugPrint(`[WARNING] Now Gin requires Go 1.14+. - -`) - } - debugPrint(`[WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. - -`) -} - -func debugPrintWARNINGNew() { - debugPrint(`[WARNING] Running in "debug" mode. Switch to "release" mode in production. - - using env: export GIN_MODE=release - - using code: gin.SetMode(gin.ReleaseMode) - -`) -} - -func debugPrintWARNINGSetHTMLTemplate() { - debugPrint(`[WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called -at initialization. ie. before any route is registered or the router is listening in a socket: - - router := gin.Default() - router.SetHTMLTemplate(template) // << good place - -`) -} - -func debugPrintError(err error) { - if err != nil && IsDebugging() { - fmt.Fprintf(DefaultErrorWriter, "[GIN-debug] [ERROR] %v\n", err) - } -} diff --git a/vendor/github.com/gin-gonic/gin/deprecated.go b/vendor/github.com/gin-gonic/gin/deprecated.go deleted file mode 100644 index fdad855..0000000 --- a/vendor/github.com/gin-gonic/gin/deprecated.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "log" - - "github.com/gin-gonic/gin/binding" -) - -// BindWith binds the passed struct pointer using the specified binding engine. -// See the binding package. -func (c *Context) BindWith(obj any, b binding.Binding) error { - log.Println(`BindWith(\"interface{}, binding.Binding\") error is going to - be deprecated, please check issue #662 and either use MustBindWith() if you - want HTTP 400 to be automatically returned if any error occur, or use - ShouldBindWith() if you need to manage the error.`) - return c.MustBindWith(obj, b) -} diff --git a/vendor/github.com/gin-gonic/gin/doc.go b/vendor/github.com/gin-gonic/gin/doc.go deleted file mode 100644 index 1bd0386..0000000 --- a/vendor/github.com/gin-gonic/gin/doc.go +++ /dev/null @@ -1,6 +0,0 @@ -/* -Package gin implements a HTTP web framework called gin. - -See https://gin-gonic.com/ for more information about gin. -*/ -package gin // import "github.com/gin-gonic/gin" diff --git a/vendor/github.com/gin-gonic/gin/errors.go b/vendor/github.com/gin-gonic/gin/errors.go deleted file mode 100644 index 2853ce8..0000000 --- a/vendor/github.com/gin-gonic/gin/errors.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "fmt" - "reflect" - "strings" - - "github.com/gin-gonic/gin/internal/json" -) - -// ErrorType is an unsigned 64-bit error code as defined in the gin spec. -type ErrorType uint64 - -const ( - // ErrorTypeBind is used when Context.Bind() fails. - ErrorTypeBind ErrorType = 1 << 63 - // ErrorTypeRender is used when Context.Render() fails. - ErrorTypeRender ErrorType = 1 << 62 - // ErrorTypePrivate indicates a private error. - ErrorTypePrivate ErrorType = 1 << 0 - // ErrorTypePublic indicates a public error. - ErrorTypePublic ErrorType = 1 << 1 - // ErrorTypeAny indicates any other error. - ErrorTypeAny ErrorType = 1<<64 - 1 - // ErrorTypeNu indicates any other error. - ErrorTypeNu = 2 -) - -// Error represents a error's specification. -type Error struct { - Err error - Type ErrorType - Meta any -} - -type errorMsgs []*Error - -var _ error = &Error{} - -// SetType sets the error's type. -func (msg *Error) SetType(flags ErrorType) *Error { - msg.Type = flags - return msg -} - -// SetMeta sets the error's meta data. -func (msg *Error) SetMeta(data any) *Error { - msg.Meta = data - return msg -} - -// JSON creates a properly formatted JSON -func (msg *Error) JSON() any { - jsonData := H{} - if msg.Meta != nil { - value := reflect.ValueOf(msg.Meta) - switch value.Kind() { - case reflect.Struct: - return msg.Meta - case reflect.Map: - for _, key := range value.MapKeys() { - jsonData[key.String()] = value.MapIndex(key).Interface() - } - default: - jsonData["meta"] = msg.Meta - } - } - if _, ok := jsonData["error"]; !ok { - jsonData["error"] = msg.Error() - } - return jsonData -} - -// MarshalJSON implements the json.Marshaller interface. -func (msg *Error) MarshalJSON() ([]byte, error) { - return json.Marshal(msg.JSON()) -} - -// Error implements the error interface. -func (msg Error) Error() string { - return msg.Err.Error() -} - -// IsType judges one error. -func (msg *Error) IsType(flags ErrorType) bool { - return (msg.Type & flags) > 0 -} - -// Unwrap returns the wrapped error, to allow interoperability with errors.Is(), errors.As() and errors.Unwrap() -func (msg *Error) Unwrap() error { - return msg.Err -} - -// ByType returns a readonly copy filtered the byte. -// ie ByType(gin.ErrorTypePublic) returns a slice of errors with type=ErrorTypePublic. -func (a errorMsgs) ByType(typ ErrorType) errorMsgs { - if len(a) == 0 { - return nil - } - if typ == ErrorTypeAny { - return a - } - var result errorMsgs - for _, msg := range a { - if msg.IsType(typ) { - result = append(result, msg) - } - } - return result -} - -// Last returns the last error in the slice. It returns nil if the array is empty. -// Shortcut for errors[len(errors)-1]. -func (a errorMsgs) Last() *Error { - if length := len(a); length > 0 { - return a[length-1] - } - return nil -} - -// Errors returns an array with all the error messages. -// Example: -// c.Error(errors.New("first")) -// c.Error(errors.New("second")) -// c.Error(errors.New("third")) -// c.Errors.Errors() // == []string{"first", "second", "third"} -func (a errorMsgs) Errors() []string { - if len(a) == 0 { - return nil - } - errorStrings := make([]string, len(a)) - for i, err := range a { - errorStrings[i] = err.Error() - } - return errorStrings -} - -func (a errorMsgs) JSON() any { - switch length := len(a); length { - case 0: - return nil - case 1: - return a.Last().JSON() - default: - jsonData := make([]any, length) - for i, err := range a { - jsonData[i] = err.JSON() - } - return jsonData - } -} - -// MarshalJSON implements the json.Marshaller interface. -func (a errorMsgs) MarshalJSON() ([]byte, error) { - return json.Marshal(a.JSON()) -} - -func (a errorMsgs) String() string { - if len(a) == 0 { - return "" - } - var buffer strings.Builder - for i, msg := range a { - fmt.Fprintf(&buffer, "Error #%02d: %s\n", i+1, msg.Err) - if msg.Meta != nil { - fmt.Fprintf(&buffer, " Meta: %v\n", msg.Meta) - } - } - return buffer.String() -} diff --git a/vendor/github.com/gin-gonic/gin/fs.go b/vendor/github.com/gin-gonic/gin/fs.go deleted file mode 100644 index 6427473..0000000 --- a/vendor/github.com/gin-gonic/gin/fs.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2017 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "net/http" - "os" -) - -type onlyFilesFS struct { - fs http.FileSystem -} - -type neuteredReaddirFile struct { - http.File -} - -// Dir returns a http.FileSystem that can be used by http.FileServer(). It is used internally -// in router.Static(). -// if listDirectory == true, then it works the same as http.Dir() otherwise it returns -// a filesystem that prevents http.FileServer() to list the directory files. -func Dir(root string, listDirectory bool) http.FileSystem { - fs := http.Dir(root) - if listDirectory { - return fs - } - return &onlyFilesFS{fs} -} - -// Open conforms to http.Filesystem. -func (fs onlyFilesFS) Open(name string) (http.File, error) { - f, err := fs.fs.Open(name) - if err != nil { - return nil, err - } - return neuteredReaddirFile{f}, nil -} - -// Readdir overrides the http.File default implementation. -func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) { - // this disables directory listing - return nil, nil -} diff --git a/vendor/github.com/gin-gonic/gin/gin.go b/vendor/github.com/gin-gonic/gin/gin.go deleted file mode 100644 index f932429..0000000 --- a/vendor/github.com/gin-gonic/gin/gin.go +++ /dev/null @@ -1,704 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "fmt" - "html/template" - "net" - "net/http" - "os" - "path" - "strings" - "sync" - - "github.com/gin-gonic/gin/internal/bytesconv" - "github.com/gin-gonic/gin/render" - "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" -) - -const defaultMultipartMemory = 32 << 20 // 32 MB - -var ( - default404Body = []byte("404 page not found") - default405Body = []byte("405 method not allowed") -) - -var defaultPlatform string - -var defaultTrustedCIDRs = []*net.IPNet{ - { // 0.0.0.0/0 (IPv4) - IP: net.IP{0x0, 0x0, 0x0, 0x0}, - Mask: net.IPMask{0x0, 0x0, 0x0, 0x0}, - }, - { // ::/0 (IPv6) - IP: net.IP{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, - Mask: net.IPMask{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, - }, -} - -// HandlerFunc defines the handler used by gin middleware as return value. -type HandlerFunc func(*Context) - -// HandlersChain defines a HandlerFunc slice. -type HandlersChain []HandlerFunc - -// Last returns the last handler in the chain. i.e. the last handler is the main one. -func (c HandlersChain) Last() HandlerFunc { - if length := len(c); length > 0 { - return c[length-1] - } - return nil -} - -// RouteInfo represents a request route's specification which contains method and path and its handler. -type RouteInfo struct { - Method string - Path string - Handler string - HandlerFunc HandlerFunc -} - -// RoutesInfo defines a RouteInfo slice. -type RoutesInfo []RouteInfo - -// Trusted platforms -const ( - // PlatformGoogleAppEngine when running on Google App Engine. Trust X-Appengine-Remote-Addr - // for determining the client's IP - PlatformGoogleAppEngine = "X-Appengine-Remote-Addr" - // PlatformCloudflare when using Cloudflare's CDN. Trust CF-Connecting-IP for determining - // the client's IP - PlatformCloudflare = "CF-Connecting-IP" -) - -// Engine is the framework's instance, it contains the muxer, middleware and configuration settings. -// Create an instance of Engine, by using New() or Default() -type Engine struct { - RouterGroup - - // RedirectTrailingSlash enables automatic redirection if the current route can't be matched but a - // handler for the path with (without) the trailing slash exists. - // For example if /foo/ is requested but a route only exists for /foo, the - // client is redirected to /foo with http status code 301 for GET requests - // and 307 for all other request methods. - RedirectTrailingSlash bool - - // RedirectFixedPath if enabled, the router tries to fix the current request path, if no - // handle is registered for it. - // First superfluous path elements like ../ or // are removed. - // Afterwards the router does a case-insensitive lookup of the cleaned path. - // If a handle can be found for this route, the router makes a redirection - // to the corrected path with status code 301 for GET requests and 307 for - // all other request methods. - // For example /FOO and /..//Foo could be redirected to /foo. - // RedirectTrailingSlash is independent of this option. - RedirectFixedPath bool - - // HandleMethodNotAllowed if enabled, the router checks if another method is allowed for the - // current route, if the current request can not be routed. - // If this is the case, the request is answered with 'Method Not Allowed' - // and HTTP status code 405. - // If no other Method is allowed, the request is delegated to the NotFound - // handler. - HandleMethodNotAllowed bool - - // ForwardedByClientIP if enabled, client IP will be parsed from the request's headers that - // match those stored at `(*gin.Engine).RemoteIPHeaders`. If no IP was - // fetched, it falls back to the IP obtained from - // `(*gin.Context).Request.RemoteAddr`. - ForwardedByClientIP bool - - // AppEngine was deprecated. - // Deprecated: USE `TrustedPlatform` WITH VALUE `gin.PlatformGoogleAppEngine` INSTEAD - // #726 #755 If enabled, it will trust some headers starting with - // 'X-AppEngine...' for better integration with that PaaS. - AppEngine bool - - // UseRawPath if enabled, the url.RawPath will be used to find parameters. - UseRawPath bool - - // UnescapePathValues if true, the path value will be unescaped. - // If UseRawPath is false (by default), the UnescapePathValues effectively is true, - // as url.Path gonna be used, which is already unescaped. - UnescapePathValues bool - - // RemoveExtraSlash a parameter can be parsed from the URL even with extra slashes. - // See the PR #1817 and issue #1644 - RemoveExtraSlash bool - - // RemoteIPHeaders list of headers used to obtain the client IP when - // `(*gin.Engine).ForwardedByClientIP` is `true` and - // `(*gin.Context).Request.RemoteAddr` is matched by at least one of the - // network origins of list defined by `(*gin.Engine).SetTrustedProxies()`. - RemoteIPHeaders []string - - // TrustedPlatform if set to a constant of value gin.Platform*, trusts the headers set by - // that platform, for example to determine the client IP - TrustedPlatform string - - // MaxMultipartMemory value of 'maxMemory' param that is given to http.Request's ParseMultipartForm - // method call. - MaxMultipartMemory int64 - - // UseH2C enable h2c support. - UseH2C bool - - // ContextWithFallback enable fallback Context.Deadline(), Context.Done(), Context.Err() and Context.Value() when Context.Request.Context() is not nil. - ContextWithFallback bool - - delims render.Delims - secureJSONPrefix string - HTMLRender render.HTMLRender - FuncMap template.FuncMap - allNoRoute HandlersChain - allNoMethod HandlersChain - noRoute HandlersChain - noMethod HandlersChain - pool sync.Pool - trees methodTrees - maxParams uint16 - maxSections uint16 - trustedProxies []string - trustedCIDRs []*net.IPNet -} - -var _ IRouter = &Engine{} - -// New returns a new blank Engine instance without any middleware attached. -// By default, the configuration is: -// - RedirectTrailingSlash: true -// - RedirectFixedPath: false -// - HandleMethodNotAllowed: false -// - ForwardedByClientIP: true -// - UseRawPath: false -// - UnescapePathValues: true -func New() *Engine { - debugPrintWARNINGNew() - engine := &Engine{ - RouterGroup: RouterGroup{ - Handlers: nil, - basePath: "/", - root: true, - }, - FuncMap: template.FuncMap{}, - RedirectTrailingSlash: true, - RedirectFixedPath: false, - HandleMethodNotAllowed: false, - ForwardedByClientIP: true, - RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"}, - TrustedPlatform: defaultPlatform, - UseRawPath: false, - RemoveExtraSlash: false, - UnescapePathValues: true, - MaxMultipartMemory: defaultMultipartMemory, - trees: make(methodTrees, 0, 9), - delims: render.Delims{Left: "{{", Right: "}}"}, - secureJSONPrefix: "while(1);", - trustedProxies: []string{"0.0.0.0/0", "::/0"}, - trustedCIDRs: defaultTrustedCIDRs, - } - engine.RouterGroup.engine = engine - engine.pool.New = func() any { - return engine.allocateContext() - } - return engine -} - -// Default returns an Engine instance with the Logger and Recovery middleware already attached. -func Default() *Engine { - debugPrintWARNINGDefault() - engine := New() - engine.Use(Logger(), Recovery()) - return engine -} - -func (engine *Engine) Handler() http.Handler { - if !engine.UseH2C { - return engine - } - - h2s := &http2.Server{} - return h2c.NewHandler(engine, h2s) -} - -func (engine *Engine) allocateContext() *Context { - v := make(Params, 0, engine.maxParams) - skippedNodes := make([]skippedNode, 0, engine.maxSections) - return &Context{engine: engine, params: &v, skippedNodes: &skippedNodes} -} - -// Delims sets template left and right delims and returns an Engine instance. -func (engine *Engine) Delims(left, right string) *Engine { - engine.delims = render.Delims{Left: left, Right: right} - return engine -} - -// SecureJsonPrefix sets the secureJSONPrefix used in Context.SecureJSON. -func (engine *Engine) SecureJsonPrefix(prefix string) *Engine { - engine.secureJSONPrefix = prefix - return engine -} - -// LoadHTMLGlob loads HTML files identified by glob pattern -// and associates the result with HTML renderer. -func (engine *Engine) LoadHTMLGlob(pattern string) { - left := engine.delims.Left - right := engine.delims.Right - templ := template.Must(template.New("").Delims(left, right).Funcs(engine.FuncMap).ParseGlob(pattern)) - - if IsDebugging() { - debugPrintLoadTemplate(templ) - engine.HTMLRender = render.HTMLDebug{Glob: pattern, FuncMap: engine.FuncMap, Delims: engine.delims} - return - } - - engine.SetHTMLTemplate(templ) -} - -// LoadHTMLFiles loads a slice of HTML files -// and associates the result with HTML renderer. -func (engine *Engine) LoadHTMLFiles(files ...string) { - if IsDebugging() { - engine.HTMLRender = render.HTMLDebug{Files: files, FuncMap: engine.FuncMap, Delims: engine.delims} - return - } - - templ := template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseFiles(files...)) - engine.SetHTMLTemplate(templ) -} - -// SetHTMLTemplate associate a template with HTML renderer. -func (engine *Engine) SetHTMLTemplate(templ *template.Template) { - if len(engine.trees) > 0 { - debugPrintWARNINGSetHTMLTemplate() - } - - engine.HTMLRender = render.HTMLProduction{Template: templ.Funcs(engine.FuncMap)} -} - -// SetFuncMap sets the FuncMap used for template.FuncMap. -func (engine *Engine) SetFuncMap(funcMap template.FuncMap) { - engine.FuncMap = funcMap -} - -// NoRoute adds handlers for NoRoute. It returns a 404 code by default. -func (engine *Engine) NoRoute(handlers ...HandlerFunc) { - engine.noRoute = handlers - engine.rebuild404Handlers() -} - -// NoMethod sets the handlers called when Engine.HandleMethodNotAllowed = true. -func (engine *Engine) NoMethod(handlers ...HandlerFunc) { - engine.noMethod = handlers - engine.rebuild405Handlers() -} - -// Use attaches a global middleware to the router. i.e. the middleware attached through Use() will be -// included in the handlers chain for every single request. Even 404, 405, static files... -// For example, this is the right place for a logger or error management middleware. -func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes { - engine.RouterGroup.Use(middleware...) - engine.rebuild404Handlers() - engine.rebuild405Handlers() - return engine -} - -func (engine *Engine) rebuild404Handlers() { - engine.allNoRoute = engine.combineHandlers(engine.noRoute) -} - -func (engine *Engine) rebuild405Handlers() { - engine.allNoMethod = engine.combineHandlers(engine.noMethod) -} - -func (engine *Engine) addRoute(method, path string, handlers HandlersChain) { - assert1(path[0] == '/', "path must begin with '/'") - assert1(method != "", "HTTP method can not be empty") - assert1(len(handlers) > 0, "there must be at least one handler") - - debugPrintRoute(method, path, handlers) - - root := engine.trees.get(method) - if root == nil { - root = new(node) - root.fullPath = "/" - engine.trees = append(engine.trees, methodTree{method: method, root: root}) - } - root.addRoute(path, handlers) - - // Update maxParams - if paramsCount := countParams(path); paramsCount > engine.maxParams { - engine.maxParams = paramsCount - } - - if sectionsCount := countSections(path); sectionsCount > engine.maxSections { - engine.maxSections = sectionsCount - } -} - -// Routes returns a slice of registered routes, including some useful information, such as: -// the http method, path and the handler name. -func (engine *Engine) Routes() (routes RoutesInfo) { - for _, tree := range engine.trees { - routes = iterate("", tree.method, routes, tree.root) - } - return routes -} - -func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo { - path += root.path - if len(root.handlers) > 0 { - handlerFunc := root.handlers.Last() - routes = append(routes, RouteInfo{ - Method: method, - Path: path, - Handler: nameOfFunction(handlerFunc), - HandlerFunc: handlerFunc, - }) - } - for _, child := range root.children { - routes = iterate(path, method, routes, child) - } - return routes -} - -// Run attaches the router to a http.Server and starts listening and serving HTTP requests. -// It is a shortcut for http.ListenAndServe(addr, router) -// Note: this method will block the calling goroutine indefinitely unless an error happens. -func (engine *Engine) Run(addr ...string) (err error) { - defer func() { debugPrintError(err) }() - - if engine.isUnsafeTrustedProxies() { - debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" + - "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.") - } - - address := resolveAddress(addr) - debugPrint("Listening and serving HTTP on %s\n", address) - err = http.ListenAndServe(address, engine.Handler()) - return -} - -func (engine *Engine) prepareTrustedCIDRs() ([]*net.IPNet, error) { - if engine.trustedProxies == nil { - return nil, nil - } - - cidr := make([]*net.IPNet, 0, len(engine.trustedProxies)) - for _, trustedProxy := range engine.trustedProxies { - if !strings.Contains(trustedProxy, "/") { - ip := parseIP(trustedProxy) - if ip == nil { - return cidr, &net.ParseError{Type: "IP address", Text: trustedProxy} - } - - switch len(ip) { - case net.IPv4len: - trustedProxy += "/32" - case net.IPv6len: - trustedProxy += "/128" - } - } - _, cidrNet, err := net.ParseCIDR(trustedProxy) - if err != nil { - return cidr, err - } - cidr = append(cidr, cidrNet) - } - return cidr, nil -} - -// SetTrustedProxies set a list of network origins (IPv4 addresses, -// IPv4 CIDRs, IPv6 addresses or IPv6 CIDRs) from which to trust -// request's headers that contain alternative client IP when -// `(*gin.Engine).ForwardedByClientIP` is `true`. `TrustedProxies` -// feature is enabled by default, and it also trusts all proxies -// by default. If you want to disable this feature, use -// Engine.SetTrustedProxies(nil), then Context.ClientIP() will -// return the remote address directly. -func (engine *Engine) SetTrustedProxies(trustedProxies []string) error { - engine.trustedProxies = trustedProxies - return engine.parseTrustedProxies() -} - -// isUnsafeTrustedProxies checks if Engine.trustedCIDRs contains all IPs, it's not safe if it has (returns true) -func (engine *Engine) isUnsafeTrustedProxies() bool { - return engine.isTrustedProxy(net.ParseIP("0.0.0.0")) || engine.isTrustedProxy(net.ParseIP("::")) -} - -// parseTrustedProxies parse Engine.trustedProxies to Engine.trustedCIDRs -func (engine *Engine) parseTrustedProxies() error { - trustedCIDRs, err := engine.prepareTrustedCIDRs() - engine.trustedCIDRs = trustedCIDRs - return err -} - -// isTrustedProxy will check whether the IP address is included in the trusted list according to Engine.trustedCIDRs -func (engine *Engine) isTrustedProxy(ip net.IP) bool { - if engine.trustedCIDRs == nil { - return false - } - for _, cidr := range engine.trustedCIDRs { - if cidr.Contains(ip) { - return true - } - } - return false -} - -// validateHeader will parse X-Forwarded-For header and return the trusted client IP address -func (engine *Engine) validateHeader(header string) (clientIP string, valid bool) { - if header == "" { - return "", false - } - items := strings.Split(header, ",") - for i := len(items) - 1; i >= 0; i-- { - ipStr := strings.TrimSpace(items[i]) - ip := net.ParseIP(ipStr) - if ip == nil { - break - } - - // X-Forwarded-For is appended by proxy - // Check IPs in reverse order and stop when find untrusted proxy - if (i == 0) || (!engine.isTrustedProxy(ip)) { - return ipStr, true - } - } - return "", false -} - -// parseIP parse a string representation of an IP and returns a net.IP with the -// minimum byte representation or nil if input is invalid. -func parseIP(ip string) net.IP { - parsedIP := net.ParseIP(ip) - - if ipv4 := parsedIP.To4(); ipv4 != nil { - // return ip in a 4-byte representation - return ipv4 - } - - // return ip in a 16-byte representation or nil - return parsedIP -} - -// RunTLS attaches the router to a http.Server and starts listening and serving HTTPS (secure) requests. -// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router) -// Note: this method will block the calling goroutine indefinitely unless an error happens. -func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err error) { - debugPrint("Listening and serving HTTPS on %s\n", addr) - defer func() { debugPrintError(err) }() - - if engine.isUnsafeTrustedProxies() { - debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" + - "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.") - } - - err = http.ListenAndServeTLS(addr, certFile, keyFile, engine.Handler()) - return -} - -// RunUnix attaches the router to a http.Server and starts listening and serving HTTP requests -// through the specified unix socket (i.e. a file). -// Note: this method will block the calling goroutine indefinitely unless an error happens. -func (engine *Engine) RunUnix(file string) (err error) { - debugPrint("Listening and serving HTTP on unix:/%s", file) - defer func() { debugPrintError(err) }() - - if engine.isUnsafeTrustedProxies() { - debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" + - "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.") - } - - listener, err := net.Listen("unix", file) - if err != nil { - return - } - defer listener.Close() - defer os.Remove(file) - - err = http.Serve(listener, engine.Handler()) - return -} - -// RunFd attaches the router to a http.Server and starts listening and serving HTTP requests -// through the specified file descriptor. -// Note: this method will block the calling goroutine indefinitely unless an error happens. -func (engine *Engine) RunFd(fd int) (err error) { - debugPrint("Listening and serving HTTP on fd@%d", fd) - defer func() { debugPrintError(err) }() - - if engine.isUnsafeTrustedProxies() { - debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" + - "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.") - } - - f := os.NewFile(uintptr(fd), fmt.Sprintf("fd@%d", fd)) - listener, err := net.FileListener(f) - if err != nil { - return - } - defer listener.Close() - err = engine.RunListener(listener) - return -} - -// RunListener attaches the router to a http.Server and starts listening and serving HTTP requests -// through the specified net.Listener -func (engine *Engine) RunListener(listener net.Listener) (err error) { - debugPrint("Listening and serving HTTP on listener what's bind with address@%s", listener.Addr()) - defer func() { debugPrintError(err) }() - - if engine.isUnsafeTrustedProxies() { - debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" + - "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.") - } - - err = http.Serve(listener, engine.Handler()) - return -} - -// ServeHTTP conforms to the http.Handler interface. -func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { - c := engine.pool.Get().(*Context) - c.writermem.reset(w) - c.Request = req - c.reset() - - engine.handleHTTPRequest(c) - - engine.pool.Put(c) -} - -// HandleContext re-enters a context that has been rewritten. -// This can be done by setting c.Request.URL.Path to your new target. -// Disclaimer: You can loop yourself to deal with this, use wisely. -func (engine *Engine) HandleContext(c *Context) { - oldIndexValue := c.index - c.reset() - engine.handleHTTPRequest(c) - - c.index = oldIndexValue -} - -func (engine *Engine) handleHTTPRequest(c *Context) { - httpMethod := c.Request.Method - rPath := c.Request.URL.Path - unescape := false - if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 { - rPath = c.Request.URL.RawPath - unescape = engine.UnescapePathValues - } - - if engine.RemoveExtraSlash { - rPath = cleanPath(rPath) - } - - // Find root of the tree for the given HTTP method - t := engine.trees - for i, tl := 0, len(t); i < tl; i++ { - if t[i].method != httpMethod { - continue - } - root := t[i].root - // Find route in tree - value := root.getValue(rPath, c.params, c.skippedNodes, unescape) - if value.params != nil { - c.Params = *value.params - } - if value.handlers != nil { - c.handlers = value.handlers - c.fullPath = value.fullPath - c.Next() - c.writermem.WriteHeaderNow() - return - } - if httpMethod != http.MethodConnect && rPath != "/" { - if value.tsr && engine.RedirectTrailingSlash { - redirectTrailingSlash(c) - return - } - if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) { - return - } - } - break - } - - if engine.HandleMethodNotAllowed { - for _, tree := range engine.trees { - if tree.method == httpMethod { - continue - } - if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers != nil { - c.handlers = engine.allNoMethod - serveError(c, http.StatusMethodNotAllowed, default405Body) - return - } - } - } - c.handlers = engine.allNoRoute - serveError(c, http.StatusNotFound, default404Body) -} - -var mimePlain = []string{MIMEPlain} - -func serveError(c *Context, code int, defaultMessage []byte) { - c.writermem.status = code - c.Next() - if c.writermem.Written() { - return - } - if c.writermem.Status() == code { - c.writermem.Header()["Content-Type"] = mimePlain - _, err := c.Writer.Write(defaultMessage) - if err != nil { - debugPrint("cannot write message to writer during serve error: %v", err) - } - return - } - c.writermem.WriteHeaderNow() -} - -func redirectTrailingSlash(c *Context) { - req := c.Request - p := req.URL.Path - if prefix := path.Clean(c.Request.Header.Get("X-Forwarded-Prefix")); prefix != "." { - p = prefix + "/" + req.URL.Path - } - req.URL.Path = p + "/" - if length := len(p); length > 1 && p[length-1] == '/' { - req.URL.Path = p[:length-1] - } - redirectRequest(c) -} - -func redirectFixedPath(c *Context, root *node, trailingSlash bool) bool { - req := c.Request - rPath := req.URL.Path - - if fixedPath, ok := root.findCaseInsensitivePath(cleanPath(rPath), trailingSlash); ok { - req.URL.Path = bytesconv.BytesToString(fixedPath) - redirectRequest(c) - return true - } - return false -} - -func redirectRequest(c *Context) { - req := c.Request - rPath := req.URL.Path - rURL := req.URL.String() - - code := http.StatusMovedPermanently // Permanent redirect, request with GET method - if req.Method != http.MethodGet { - code = http.StatusTemporaryRedirect - } - debugPrint("redirecting request %d: %s --> %s", code, rPath, rURL) - http.Redirect(c.Writer, req, rURL, code) - c.writermem.WriteHeaderNow() -} diff --git a/vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv.go b/vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv.go deleted file mode 100644 index 86e4c4d..0000000 --- a/vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2020 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package bytesconv - -import ( - "unsafe" -) - -// StringToBytes converts string to byte slice without a memory allocation. -func StringToBytes(s string) []byte { - return *(*[]byte)(unsafe.Pointer( - &struct { - string - Cap int - }{s, len(s)}, - )) -} - -// BytesToString converts byte slice to string without a memory allocation. -func BytesToString(b []byte) string { - return *(*string)(unsafe.Pointer(&b)) -} diff --git a/vendor/github.com/gin-gonic/gin/internal/json/go_json.go b/vendor/github.com/gin-gonic/gin/internal/json/go_json.go deleted file mode 100644 index 23f7172..0000000 --- a/vendor/github.com/gin-gonic/gin/internal/json/go_json.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017 Bo-Yi Wu. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build go_json -// +build go_json - -package json - -import json "github.com/goccy/go-json" - -var ( - // Marshal is exported by gin/json package. - Marshal = json.Marshal - // Unmarshal is exported by gin/json package. - Unmarshal = json.Unmarshal - // MarshalIndent is exported by gin/json package. - MarshalIndent = json.MarshalIndent - // NewDecoder is exported by gin/json package. - NewDecoder = json.NewDecoder - // NewEncoder is exported by gin/json package. - NewEncoder = json.NewEncoder -) diff --git a/vendor/github.com/gin-gonic/gin/internal/json/json.go b/vendor/github.com/gin-gonic/gin/internal/json/json.go deleted file mode 100644 index a26d7db..0000000 --- a/vendor/github.com/gin-gonic/gin/internal/json/json.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017 Bo-Yi Wu. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !jsoniter && !go_json -// +build !jsoniter,!go_json - -package json - -import "encoding/json" - -var ( - // Marshal is exported by gin/json package. - Marshal = json.Marshal - // Unmarshal is exported by gin/json package. - Unmarshal = json.Unmarshal - // MarshalIndent is exported by gin/json package. - MarshalIndent = json.MarshalIndent - // NewDecoder is exported by gin/json package. - NewDecoder = json.NewDecoder - // NewEncoder is exported by gin/json package. - NewEncoder = json.NewEncoder -) diff --git a/vendor/github.com/gin-gonic/gin/internal/json/jsoniter.go b/vendor/github.com/gin-gonic/gin/internal/json/jsoniter.go deleted file mode 100644 index 853b1a9..0000000 --- a/vendor/github.com/gin-gonic/gin/internal/json/jsoniter.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2017 Bo-Yi Wu. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build jsoniter -// +build jsoniter - -package json - -import jsoniter "github.com/json-iterator/go" - -var ( - json = jsoniter.ConfigCompatibleWithStandardLibrary - // Marshal is exported by gin/json package. - Marshal = json.Marshal - // Unmarshal is exported by gin/json package. - Unmarshal = json.Unmarshal - // MarshalIndent is exported by gin/json package. - MarshalIndent = json.MarshalIndent - // NewDecoder is exported by gin/json package. - NewDecoder = json.NewDecoder - // NewEncoder is exported by gin/json package. - NewEncoder = json.NewEncoder -) diff --git a/vendor/github.com/gin-gonic/gin/logger.go b/vendor/github.com/gin-gonic/gin/logger.go deleted file mode 100644 index cd1e7fa..0000000 --- a/vendor/github.com/gin-gonic/gin/logger.go +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "fmt" - "io" - "net/http" - "os" - "time" - - "github.com/mattn/go-isatty" -) - -type consoleColorModeValue int - -const ( - autoColor consoleColorModeValue = iota - disableColor - forceColor -) - -const ( - green = "\033[97;42m" - white = "\033[90;47m" - yellow = "\033[90;43m" - red = "\033[97;41m" - blue = "\033[97;44m" - magenta = "\033[97;45m" - cyan = "\033[97;46m" - reset = "\033[0m" -) - -var consoleColorMode = autoColor - -// LoggerConfig defines the config for Logger middleware. -type LoggerConfig struct { - // Optional. Default value is gin.defaultLogFormatter - Formatter LogFormatter - - // Output is a writer where logs are written. - // Optional. Default value is gin.DefaultWriter. - Output io.Writer - - // SkipPaths is an url path array which logs are not written. - // Optional. - SkipPaths []string -} - -// LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter -type LogFormatter func(params LogFormatterParams) string - -// LogFormatterParams is the structure any formatter will be handed when time to log comes -type LogFormatterParams struct { - Request *http.Request - - // TimeStamp shows the time after the server returns a response. - TimeStamp time.Time - // StatusCode is HTTP response code. - StatusCode int - // Latency is how much time the server cost to process a certain request. - Latency time.Duration - // ClientIP equals Context's ClientIP method. - ClientIP string - // Method is the HTTP method given to the request. - Method string - // Path is a path the client requests. - Path string - // ErrorMessage is set if error has occurred in processing the request. - ErrorMessage string - // isTerm shows whether gin's output descriptor refers to a terminal. - isTerm bool - // BodySize is the size of the Response Body - BodySize int - // Keys are the keys set on the request's context. - Keys map[string]any -} - -// StatusCodeColor is the ANSI color for appropriately logging http status code to a terminal. -func (p *LogFormatterParams) StatusCodeColor() string { - code := p.StatusCode - - switch { - case code >= http.StatusOK && code < http.StatusMultipleChoices: - return green - case code >= http.StatusMultipleChoices && code < http.StatusBadRequest: - return white - case code >= http.StatusBadRequest && code < http.StatusInternalServerError: - return yellow - default: - return red - } -} - -// MethodColor is the ANSI color for appropriately logging http method to a terminal. -func (p *LogFormatterParams) MethodColor() string { - method := p.Method - - switch method { - case http.MethodGet: - return blue - case http.MethodPost: - return cyan - case http.MethodPut: - return yellow - case http.MethodDelete: - return red - case http.MethodPatch: - return green - case http.MethodHead: - return magenta - case http.MethodOptions: - return white - default: - return reset - } -} - -// ResetColor resets all escape attributes. -func (p *LogFormatterParams) ResetColor() string { - return reset -} - -// IsOutputColor indicates whether can colors be outputted to the log. -func (p *LogFormatterParams) IsOutputColor() bool { - return consoleColorMode == forceColor || (consoleColorMode == autoColor && p.isTerm) -} - -// defaultLogFormatter is the default log format function Logger middleware uses. -var defaultLogFormatter = func(param LogFormatterParams) string { - var statusColor, methodColor, resetColor string - if param.IsOutputColor() { - statusColor = param.StatusCodeColor() - methodColor = param.MethodColor() - resetColor = param.ResetColor() - } - - if param.Latency > time.Minute { - param.Latency = param.Latency.Truncate(time.Second) - } - return fmt.Sprintf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %#v\n%s", - param.TimeStamp.Format("2006/01/02 - 15:04:05"), - statusColor, param.StatusCode, resetColor, - param.Latency, - param.ClientIP, - methodColor, param.Method, resetColor, - param.Path, - param.ErrorMessage, - ) -} - -// DisableConsoleColor disables color output in the console. -func DisableConsoleColor() { - consoleColorMode = disableColor -} - -// ForceConsoleColor force color output in the console. -func ForceConsoleColor() { - consoleColorMode = forceColor -} - -// ErrorLogger returns a HandlerFunc for any error type. -func ErrorLogger() HandlerFunc { - return ErrorLoggerT(ErrorTypeAny) -} - -// ErrorLoggerT returns a HandlerFunc for a given error type. -func ErrorLoggerT(typ ErrorType) HandlerFunc { - return func(c *Context) { - c.Next() - errors := c.Errors.ByType(typ) - if len(errors) > 0 { - c.JSON(-1, errors) - } - } -} - -// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter. -// By default, gin.DefaultWriter = os.Stdout. -func Logger() HandlerFunc { - return LoggerWithConfig(LoggerConfig{}) -} - -// LoggerWithFormatter instance a Logger middleware with the specified log format function. -func LoggerWithFormatter(f LogFormatter) HandlerFunc { - return LoggerWithConfig(LoggerConfig{ - Formatter: f, - }) -} - -// LoggerWithWriter instance a Logger middleware with the specified writer buffer. -// Example: os.Stdout, a file opened in write mode, a socket... -func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc { - return LoggerWithConfig(LoggerConfig{ - Output: out, - SkipPaths: notlogged, - }) -} - -// LoggerWithConfig instance a Logger middleware with config. -func LoggerWithConfig(conf LoggerConfig) HandlerFunc { - formatter := conf.Formatter - if formatter == nil { - formatter = defaultLogFormatter - } - - out := conf.Output - if out == nil { - out = DefaultWriter - } - - notlogged := conf.SkipPaths - - isTerm := true - - if w, ok := out.(*os.File); !ok || os.Getenv("TERM") == "dumb" || - (!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd())) { - isTerm = false - } - - var skip map[string]struct{} - - if length := len(notlogged); length > 0 { - skip = make(map[string]struct{}, length) - - for _, path := range notlogged { - skip[path] = struct{}{} - } - } - - return func(c *Context) { - // Start timer - start := time.Now() - path := c.Request.URL.Path - raw := c.Request.URL.RawQuery - - // Process request - c.Next() - - // Log only when path is not being skipped - if _, ok := skip[path]; !ok { - param := LogFormatterParams{ - Request: c.Request, - isTerm: isTerm, - Keys: c.Keys, - } - - // Stop timer - param.TimeStamp = time.Now() - param.Latency = param.TimeStamp.Sub(start) - - param.ClientIP = c.ClientIP() - param.Method = c.Request.Method - param.StatusCode = c.Writer.Status() - param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String() - - param.BodySize = c.Writer.Size() - - if raw != "" { - path = path + "?" + raw - } - - param.Path = path - - fmt.Fprint(out, formatter(param)) - } - } -} diff --git a/vendor/github.com/gin-gonic/gin/mode.go b/vendor/github.com/gin-gonic/gin/mode.go deleted file mode 100644 index 545fdaa..0000000 --- a/vendor/github.com/gin-gonic/gin/mode.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "flag" - "io" - "os" - - "github.com/gin-gonic/gin/binding" -) - -// EnvGinMode indicates environment name for gin mode. -const EnvGinMode = "GIN_MODE" - -const ( - // DebugMode indicates gin mode is debug. - DebugMode = "debug" - // ReleaseMode indicates gin mode is release. - ReleaseMode = "release" - // TestMode indicates gin mode is test. - TestMode = "test" -) - -const ( - debugCode = iota - releaseCode - testCode -) - -// DefaultWriter is the default io.Writer used by Gin for debug output and -// middleware output like Logger() or Recovery(). -// Note that both Logger and Recovery provides custom ways to configure their -// output io.Writer. -// To support coloring in Windows use: -// import "github.com/mattn/go-colorable" -// gin.DefaultWriter = colorable.NewColorableStdout() -var DefaultWriter io.Writer = os.Stdout - -// DefaultErrorWriter is the default io.Writer used by Gin to debug errors -var DefaultErrorWriter io.Writer = os.Stderr - -var ( - ginMode = debugCode - modeName = DebugMode -) - -func init() { - mode := os.Getenv(EnvGinMode) - SetMode(mode) -} - -// SetMode sets gin mode according to input string. -func SetMode(value string) { - if value == "" { - if flag.Lookup("test.v") != nil { - value = TestMode - } else { - value = DebugMode - } - } - - switch value { - case DebugMode: - ginMode = debugCode - case ReleaseMode: - ginMode = releaseCode - case TestMode: - ginMode = testCode - default: - panic("gin mode unknown: " + value + " (available mode: debug release test)") - } - - modeName = value -} - -// DisableBindValidation closes the default validator. -func DisableBindValidation() { - binding.Validator = nil -} - -// EnableJsonDecoderUseNumber sets true for binding.EnableDecoderUseNumber to -// call the UseNumber method on the JSON Decoder instance. -func EnableJsonDecoderUseNumber() { - binding.EnableDecoderUseNumber = true -} - -// EnableJsonDecoderDisallowUnknownFields sets true for binding.EnableDecoderDisallowUnknownFields to -// call the DisallowUnknownFields method on the JSON Decoder instance. -func EnableJsonDecoderDisallowUnknownFields() { - binding.EnableDecoderDisallowUnknownFields = true -} - -// Mode returns current gin mode. -func Mode() string { - return modeName -} diff --git a/vendor/github.com/gin-gonic/gin/path.go b/vendor/github.com/gin-gonic/gin/path.go deleted file mode 100644 index d42d6b9..0000000 --- a/vendor/github.com/gin-gonic/gin/path.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2013 Julien Schmidt. All rights reserved. -// Based on the path package, Copyright 2009 The Go Authors. -// Use of this source code is governed by a BSD-style license that can be found -// at https://github.com/julienschmidt/httprouter/blob/master/LICENSE. - -package gin - -// cleanPath is the URL version of path.Clean, it returns a canonical URL path -// for p, eliminating . and .. elements. -// -// The following rules are applied iteratively until no further processing can -// be done: -// 1. Replace multiple slashes with a single slash. -// 2. Eliminate each . path name element (the current directory). -// 3. Eliminate each inner .. path name element (the parent directory) -// along with the non-.. element that precedes it. -// 4. Eliminate .. elements that begin a rooted path: -// that is, replace "/.." by "/" at the beginning of a path. -// -// If the result of this process is an empty string, "/" is returned. -func cleanPath(p string) string { - const stackBufSize = 128 - // Turn empty string into "/" - if p == "" { - return "/" - } - - // Reasonably sized buffer on stack to avoid allocations in the common case. - // If a larger buffer is required, it gets allocated dynamically. - buf := make([]byte, 0, stackBufSize) - - n := len(p) - - // Invariants: - // reading from path; r is index of next byte to process. - // writing to buf; w is index of next byte to write. - - // path must start with '/' - r := 1 - w := 1 - - if p[0] != '/' { - r = 0 - - if n+1 > stackBufSize { - buf = make([]byte, n+1) - } else { - buf = buf[:n+1] - } - buf[0] = '/' - } - - trailing := n > 1 && p[n-1] == '/' - - // A bit more clunky without a 'lazybuf' like the path package, but the loop - // gets completely inlined (bufApp calls). - // loop has no expensive function calls (except 1x make) // So in contrast to the path package this loop has no expensive function - // calls (except make, if needed). - - for r < n { - switch { - case p[r] == '/': - // empty path element, trailing slash is added after the end - r++ - - case p[r] == '.' && r+1 == n: - trailing = true - r++ - - case p[r] == '.' && p[r+1] == '/': - // . element - r += 2 - - case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'): - // .. element: remove to last / - r += 3 - - if w > 1 { - // can backtrack - w-- - - if len(buf) == 0 { - for w > 1 && p[w] != '/' { - w-- - } - } else { - for w > 1 && buf[w] != '/' { - w-- - } - } - } - - default: - // Real path element. - // Add slash if needed - if w > 1 { - bufApp(&buf, p, w, '/') - w++ - } - - // Copy element - for r < n && p[r] != '/' { - bufApp(&buf, p, w, p[r]) - w++ - r++ - } - } - } - - // Re-append trailing slash - if trailing && w > 1 { - bufApp(&buf, p, w, '/') - w++ - } - - // If the original string was not modified (or only shortened at the end), - // return the respective substring of the original string. - // Otherwise return a new string from the buffer. - if len(buf) == 0 { - return p[:w] - } - return string(buf[:w]) -} - -// Internal helper to lazily create a buffer if necessary. -// Calls to this function get inlined. -func bufApp(buf *[]byte, s string, w int, c byte) { - b := *buf - if len(b) == 0 { - // No modification of the original string so far. - // If the next character is the same as in the original string, we do - // not yet have to allocate a buffer. - if s[w] == c { - return - } - - // Otherwise use either the stack buffer, if it is large enough, or - // allocate a new buffer on the heap, and copy all previous characters. - length := len(s) - if length > cap(b) { - *buf = make([]byte, length) - } else { - *buf = (*buf)[:length] - } - b = *buf - - copy(b, s[:w]) - } - b[w] = c -} diff --git a/vendor/github.com/gin-gonic/gin/recovery.go b/vendor/github.com/gin-gonic/gin/recovery.go deleted file mode 100644 index abb6451..0000000 --- a/vendor/github.com/gin-gonic/gin/recovery.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "bytes" - "errors" - "fmt" - "io" - "io/ioutil" - "log" - "net" - "net/http" - "net/http/httputil" - "os" - "runtime" - "strings" - "time" -) - -var ( - dunno = []byte("???") - centerDot = []byte("·") - dot = []byte(".") - slash = []byte("/") -) - -// RecoveryFunc defines the function passable to CustomRecovery. -type RecoveryFunc func(c *Context, err any) - -// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one. -func Recovery() HandlerFunc { - return RecoveryWithWriter(DefaultErrorWriter) -} - -// CustomRecovery returns a middleware that recovers from any panics and calls the provided handle func to handle it. -func CustomRecovery(handle RecoveryFunc) HandlerFunc { - return RecoveryWithWriter(DefaultErrorWriter, handle) -} - -// RecoveryWithWriter returns a middleware for a given writer that recovers from any panics and writes a 500 if there was one. -func RecoveryWithWriter(out io.Writer, recovery ...RecoveryFunc) HandlerFunc { - if len(recovery) > 0 { - return CustomRecoveryWithWriter(out, recovery[0]) - } - return CustomRecoveryWithWriter(out, defaultHandleRecovery) -} - -// CustomRecoveryWithWriter returns a middleware for a given writer that recovers from any panics and calls the provided handle func to handle it. -func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) HandlerFunc { - var logger *log.Logger - if out != nil { - logger = log.New(out, "\n\n\x1b[31m", log.LstdFlags) - } - return func(c *Context) { - defer func() { - if err := recover(); err != nil { - // Check for a broken connection, as it is not really a - // condition that warrants a panic stack trace. - var brokenPipe bool - if ne, ok := err.(*net.OpError); ok { - var se *os.SyscallError - if errors.As(ne, &se) { - if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") { - brokenPipe = true - } - } - } - if logger != nil { - stack := stack(3) - httpRequest, _ := httputil.DumpRequest(c.Request, false) - headers := strings.Split(string(httpRequest), "\r\n") - for idx, header := range headers { - current := strings.Split(header, ":") - if current[0] == "Authorization" { - headers[idx] = current[0] + ": *" - } - } - headersToStr := strings.Join(headers, "\r\n") - if brokenPipe { - logger.Printf("%s\n%s%s", err, headersToStr, reset) - } else if IsDebugging() { - logger.Printf("[Recovery] %s panic recovered:\n%s\n%s\n%s%s", - timeFormat(time.Now()), headersToStr, err, stack, reset) - } else { - logger.Printf("[Recovery] %s panic recovered:\n%s\n%s%s", - timeFormat(time.Now()), err, stack, reset) - } - } - if brokenPipe { - // If the connection is dead, we can't write a status to it. - c.Error(err.(error)) // nolint: errcheck - c.Abort() - } else { - handle(c, err) - } - } - }() - c.Next() - } -} - -func defaultHandleRecovery(c *Context, err any) { - c.AbortWithStatus(http.StatusInternalServerError) -} - -// stack returns a nicely formatted stack frame, skipping skip frames. -func stack(skip int) []byte { - buf := new(bytes.Buffer) // the returned data - // As we loop, we open files and read them. These variables record the currently - // loaded file. - var lines [][]byte - var lastFile string - for i := skip; ; i++ { // Skip the expected number of frames - pc, file, line, ok := runtime.Caller(i) - if !ok { - break - } - // Print this much at least. If we can't find the source, it won't show. - fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc) - if file != lastFile { - data, err := ioutil.ReadFile(file) - if err != nil { - continue - } - lines = bytes.Split(data, []byte{'\n'}) - lastFile = file - } - fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line)) - } - return buf.Bytes() -} - -// source returns a space-trimmed slice of the n'th line. -func source(lines [][]byte, n int) []byte { - n-- // in stack trace, lines are 1-indexed but our array is 0-indexed - if n < 0 || n >= len(lines) { - return dunno - } - return bytes.TrimSpace(lines[n]) -} - -// function returns, if possible, the name of the function containing the PC. -func function(pc uintptr) []byte { - fn := runtime.FuncForPC(pc) - if fn == nil { - return dunno - } - name := []byte(fn.Name()) - // The name includes the path name to the package, which is unnecessary - // since the file name is already included. Plus, it has center dots. - // That is, we see - // runtime/debug.*T·ptrmethod - // and want - // *T.ptrmethod - // Also the package path might contain dot (e.g. code.google.com/...), - // so first eliminate the path prefix - if lastSlash := bytes.LastIndex(name, slash); lastSlash >= 0 { - name = name[lastSlash+1:] - } - if period := bytes.Index(name, dot); period >= 0 { - name = name[period+1:] - } - name = bytes.Replace(name, centerDot, dot, -1) - return name -} - -// timeFormat returns a customized time string for logger. -func timeFormat(t time.Time) string { - return t.Format("2006/01/02 - 15:04:05") -} diff --git a/vendor/github.com/gin-gonic/gin/render/any.go b/vendor/github.com/gin-gonic/gin/render/any.go deleted file mode 100644 index b19ad45..0000000 --- a/vendor/github.com/gin-gonic/gin/render/any.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2021 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package render - -type any = interface{} diff --git a/vendor/github.com/gin-gonic/gin/render/data.go b/vendor/github.com/gin-gonic/gin/render/data.go deleted file mode 100644 index a653ea3..0000000 --- a/vendor/github.com/gin-gonic/gin/render/data.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import "net/http" - -// Data contains ContentType and bytes data. -type Data struct { - ContentType string - Data []byte -} - -// Render (Data) writes data with custom ContentType. -func (r Data) Render(w http.ResponseWriter) (err error) { - r.WriteContentType(w) - _, err = w.Write(r.Data) - return -} - -// WriteContentType (Data) writes custom ContentType. -func (r Data) WriteContentType(w http.ResponseWriter) { - writeContentType(w, []string{r.ContentType}) -} diff --git a/vendor/github.com/gin-gonic/gin/render/html.go b/vendor/github.com/gin-gonic/gin/render/html.go deleted file mode 100644 index c308408..0000000 --- a/vendor/github.com/gin-gonic/gin/render/html.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "html/template" - "net/http" -) - -// Delims represents a set of Left and Right delimiters for HTML template rendering. -type Delims struct { - // Left delimiter, defaults to {{. - Left string - // Right delimiter, defaults to }}. - Right string -} - -// HTMLRender interface is to be implemented by HTMLProduction and HTMLDebug. -type HTMLRender interface { - // Instance returns an HTML instance. - Instance(string, any) Render -} - -// HTMLProduction contains template reference and its delims. -type HTMLProduction struct { - Template *template.Template - Delims Delims -} - -// HTMLDebug contains template delims and pattern and function with file list. -type HTMLDebug struct { - Files []string - Glob string - Delims Delims - FuncMap template.FuncMap -} - -// HTML contains template reference and its name with given interface object. -type HTML struct { - Template *template.Template - Name string - Data any -} - -var htmlContentType = []string{"text/html; charset=utf-8"} - -// Instance (HTMLProduction) returns an HTML instance which it realizes Render interface. -func (r HTMLProduction) Instance(name string, data any) Render { - return HTML{ - Template: r.Template, - Name: name, - Data: data, - } -} - -// Instance (HTMLDebug) returns an HTML instance which it realizes Render interface. -func (r HTMLDebug) Instance(name string, data any) Render { - return HTML{ - Template: r.loadTemplate(), - Name: name, - Data: data, - } -} -func (r HTMLDebug) loadTemplate() *template.Template { - if r.FuncMap == nil { - r.FuncMap = template.FuncMap{} - } - if len(r.Files) > 0 { - return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap).ParseFiles(r.Files...)) - } - if r.Glob != "" { - return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap).ParseGlob(r.Glob)) - } - panic("the HTML debug render was created without files or glob pattern") -} - -// Render (HTML) executes template and writes its result with custom ContentType for response. -func (r HTML) Render(w http.ResponseWriter) error { - r.WriteContentType(w) - - if r.Name == "" { - return r.Template.Execute(w, r.Data) - } - return r.Template.ExecuteTemplate(w, r.Name, r.Data) -} - -// WriteContentType (HTML) writes HTML ContentType. -func (r HTML) WriteContentType(w http.ResponseWriter) { - writeContentType(w, htmlContentType) -} diff --git a/vendor/github.com/gin-gonic/gin/render/json.go b/vendor/github.com/gin-gonic/gin/render/json.go deleted file mode 100644 index af678e8..0000000 --- a/vendor/github.com/gin-gonic/gin/render/json.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "bytes" - "fmt" - "html/template" - "net/http" - - "github.com/gin-gonic/gin/internal/bytesconv" - "github.com/gin-gonic/gin/internal/json" -) - -// JSON contains the given interface object. -type JSON struct { - Data any -} - -// IndentedJSON contains the given interface object. -type IndentedJSON struct { - Data any -} - -// SecureJSON contains the given interface object and its prefix. -type SecureJSON struct { - Prefix string - Data any -} - -// JsonpJSON contains the given interface object its callback. -type JsonpJSON struct { - Callback string - Data any -} - -// AsciiJSON contains the given interface object. -type AsciiJSON struct { - Data any -} - -// PureJSON contains the given interface object. -type PureJSON struct { - Data any -} - -var ( - jsonContentType = []string{"application/json; charset=utf-8"} - jsonpContentType = []string{"application/javascript; charset=utf-8"} - jsonASCIIContentType = []string{"application/json"} -) - -// Render (JSON) writes data with custom ContentType. -func (r JSON) Render(w http.ResponseWriter) (err error) { - if err = WriteJSON(w, r.Data); err != nil { - panic(err) - } - return -} - -// WriteContentType (JSON) writes JSON ContentType. -func (r JSON) WriteContentType(w http.ResponseWriter) { - writeContentType(w, jsonContentType) -} - -// WriteJSON marshals the given interface object and writes it with custom ContentType. -func WriteJSON(w http.ResponseWriter, obj any) error { - writeContentType(w, jsonContentType) - jsonBytes, err := json.Marshal(obj) - if err != nil { - return err - } - _, err = w.Write(jsonBytes) - return err -} - -// Render (IndentedJSON) marshals the given interface object and writes it with custom ContentType. -func (r IndentedJSON) Render(w http.ResponseWriter) error { - r.WriteContentType(w) - jsonBytes, err := json.MarshalIndent(r.Data, "", " ") - if err != nil { - return err - } - _, err = w.Write(jsonBytes) - return err -} - -// WriteContentType (IndentedJSON) writes JSON ContentType. -func (r IndentedJSON) WriteContentType(w http.ResponseWriter) { - writeContentType(w, jsonContentType) -} - -// Render (SecureJSON) marshals the given interface object and writes it with custom ContentType. -func (r SecureJSON) Render(w http.ResponseWriter) error { - r.WriteContentType(w) - jsonBytes, err := json.Marshal(r.Data) - if err != nil { - return err - } - // if the jsonBytes is array values - if bytes.HasPrefix(jsonBytes, bytesconv.StringToBytes("[")) && bytes.HasSuffix(jsonBytes, - bytesconv.StringToBytes("]")) { - if _, err = w.Write(bytesconv.StringToBytes(r.Prefix)); err != nil { - return err - } - } - _, err = w.Write(jsonBytes) - return err -} - -// WriteContentType (SecureJSON) writes JSON ContentType. -func (r SecureJSON) WriteContentType(w http.ResponseWriter) { - writeContentType(w, jsonContentType) -} - -// Render (JsonpJSON) marshals the given interface object and writes it and its callback with custom ContentType. -func (r JsonpJSON) Render(w http.ResponseWriter) (err error) { - r.WriteContentType(w) - ret, err := json.Marshal(r.Data) - if err != nil { - return err - } - - if r.Callback == "" { - _, err = w.Write(ret) - return err - } - - callback := template.JSEscapeString(r.Callback) - if _, err = w.Write(bytesconv.StringToBytes(callback)); err != nil { - return err - } - - if _, err = w.Write(bytesconv.StringToBytes("(")); err != nil { - return err - } - - if _, err = w.Write(ret); err != nil { - return err - } - - if _, err = w.Write(bytesconv.StringToBytes(");")); err != nil { - return err - } - - return nil -} - -// WriteContentType (JsonpJSON) writes Javascript ContentType. -func (r JsonpJSON) WriteContentType(w http.ResponseWriter) { - writeContentType(w, jsonpContentType) -} - -// Render (AsciiJSON) marshals the given interface object and writes it with custom ContentType. -func (r AsciiJSON) Render(w http.ResponseWriter) (err error) { - r.WriteContentType(w) - ret, err := json.Marshal(r.Data) - if err != nil { - return err - } - - var buffer bytes.Buffer - for _, r := range bytesconv.BytesToString(ret) { - cvt := string(r) - if r >= 128 { - cvt = fmt.Sprintf("\\u%04x", int64(r)) - } - buffer.WriteString(cvt) - } - - _, err = w.Write(buffer.Bytes()) - return err -} - -// WriteContentType (AsciiJSON) writes JSON ContentType. -func (r AsciiJSON) WriteContentType(w http.ResponseWriter) { - writeContentType(w, jsonASCIIContentType) -} - -// Render (PureJSON) writes custom ContentType and encodes the given interface object. -func (r PureJSON) Render(w http.ResponseWriter) error { - r.WriteContentType(w) - encoder := json.NewEncoder(w) - encoder.SetEscapeHTML(false) - return encoder.Encode(r.Data) -} - -// WriteContentType (PureJSON) writes custom ContentType. -func (r PureJSON) WriteContentType(w http.ResponseWriter) { - writeContentType(w, jsonContentType) -} diff --git a/vendor/github.com/gin-gonic/gin/render/msgpack.go b/vendor/github.com/gin-gonic/gin/render/msgpack.go deleted file mode 100644 index e0f30f7..0000000 --- a/vendor/github.com/gin-gonic/gin/render/msgpack.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !nomsgpack -// +build !nomsgpack - -package render - -import ( - "net/http" - - "github.com/ugorji/go/codec" -) - -// Check interface implemented here to support go build tag nomsgpack. -// See: https://github.com/gin-gonic/gin/pull/1852/ -var ( - _ Render = MsgPack{} -) - -// MsgPack contains the given interface object. -type MsgPack struct { - Data any -} - -var msgpackContentType = []string{"application/msgpack; charset=utf-8"} - -// WriteContentType (MsgPack) writes MsgPack ContentType. -func (r MsgPack) WriteContentType(w http.ResponseWriter) { - writeContentType(w, msgpackContentType) -} - -// Render (MsgPack) encodes the given interface object and writes data with custom ContentType. -func (r MsgPack) Render(w http.ResponseWriter) error { - return WriteMsgPack(w, r.Data) -} - -// WriteMsgPack writes MsgPack ContentType and encodes the given interface object. -func WriteMsgPack(w http.ResponseWriter, obj any) error { - writeContentType(w, msgpackContentType) - var mh codec.MsgpackHandle - return codec.NewEncoder(w, &mh).Encode(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/render/protobuf.go b/vendor/github.com/gin-gonic/gin/render/protobuf.go deleted file mode 100644 index 9331c40..0000000 --- a/vendor/github.com/gin-gonic/gin/render/protobuf.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2018 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "net/http" - - "google.golang.org/protobuf/proto" -) - -// ProtoBuf contains the given interface object. -type ProtoBuf struct { - Data any -} - -var protobufContentType = []string{"application/x-protobuf"} - -// Render (ProtoBuf) marshals the given interface object and writes data with custom ContentType. -func (r ProtoBuf) Render(w http.ResponseWriter) error { - r.WriteContentType(w) - - bytes, err := proto.Marshal(r.Data.(proto.Message)) - if err != nil { - return err - } - - _, err = w.Write(bytes) - return err -} - -// WriteContentType (ProtoBuf) writes ProtoBuf ContentType. -func (r ProtoBuf) WriteContentType(w http.ResponseWriter) { - writeContentType(w, protobufContentType) -} diff --git a/vendor/github.com/gin-gonic/gin/render/reader.go b/vendor/github.com/gin-gonic/gin/render/reader.go deleted file mode 100644 index 5752d8d..0000000 --- a/vendor/github.com/gin-gonic/gin/render/reader.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2018 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "io" - "net/http" - "strconv" -) - -// Reader contains the IO reader and its length, and custom ContentType and other headers. -type Reader struct { - ContentType string - ContentLength int64 - Reader io.Reader - Headers map[string]string -} - -// Render (Reader) writes data with custom ContentType and headers. -func (r Reader) Render(w http.ResponseWriter) (err error) { - r.WriteContentType(w) - if r.ContentLength >= 0 { - if r.Headers == nil { - r.Headers = map[string]string{} - } - r.Headers["Content-Length"] = strconv.FormatInt(r.ContentLength, 10) - } - r.writeHeaders(w, r.Headers) - _, err = io.Copy(w, r.Reader) - return -} - -// WriteContentType (Reader) writes custom ContentType. -func (r Reader) WriteContentType(w http.ResponseWriter) { - writeContentType(w, []string{r.ContentType}) -} - -// writeHeaders writes custom Header. -func (r Reader) writeHeaders(w http.ResponseWriter, headers map[string]string) { - header := w.Header() - for k, v := range headers { - if header.Get(k) == "" { - header.Set(k, v) - } - } -} diff --git a/vendor/github.com/gin-gonic/gin/render/redirect.go b/vendor/github.com/gin-gonic/gin/render/redirect.go deleted file mode 100644 index 70e3a47..0000000 --- a/vendor/github.com/gin-gonic/gin/render/redirect.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "fmt" - "net/http" -) - -// Redirect contains the http request reference and redirects status code and location. -type Redirect struct { - Code int - Request *http.Request - Location string -} - -// Render (Redirect) redirects the http request to new location and writes redirect response. -func (r Redirect) Render(w http.ResponseWriter) error { - if (r.Code < http.StatusMultipleChoices || r.Code > http.StatusPermanentRedirect) && r.Code != http.StatusCreated { - panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code)) - } - http.Redirect(w, r.Request, r.Location, r.Code) - return nil -} - -// WriteContentType (Redirect) don't write any ContentType. -func (r Redirect) WriteContentType(http.ResponseWriter) {} diff --git a/vendor/github.com/gin-gonic/gin/render/render.go b/vendor/github.com/gin-gonic/gin/render/render.go deleted file mode 100644 index 7955000..0000000 --- a/vendor/github.com/gin-gonic/gin/render/render.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import "net/http" - -// Render interface is to be implemented by JSON, XML, HTML, YAML and so on. -type Render interface { - // Render writes data with custom ContentType. - Render(http.ResponseWriter) error - // WriteContentType writes custom ContentType. - WriteContentType(w http.ResponseWriter) -} - -var ( - _ Render = JSON{} - _ Render = IndentedJSON{} - _ Render = SecureJSON{} - _ Render = JsonpJSON{} - _ Render = XML{} - _ Render = String{} - _ Render = Redirect{} - _ Render = Data{} - _ Render = HTML{} - _ HTMLRender = HTMLDebug{} - _ HTMLRender = HTMLProduction{} - _ Render = YAML{} - _ Render = Reader{} - _ Render = AsciiJSON{} - _ Render = ProtoBuf{} - _ Render = TOML{} -) - -func writeContentType(w http.ResponseWriter, value []string) { - header := w.Header() - if val := header["Content-Type"]; len(val) == 0 { - header["Content-Type"] = value - } -} diff --git a/vendor/github.com/gin-gonic/gin/render/text.go b/vendor/github.com/gin-gonic/gin/render/text.go deleted file mode 100644 index 77eafdf..0000000 --- a/vendor/github.com/gin-gonic/gin/render/text.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "fmt" - "net/http" - - "github.com/gin-gonic/gin/internal/bytesconv" -) - -// String contains the given interface object slice and its format. -type String struct { - Format string - Data []any -} - -var plainContentType = []string{"text/plain; charset=utf-8"} - -// Render (String) writes data with custom ContentType. -func (r String) Render(w http.ResponseWriter) error { - return WriteString(w, r.Format, r.Data) -} - -// WriteContentType (String) writes Plain ContentType. -func (r String) WriteContentType(w http.ResponseWriter) { - writeContentType(w, plainContentType) -} - -// WriteString writes data according to its format and write custom ContentType. -func WriteString(w http.ResponseWriter, format string, data []any) (err error) { - writeContentType(w, plainContentType) - if len(data) > 0 { - _, err = fmt.Fprintf(w, format, data...) - return - } - _, err = w.Write(bytesconv.StringToBytes(format)) - return -} diff --git a/vendor/github.com/gin-gonic/gin/render/toml.go b/vendor/github.com/gin-gonic/gin/render/toml.go deleted file mode 100644 index 40f044c..0000000 --- a/vendor/github.com/gin-gonic/gin/render/toml.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2022 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "net/http" - - "github.com/pelletier/go-toml/v2" -) - -// TOML contains the given interface object. -type TOML struct { - Data any -} - -var TOMLContentType = []string{"application/toml; charset=utf-8"} - -// Render (TOML) marshals the given interface object and writes data with custom ContentType. -func (r TOML) Render(w http.ResponseWriter) error { - r.WriteContentType(w) - - bytes, err := toml.Marshal(r.Data) - if err != nil { - return err - } - - _, err = w.Write(bytes) - return err -} - -// WriteContentType (TOML) writes TOML ContentType for response. -func (r TOML) WriteContentType(w http.ResponseWriter) { - writeContentType(w, TOMLContentType) -} diff --git a/vendor/github.com/gin-gonic/gin/render/xml.go b/vendor/github.com/gin-gonic/gin/render/xml.go deleted file mode 100644 index 6af8901..0000000 --- a/vendor/github.com/gin-gonic/gin/render/xml.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "encoding/xml" - "net/http" -) - -// XML contains the given interface object. -type XML struct { - Data any -} - -var xmlContentType = []string{"application/xml; charset=utf-8"} - -// Render (XML) encodes the given interface object and writes data with custom ContentType. -func (r XML) Render(w http.ResponseWriter) error { - r.WriteContentType(w) - return xml.NewEncoder(w).Encode(r.Data) -} - -// WriteContentType (XML) writes XML ContentType for response. -func (r XML) WriteContentType(w http.ResponseWriter) { - writeContentType(w, xmlContentType) -} diff --git a/vendor/github.com/gin-gonic/gin/render/yaml.go b/vendor/github.com/gin-gonic/gin/render/yaml.go deleted file mode 100644 index 4f0ac01..0000000 --- a/vendor/github.com/gin-gonic/gin/render/yaml.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "net/http" - - "gopkg.in/yaml.v2" -) - -// YAML contains the given interface object. -type YAML struct { - Data any -} - -var yamlContentType = []string{"application/x-yaml; charset=utf-8"} - -// Render (YAML) marshals the given interface object and writes data with custom ContentType. -func (r YAML) Render(w http.ResponseWriter) error { - r.WriteContentType(w) - - bytes, err := yaml.Marshal(r.Data) - if err != nil { - return err - } - - _, err = w.Write(bytes) - return err -} - -// WriteContentType (YAML) writes YAML ContentType for response. -func (r YAML) WriteContentType(w http.ResponseWriter) { - writeContentType(w, yamlContentType) -} diff --git a/vendor/github.com/gin-gonic/gin/response_writer.go b/vendor/github.com/gin-gonic/gin/response_writer.go deleted file mode 100644 index 77c7ed8..0000000 --- a/vendor/github.com/gin-gonic/gin/response_writer.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "bufio" - "io" - "net" - "net/http" -) - -const ( - noWritten = -1 - defaultStatus = http.StatusOK -) - -// ResponseWriter ... -type ResponseWriter interface { - http.ResponseWriter - http.Hijacker - http.Flusher - http.CloseNotifier - - // Status returns the HTTP response status code of the current request. - Status() int - - // Size returns the number of bytes already written into the response http body. - // See Written() - Size() int - - // WriteString writes the string into the response body. - WriteString(string) (int, error) - - // Written returns true if the response body was already written. - Written() bool - - // WriteHeaderNow forces to write the http header (status code + headers). - WriteHeaderNow() - - // Pusher get the http.Pusher for server push - Pusher() http.Pusher -} - -type responseWriter struct { - http.ResponseWriter - size int - status int -} - -var _ ResponseWriter = &responseWriter{} - -func (w *responseWriter) reset(writer http.ResponseWriter) { - w.ResponseWriter = writer - w.size = noWritten - w.status = defaultStatus -} - -func (w *responseWriter) WriteHeader(code int) { - if code > 0 && w.status != code { - if w.Written() { - debugPrint("[WARNING] Headers were already written. Wanted to override status code %d with %d", w.status, code) - } - w.status = code - } -} - -func (w *responseWriter) WriteHeaderNow() { - if !w.Written() { - w.size = 0 - w.ResponseWriter.WriteHeader(w.status) - } -} - -func (w *responseWriter) Write(data []byte) (n int, err error) { - w.WriteHeaderNow() - n, err = w.ResponseWriter.Write(data) - w.size += n - return -} - -func (w *responseWriter) WriteString(s string) (n int, err error) { - w.WriteHeaderNow() - n, err = io.WriteString(w.ResponseWriter, s) - w.size += n - return -} - -func (w *responseWriter) Status() int { - return w.status -} - -func (w *responseWriter) Size() int { - return w.size -} - -func (w *responseWriter) Written() bool { - return w.size != noWritten -} - -// Hijack implements the http.Hijacker interface. -func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - if w.size < 0 { - w.size = 0 - } - return w.ResponseWriter.(http.Hijacker).Hijack() -} - -// CloseNotify implements the http.CloseNotifier interface. -func (w *responseWriter) CloseNotify() <-chan bool { - return w.ResponseWriter.(http.CloseNotifier).CloseNotify() -} - -// Flush implements the http.Flusher interface. -func (w *responseWriter) Flush() { - w.WriteHeaderNow() - w.ResponseWriter.(http.Flusher).Flush() -} - -func (w *responseWriter) Pusher() (pusher http.Pusher) { - if pusher, ok := w.ResponseWriter.(http.Pusher); ok { - return pusher - } - return nil -} diff --git a/vendor/github.com/gin-gonic/gin/routergroup.go b/vendor/github.com/gin-gonic/gin/routergroup.go deleted file mode 100644 index 3c082d9..0000000 --- a/vendor/github.com/gin-gonic/gin/routergroup.go +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "net/http" - "path" - "regexp" - "strings" -) - -var ( - // regEnLetter matches english letters for http method name - regEnLetter = regexp.MustCompile("^[A-Z]+$") - - // anyMethods for RouterGroup Any method - anyMethods = []string{ - http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, - http.MethodHead, http.MethodOptions, http.MethodDelete, http.MethodConnect, - http.MethodTrace, - } -) - -// IRouter defines all router handle interface includes single and group router. -type IRouter interface { - IRoutes - Group(string, ...HandlerFunc) *RouterGroup -} - -// IRoutes defines all router handle interface. -type IRoutes interface { - Use(...HandlerFunc) IRoutes - - Handle(string, string, ...HandlerFunc) IRoutes - Any(string, ...HandlerFunc) IRoutes - GET(string, ...HandlerFunc) IRoutes - POST(string, ...HandlerFunc) IRoutes - DELETE(string, ...HandlerFunc) IRoutes - PATCH(string, ...HandlerFunc) IRoutes - PUT(string, ...HandlerFunc) IRoutes - OPTIONS(string, ...HandlerFunc) IRoutes - HEAD(string, ...HandlerFunc) IRoutes - - StaticFile(string, string) IRoutes - StaticFileFS(string, string, http.FileSystem) IRoutes - Static(string, string) IRoutes - StaticFS(string, http.FileSystem) IRoutes -} - -// RouterGroup is used internally to configure router, a RouterGroup is associated with -// a prefix and an array of handlers (middleware). -type RouterGroup struct { - Handlers HandlersChain - basePath string - engine *Engine - root bool -} - -var _ IRouter = &RouterGroup{} - -// Use adds middleware to the group, see example code in GitHub. -func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes { - group.Handlers = append(group.Handlers, middleware...) - return group.returnObj() -} - -// Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix. -// For example, all the routes that use a common middleware for authorization could be grouped. -func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup { - return &RouterGroup{ - Handlers: group.combineHandlers(handlers), - basePath: group.calculateAbsolutePath(relativePath), - engine: group.engine, - } -} - -// BasePath returns the base path of router group. -// For example, if v := router.Group("/rest/n/v1/api"), v.BasePath() is "/rest/n/v1/api". -func (group *RouterGroup) BasePath() string { - return group.basePath -} - -func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes { - absolutePath := group.calculateAbsolutePath(relativePath) - handlers = group.combineHandlers(handlers) - group.engine.addRoute(httpMethod, absolutePath, handlers) - return group.returnObj() -} - -// Handle registers a new request handle and middleware with the given path and method. -// The last handler should be the real handler, the other ones should be middleware that can and should be shared among different routes. -// See the example code in GitHub. -// -// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut -// functions can be used. -// -// This function is intended for bulk loading and to allow the usage of less -// frequently used, non-standardized or custom methods (e.g. for internal -// communication with a proxy). -func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes { - if matched := regEnLetter.MatchString(httpMethod); !matched { - panic("http method " + httpMethod + " is not valid") - } - return group.handle(httpMethod, relativePath, handlers) -} - -// POST is a shortcut for router.Handle("POST", path, handle). -func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle(http.MethodPost, relativePath, handlers) -} - -// GET is a shortcut for router.Handle("GET", path, handle). -func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle(http.MethodGet, relativePath, handlers) -} - -// DELETE is a shortcut for router.Handle("DELETE", path, handle). -func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle(http.MethodDelete, relativePath, handlers) -} - -// PATCH is a shortcut for router.Handle("PATCH", path, handle). -func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle(http.MethodPatch, relativePath, handlers) -} - -// PUT is a shortcut for router.Handle("PUT", path, handle). -func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle(http.MethodPut, relativePath, handlers) -} - -// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle). -func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle(http.MethodOptions, relativePath, handlers) -} - -// HEAD is a shortcut for router.Handle("HEAD", path, handle). -func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle(http.MethodHead, relativePath, handlers) -} - -// Any registers a route that matches all the HTTP methods. -// GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE. -func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) IRoutes { - for _, method := range anyMethods { - group.handle(method, relativePath, handlers) - } - - return group.returnObj() -} - -// StaticFile registers a single route in order to serve a single file of the local filesystem. -// router.StaticFile("favicon.ico", "./resources/favicon.ico") -func (group *RouterGroup) StaticFile(relativePath, filepath string) IRoutes { - return group.staticFileHandler(relativePath, func(c *Context) { - c.File(filepath) - }) -} - -// StaticFileFS works just like `StaticFile` but a custom `http.FileSystem` can be used instead.. -// router.StaticFileFS("favicon.ico", "./resources/favicon.ico", Dir{".", false}) -// Gin by default user: gin.Dir() -func (group *RouterGroup) StaticFileFS(relativePath, filepath string, fs http.FileSystem) IRoutes { - return group.staticFileHandler(relativePath, func(c *Context) { - c.FileFromFS(filepath, fs) - }) -} - -func (group *RouterGroup) staticFileHandler(relativePath string, handler HandlerFunc) IRoutes { - if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") { - panic("URL parameters can not be used when serving a static file") - } - group.GET(relativePath, handler) - group.HEAD(relativePath, handler) - return group.returnObj() -} - -// Static serves files from the given file system root. -// Internally a http.FileServer is used, therefore http.NotFound is used instead -// of the Router's NotFound handler. -// To use the operating system's file system implementation, -// use : -// router.Static("/static", "/var/www") -func (group *RouterGroup) Static(relativePath, root string) IRoutes { - return group.StaticFS(relativePath, Dir(root, false)) -} - -// StaticFS works just like `Static()` but a custom `http.FileSystem` can be used instead. -// Gin by default user: gin.Dir() -func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes { - if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") { - panic("URL parameters can not be used when serving a static folder") - } - handler := group.createStaticHandler(relativePath, fs) - urlPattern := path.Join(relativePath, "/*filepath") - - // Register GET and HEAD handlers - group.GET(urlPattern, handler) - group.HEAD(urlPattern, handler) - return group.returnObj() -} - -func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc { - absolutePath := group.calculateAbsolutePath(relativePath) - fileServer := http.StripPrefix(absolutePath, http.FileServer(fs)) - - return func(c *Context) { - if _, noListing := fs.(*onlyFilesFS); noListing { - c.Writer.WriteHeader(http.StatusNotFound) - } - - file := c.Param("filepath") - // Check if file exists and/or if we have permission to access it - f, err := fs.Open(file) - if err != nil { - c.Writer.WriteHeader(http.StatusNotFound) - c.handlers = group.engine.noRoute - // Reset index - c.index = -1 - return - } - f.Close() - - fileServer.ServeHTTP(c.Writer, c.Request) - } -} - -func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain { - finalSize := len(group.Handlers) + len(handlers) - assert1(finalSize < int(abortIndex), "too many handlers") - mergedHandlers := make(HandlersChain, finalSize) - copy(mergedHandlers, group.Handlers) - copy(mergedHandlers[len(group.Handlers):], handlers) - return mergedHandlers -} - -func (group *RouterGroup) calculateAbsolutePath(relativePath string) string { - return joinPaths(group.basePath, relativePath) -} - -func (group *RouterGroup) returnObj() IRoutes { - if group.root { - return group.engine - } - return group -} diff --git a/vendor/github.com/gin-gonic/gin/test_helpers.go b/vendor/github.com/gin-gonic/gin/test_helpers.go deleted file mode 100644 index b3be93b..0000000 --- a/vendor/github.com/gin-gonic/gin/test_helpers.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import "net/http" - -// CreateTestContext returns a fresh engine and context for testing purposes -func CreateTestContext(w http.ResponseWriter) (c *Context, r *Engine) { - r = New() - c = r.allocateContext() - c.reset() - c.writermem.reset(w) - return -} diff --git a/vendor/github.com/gin-gonic/gin/tree.go b/vendor/github.com/gin-gonic/gin/tree.go deleted file mode 100644 index 88100ee..0000000 --- a/vendor/github.com/gin-gonic/gin/tree.go +++ /dev/null @@ -1,871 +0,0 @@ -// Copyright 2013 Julien Schmidt. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// at https://github.com/julienschmidt/httprouter/blob/master/LICENSE - -package gin - -import ( - "bytes" - "net/url" - "strings" - "unicode" - "unicode/utf8" - - "github.com/gin-gonic/gin/internal/bytesconv" -) - -var ( - strColon = []byte(":") - strStar = []byte("*") - strSlash = []byte("/") -) - -// Param is a single URL parameter, consisting of a key and a value. -type Param struct { - Key string - Value string -} - -// Params is a Param-slice, as returned by the router. -// The slice is ordered, the first URL parameter is also the first slice value. -// It is therefore safe to read values by the index. -type Params []Param - -// Get returns the value of the first Param which key matches the given name and a boolean true. -// If no matching Param is found, an empty string is returned and a boolean false . -func (ps Params) Get(name string) (string, bool) { - for _, entry := range ps { - if entry.Key == name { - return entry.Value, true - } - } - return "", false -} - -// ByName returns the value of the first Param which key matches the given name. -// If no matching Param is found, an empty string is returned. -func (ps Params) ByName(name string) (va string) { - va, _ = ps.Get(name) - return -} - -type methodTree struct { - method string - root *node -} - -type methodTrees []methodTree - -func (trees methodTrees) get(method string) *node { - for _, tree := range trees { - if tree.method == method { - return tree.root - } - } - return nil -} - -func min(a, b int) int { - if a <= b { - return a - } - return b -} - -func longestCommonPrefix(a, b string) int { - i := 0 - max := min(len(a), len(b)) - for i < max && a[i] == b[i] { - i++ - } - return i -} - -// addChild will add a child node, keeping wildcardChild at the end -func (n *node) addChild(child *node) { - if n.wildChild && len(n.children) > 0 { - wildcardChild := n.children[len(n.children)-1] - n.children = append(n.children[:len(n.children)-1], child, wildcardChild) - } else { - n.children = append(n.children, child) - } -} - -func countParams(path string) uint16 { - var n uint16 - s := bytesconv.StringToBytes(path) - n += uint16(bytes.Count(s, strColon)) - n += uint16(bytes.Count(s, strStar)) - return n -} - -func countSections(path string) uint16 { - s := bytesconv.StringToBytes(path) - return uint16(bytes.Count(s, strSlash)) -} - -type nodeType uint8 - -const ( - root nodeType = iota + 1 - param - catchAll -) - -type node struct { - path string - indices string - wildChild bool - nType nodeType - priority uint32 - children []*node // child nodes, at most 1 :param style node at the end of the array - handlers HandlersChain - fullPath string -} - -// Increments priority of the given child and reorders if necessary -func (n *node) incrementChildPrio(pos int) int { - cs := n.children - cs[pos].priority++ - prio := cs[pos].priority - - // Adjust position (move to front) - newPos := pos - for ; newPos > 0 && cs[newPos-1].priority < prio; newPos-- { - // Swap node positions - cs[newPos-1], cs[newPos] = cs[newPos], cs[newPos-1] - } - - // Build new index char string - if newPos != pos { - n.indices = n.indices[:newPos] + // Unchanged prefix, might be empty - n.indices[pos:pos+1] + // The index char we move - n.indices[newPos:pos] + n.indices[pos+1:] // Rest without char at 'pos' - } - - return newPos -} - -// addRoute adds a node with the given handle to the path. -// Not concurrency-safe! -func (n *node) addRoute(path string, handlers HandlersChain) { - fullPath := path - n.priority++ - - // Empty tree - if len(n.path) == 0 && len(n.children) == 0 { - n.insertChild(path, fullPath, handlers) - n.nType = root - return - } - - parentFullPathIndex := 0 - -walk: - for { - // Find the longest common prefix. - // This also implies that the common prefix contains no ':' or '*' - // since the existing key can't contain those chars. - i := longestCommonPrefix(path, n.path) - - // Split edge - if i < len(n.path) { - child := node{ - path: n.path[i:], - wildChild: n.wildChild, - indices: n.indices, - children: n.children, - handlers: n.handlers, - priority: n.priority - 1, - fullPath: n.fullPath, - } - - n.children = []*node{&child} - // []byte for proper unicode char conversion, see #65 - n.indices = bytesconv.BytesToString([]byte{n.path[i]}) - n.path = path[:i] - n.handlers = nil - n.wildChild = false - n.fullPath = fullPath[:parentFullPathIndex+i] - } - - // Make new node a child of this node - if i < len(path) { - path = path[i:] - c := path[0] - - // '/' after param - if n.nType == param && c == '/' && len(n.children) == 1 { - parentFullPathIndex += len(n.path) - n = n.children[0] - n.priority++ - continue walk - } - - // Check if a child with the next path byte exists - for i, max := 0, len(n.indices); i < max; i++ { - if c == n.indices[i] { - parentFullPathIndex += len(n.path) - i = n.incrementChildPrio(i) - n = n.children[i] - continue walk - } - } - - // Otherwise insert it - if c != ':' && c != '*' && n.nType != catchAll { - // []byte for proper unicode char conversion, see #65 - n.indices += bytesconv.BytesToString([]byte{c}) - child := &node{ - fullPath: fullPath, - } - n.addChild(child) - n.incrementChildPrio(len(n.indices) - 1) - n = child - } else if n.wildChild { - // inserting a wildcard node, need to check if it conflicts with the existing wildcard - n = n.children[len(n.children)-1] - n.priority++ - - // Check if the wildcard matches - if len(path) >= len(n.path) && n.path == path[:len(n.path)] && - // Adding a child to a catchAll is not possible - n.nType != catchAll && - // Check for longer wildcard, e.g. :name and :names - (len(n.path) >= len(path) || path[len(n.path)] == '/') { - continue walk - } - - // Wildcard conflict - pathSeg := path - if n.nType != catchAll { - pathSeg = strings.SplitN(pathSeg, "/", 2)[0] - } - prefix := fullPath[:strings.Index(fullPath, pathSeg)] + n.path - panic("'" + pathSeg + - "' in new path '" + fullPath + - "' conflicts with existing wildcard '" + n.path + - "' in existing prefix '" + prefix + - "'") - } - - n.insertChild(path, fullPath, handlers) - return - } - - // Otherwise add handle to current node - if n.handlers != nil { - panic("handlers are already registered for path '" + fullPath + "'") - } - n.handlers = handlers - n.fullPath = fullPath - return - } -} - -// Search for a wildcard segment and check the name for invalid characters. -// Returns -1 as index, if no wildcard was found. -func findWildcard(path string) (wildcard string, i int, valid bool) { - // Find start - for start, c := range []byte(path) { - // A wildcard starts with ':' (param) or '*' (catch-all) - if c != ':' && c != '*' { - continue - } - - // Find end and check for invalid characters - valid = true - for end, c := range []byte(path[start+1:]) { - switch c { - case '/': - return path[start : start+1+end], start, valid - case ':', '*': - valid = false - } - } - return path[start:], start, valid - } - return "", -1, false -} - -func (n *node) insertChild(path string, fullPath string, handlers HandlersChain) { - for { - // Find prefix until first wildcard - wildcard, i, valid := findWildcard(path) - if i < 0 { // No wildcard found - break - } - - // The wildcard name must only contain one ':' or '*' character - if !valid { - panic("only one wildcard per path segment is allowed, has: '" + - wildcard + "' in path '" + fullPath + "'") - } - - // check if the wildcard has a name - if len(wildcard) < 2 { - panic("wildcards must be named with a non-empty name in path '" + fullPath + "'") - } - - if wildcard[0] == ':' { // param - if i > 0 { - // Insert prefix before the current wildcard - n.path = path[:i] - path = path[i:] - } - - child := &node{ - nType: param, - path: wildcard, - fullPath: fullPath, - } - n.addChild(child) - n.wildChild = true - n = child - n.priority++ - - // if the path doesn't end with the wildcard, then there - // will be another subpath starting with '/' - if len(wildcard) < len(path) { - path = path[len(wildcard):] - - child := &node{ - priority: 1, - fullPath: fullPath, - } - n.addChild(child) - n = child - continue - } - - // Otherwise we're done. Insert the handle in the new leaf - n.handlers = handlers - return - } - - // catchAll - if i+len(wildcard) != len(path) { - panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'") - } - - if len(n.path) > 0 && n.path[len(n.path)-1] == '/' { - pathSeg := strings.SplitN(n.children[0].path, "/", 2)[0] - panic("catch-all wildcard '" + path + - "' in new path '" + fullPath + - "' conflicts with existing path segment '" + pathSeg + - "' in existing prefix '" + n.path + pathSeg + - "'") - } - - // currently fixed width 1 for '/' - i-- - if path[i] != '/' { - panic("no / before catch-all in path '" + fullPath + "'") - } - - n.path = path[:i] - - // First node: catchAll node with empty path - child := &node{ - wildChild: true, - nType: catchAll, - fullPath: fullPath, - } - - n.addChild(child) - n.indices = string('/') - n = child - n.priority++ - - // second node: node holding the variable - child = &node{ - path: path[i:], - nType: catchAll, - handlers: handlers, - priority: 1, - fullPath: fullPath, - } - n.children = []*node{child} - - return - } - - // If no wildcard was found, simply insert the path and handle - n.path = path - n.handlers = handlers - n.fullPath = fullPath -} - -// nodeValue holds return values of (*Node).getValue method -type nodeValue struct { - handlers HandlersChain - params *Params - tsr bool - fullPath string -} - -type skippedNode struct { - path string - node *node - paramsCount int16 -} - -// Returns the handle registered with the given path (key). The values of -// wildcards are saved to a map. -// If no handle can be found, a TSR (trailing slash redirect) recommendation is -// made if a handle exists with an extra (without the) trailing slash for the -// given path. -func (n *node) getValue(path string, params *Params, skippedNodes *[]skippedNode, unescape bool) (value nodeValue) { - var globalParamsCount int16 - -walk: // Outer loop for walking the tree - for { - prefix := n.path - if len(path) > len(prefix) { - if path[:len(prefix)] == prefix { - path = path[len(prefix):] - - // Try all the non-wildcard children first by matching the indices - idxc := path[0] - for i, c := range []byte(n.indices) { - if c == idxc { - // strings.HasPrefix(n.children[len(n.children)-1].path, ":") == n.wildChild - if n.wildChild { - index := len(*skippedNodes) - *skippedNodes = (*skippedNodes)[:index+1] - (*skippedNodes)[index] = skippedNode{ - path: prefix + path, - node: &node{ - path: n.path, - wildChild: n.wildChild, - nType: n.nType, - priority: n.priority, - children: n.children, - handlers: n.handlers, - fullPath: n.fullPath, - }, - paramsCount: globalParamsCount, - } - } - - n = n.children[i] - continue walk - } - } - - if !n.wildChild { - // If the path at the end of the loop is not equal to '/' and the current node has no child nodes - // the current node needs to roll back to last vaild skippedNode - if path != "/" { - for l := len(*skippedNodes); l > 0; { - skippedNode := (*skippedNodes)[l-1] - *skippedNodes = (*skippedNodes)[:l-1] - if strings.HasSuffix(skippedNode.path, path) { - path = skippedNode.path - n = skippedNode.node - if value.params != nil { - *value.params = (*value.params)[:skippedNode.paramsCount] - } - globalParamsCount = skippedNode.paramsCount - continue walk - } - } - } - - // Nothing found. - // We can recommend to redirect to the same URL without a - // trailing slash if a leaf exists for that path. - value.tsr = path == "/" && n.handlers != nil - return - } - - // Handle wildcard child, which is always at the end of the array - n = n.children[len(n.children)-1] - globalParamsCount++ - - switch n.nType { - case param: - // fix truncate the parameter - // tree_test.go line: 204 - - // Find param end (either '/' or path end) - end := 0 - for end < len(path) && path[end] != '/' { - end++ - } - - // Save param value - if params != nil && cap(*params) > 0 { - if value.params == nil { - value.params = params - } - // Expand slice within preallocated capacity - i := len(*value.params) - *value.params = (*value.params)[:i+1] - val := path[:end] - if unescape { - if v, err := url.QueryUnescape(val); err == nil { - val = v - } - } - (*value.params)[i] = Param{ - Key: n.path[1:], - Value: val, - } - } - - // we need to go deeper! - if end < len(path) { - if len(n.children) > 0 { - path = path[end:] - n = n.children[0] - continue walk - } - - // ... but we can't - value.tsr = len(path) == end+1 - return - } - - if value.handlers = n.handlers; value.handlers != nil { - value.fullPath = n.fullPath - return - } - if len(n.children) == 1 { - // No handle found. Check if a handle for this path + a - // trailing slash exists for TSR recommendation - n = n.children[0] - value.tsr = (n.path == "/" && n.handlers != nil) || (n.path == "" && n.indices == "/") - } - return - - case catchAll: - // Save param value - if params != nil { - if value.params == nil { - value.params = params - } - // Expand slice within preallocated capacity - i := len(*value.params) - *value.params = (*value.params)[:i+1] - val := path - if unescape { - if v, err := url.QueryUnescape(path); err == nil { - val = v - } - } - (*value.params)[i] = Param{ - Key: n.path[2:], - Value: val, - } - } - - value.handlers = n.handlers - value.fullPath = n.fullPath - return - - default: - panic("invalid node type") - } - } - } - - if path == prefix { - // If the current path does not equal '/' and the node does not have a registered handle and the most recently matched node has a child node - // the current node needs to roll back to last vaild skippedNode - if n.handlers == nil && path != "/" { - for l := len(*skippedNodes); l > 0; { - skippedNode := (*skippedNodes)[l-1] - *skippedNodes = (*skippedNodes)[:l-1] - if strings.HasSuffix(skippedNode.path, path) { - path = skippedNode.path - n = skippedNode.node - if value.params != nil { - *value.params = (*value.params)[:skippedNode.paramsCount] - } - globalParamsCount = skippedNode.paramsCount - continue walk - } - } - // n = latestNode.children[len(latestNode.children)-1] - } - // We should have reached the node containing the handle. - // Check if this node has a handle registered. - if value.handlers = n.handlers; value.handlers != nil { - value.fullPath = n.fullPath - return - } - - // If there is no handle for this route, but this route has a - // wildcard child, there must be a handle for this path with an - // additional trailing slash - if path == "/" && n.wildChild && n.nType != root { - value.tsr = true - return - } - - // No handle found. Check if a handle for this path + a - // trailing slash exists for trailing slash recommendation - for i, c := range []byte(n.indices) { - if c == '/' { - n = n.children[i] - value.tsr = (len(n.path) == 1 && n.handlers != nil) || - (n.nType == catchAll && n.children[0].handlers != nil) - return - } - } - - return - } - - // Nothing found. We can recommend to redirect to the same URL with an - // extra trailing slash if a leaf exists for that path - value.tsr = path == "/" || - (len(prefix) == len(path)+1 && prefix[len(path)] == '/' && - path == prefix[:len(prefix)-1] && n.handlers != nil) - - // roll back to last valid skippedNode - if !value.tsr && path != "/" { - for l := len(*skippedNodes); l > 0; { - skippedNode := (*skippedNodes)[l-1] - *skippedNodes = (*skippedNodes)[:l-1] - if strings.HasSuffix(skippedNode.path, path) { - path = skippedNode.path - n = skippedNode.node - if value.params != nil { - *value.params = (*value.params)[:skippedNode.paramsCount] - } - globalParamsCount = skippedNode.paramsCount - continue walk - } - } - } - - return - } -} - -// Makes a case-insensitive lookup of the given path and tries to find a handler. -// It can optionally also fix trailing slashes. -// It returns the case-corrected path and a bool indicating whether the lookup -// was successful. -func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) ([]byte, bool) { - const stackBufSize = 128 - - // Use a static sized buffer on the stack in the common case. - // If the path is too long, allocate a buffer on the heap instead. - buf := make([]byte, 0, stackBufSize) - if length := len(path) + 1; length > stackBufSize { - buf = make([]byte, 0, length) - } - - ciPath := n.findCaseInsensitivePathRec( - path, - buf, // Preallocate enough memory for new path - [4]byte{}, // Empty rune buffer - fixTrailingSlash, - ) - - return ciPath, ciPath != nil -} - -// Shift bytes in array by n bytes left -func shiftNRuneBytes(rb [4]byte, n int) [4]byte { - switch n { - case 0: - return rb - case 1: - return [4]byte{rb[1], rb[2], rb[3], 0} - case 2: - return [4]byte{rb[2], rb[3]} - case 3: - return [4]byte{rb[3]} - default: - return [4]byte{} - } -} - -// Recursive case-insensitive lookup function used by n.findCaseInsensitivePath -func (n *node) findCaseInsensitivePathRec(path string, ciPath []byte, rb [4]byte, fixTrailingSlash bool) []byte { - npLen := len(n.path) - -walk: // Outer loop for walking the tree - for len(path) >= npLen && (npLen == 0 || strings.EqualFold(path[1:npLen], n.path[1:])) { - // Add common prefix to result - oldPath := path - path = path[npLen:] - ciPath = append(ciPath, n.path...) - - if len(path) == 0 { - // We should have reached the node containing the handle. - // Check if this node has a handle registered. - if n.handlers != nil { - return ciPath - } - - // No handle found. - // Try to fix the path by adding a trailing slash - if fixTrailingSlash { - for i, c := range []byte(n.indices) { - if c == '/' { - n = n.children[i] - if (len(n.path) == 1 && n.handlers != nil) || - (n.nType == catchAll && n.children[0].handlers != nil) { - return append(ciPath, '/') - } - return nil - } - } - } - return nil - } - - // If this node does not have a wildcard (param or catchAll) child, - // we can just look up the next child node and continue to walk down - // the tree - if !n.wildChild { - // Skip rune bytes already processed - rb = shiftNRuneBytes(rb, npLen) - - if rb[0] != 0 { - // Old rune not finished - idxc := rb[0] - for i, c := range []byte(n.indices) { - if c == idxc { - // continue with child node - n = n.children[i] - npLen = len(n.path) - continue walk - } - } - } else { - // Process a new rune - var rv rune - - // Find rune start. - // Runes are up to 4 byte long, - // -4 would definitely be another rune. - var off int - for max := min(npLen, 3); off < max; off++ { - if i := npLen - off; utf8.RuneStart(oldPath[i]) { - // read rune from cached path - rv, _ = utf8.DecodeRuneInString(oldPath[i:]) - break - } - } - - // Calculate lowercase bytes of current rune - lo := unicode.ToLower(rv) - utf8.EncodeRune(rb[:], lo) - - // Skip already processed bytes - rb = shiftNRuneBytes(rb, off) - - idxc := rb[0] - for i, c := range []byte(n.indices) { - // Lowercase matches - if c == idxc { - // must use a recursive approach since both the - // uppercase byte and the lowercase byte might exist - // as an index - if out := n.children[i].findCaseInsensitivePathRec( - path, ciPath, rb, fixTrailingSlash, - ); out != nil { - return out - } - break - } - } - - // If we found no match, the same for the uppercase rune, - // if it differs - if up := unicode.ToUpper(rv); up != lo { - utf8.EncodeRune(rb[:], up) - rb = shiftNRuneBytes(rb, off) - - idxc := rb[0] - for i, c := range []byte(n.indices) { - // Uppercase matches - if c == idxc { - // Continue with child node - n = n.children[i] - npLen = len(n.path) - continue walk - } - } - } - } - - // Nothing found. We can recommend to redirect to the same URL - // without a trailing slash if a leaf exists for that path - if fixTrailingSlash && path == "/" && n.handlers != nil { - return ciPath - } - return nil - } - - n = n.children[0] - switch n.nType { - case param: - // Find param end (either '/' or path end) - end := 0 - for end < len(path) && path[end] != '/' { - end++ - } - - // Add param value to case insensitive path - ciPath = append(ciPath, path[:end]...) - - // We need to go deeper! - if end < len(path) { - if len(n.children) > 0 { - // Continue with child node - n = n.children[0] - npLen = len(n.path) - path = path[end:] - continue - } - - // ... but we can't - if fixTrailingSlash && len(path) == end+1 { - return ciPath - } - return nil - } - - if n.handlers != nil { - return ciPath - } - - if fixTrailingSlash && len(n.children) == 1 { - // No handle found. Check if a handle for this path + a - // trailing slash exists - n = n.children[0] - if n.path == "/" && n.handlers != nil { - return append(ciPath, '/') - } - } - - return nil - - case catchAll: - return append(ciPath, path...) - - default: - panic("invalid node type") - } - } - - // Nothing found. - // Try to fix the path by adding / removing a trailing slash - if fixTrailingSlash { - if path == "/" { - return ciPath - } - if len(path)+1 == npLen && n.path[len(path)] == '/' && - strings.EqualFold(path[1:], n.path[1:len(path)]) && n.handlers != nil { - return append(ciPath, n.path...) - } - } - return nil -} diff --git a/vendor/github.com/gin-gonic/gin/utils.go b/vendor/github.com/gin-gonic/gin/utils.go deleted file mode 100644 index 4021a2a..0000000 --- a/vendor/github.com/gin-gonic/gin/utils.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "encoding/xml" - "net/http" - "os" - "path" - "reflect" - "runtime" - "strings" - "unicode" -) - -// BindKey indicates a default bind key. -const BindKey = "_gin-gonic/gin/bindkey" - -// Bind is a helper function for given interface object and returns a Gin middleware. -func Bind(val any) HandlerFunc { - value := reflect.ValueOf(val) - if value.Kind() == reflect.Ptr { - panic(`Bind struct can not be a pointer. Example: - Use: gin.Bind(Struct{}) instead of gin.Bind(&Struct{}) -`) - } - typ := value.Type() - - return func(c *Context) { - obj := reflect.New(typ).Interface() - if c.Bind(obj) == nil { - c.Set(BindKey, obj) - } - } -} - -// WrapF is a helper function for wrapping http.HandlerFunc and returns a Gin middleware. -func WrapF(f http.HandlerFunc) HandlerFunc { - return func(c *Context) { - f(c.Writer, c.Request) - } -} - -// WrapH is a helper function for wrapping http.Handler and returns a Gin middleware. -func WrapH(h http.Handler) HandlerFunc { - return func(c *Context) { - h.ServeHTTP(c.Writer, c.Request) - } -} - -// H is a shortcut for map[string]interface{} -type H map[string]any - -// MarshalXML allows type H to be used with xml.Marshal. -func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error { - start.Name = xml.Name{ - Space: "", - Local: "map", - } - if err := e.EncodeToken(start); err != nil { - return err - } - for key, value := range h { - elem := xml.StartElement{ - Name: xml.Name{Space: "", Local: key}, - Attr: []xml.Attr{}, - } - if err := e.EncodeElement(value, elem); err != nil { - return err - } - } - - return e.EncodeToken(xml.EndElement{Name: start.Name}) -} - -func assert1(guard bool, text string) { - if !guard { - panic(text) - } -} - -func filterFlags(content string) string { - for i, char := range content { - if char == ' ' || char == ';' { - return content[:i] - } - } - return content -} - -func chooseData(custom, wildcard any) any { - if custom != nil { - return custom - } - if wildcard != nil { - return wildcard - } - panic("negotiation config is invalid") -} - -func parseAccept(acceptHeader string) []string { - parts := strings.Split(acceptHeader, ",") - out := make([]string, 0, len(parts)) - for _, part := range parts { - if i := strings.IndexByte(part, ';'); i > 0 { - part = part[:i] - } - if part = strings.TrimSpace(part); part != "" { - out = append(out, part) - } - } - return out -} - -func lastChar(str string) uint8 { - if str == "" { - panic("The length of the string can't be 0") - } - return str[len(str)-1] -} - -func nameOfFunction(f any) string { - return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() -} - -func joinPaths(absolutePath, relativePath string) string { - if relativePath == "" { - return absolutePath - } - - finalPath := path.Join(absolutePath, relativePath) - if lastChar(relativePath) == '/' && lastChar(finalPath) != '/' { - return finalPath + "/" - } - return finalPath -} - -func resolveAddress(addr []string) string { - switch len(addr) { - case 0: - if port := os.Getenv("PORT"); port != "" { - debugPrint("Environment variable PORT=\"%s\"", port) - return ":" + port - } - debugPrint("Environment variable PORT is undefined. Using port :8080 by default") - return ":8080" - case 1: - return addr[0] - default: - panic("too many parameters") - } -} - -// https://stackoverflow.com/questions/53069040/checking-a-string-contains-only-ascii-characters -func isASCII(s string) bool { - for i := 0; i < len(s); i++ { - if s[i] > unicode.MaxASCII { - return false - } - } - return true -} diff --git a/vendor/github.com/gin-gonic/gin/version.go b/vendor/github.com/gin-gonic/gin/version.go deleted file mode 100644 index 632ca7d..0000000 --- a/vendor/github.com/gin-gonic/gin/version.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2018 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -// Version is the current gin framework's version. -const Version = "v1.8.1" diff --git a/vendor/github.com/go-playground/locales/.gitignore b/vendor/github.com/go-playground/locales/.gitignore deleted file mode 100644 index daf913b..0000000 --- a/vendor/github.com/go-playground/locales/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof diff --git a/vendor/github.com/go-playground/locales/.travis.yml b/vendor/github.com/go-playground/locales/.travis.yml deleted file mode 100644 index d50237a..0000000 --- a/vendor/github.com/go-playground/locales/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: go -go: - - 1.13.1 - - tip -matrix: - allow_failures: - - go: tip - -notifications: - email: - recipients: dean.karn@gmail.com - on_success: change - on_failure: always - -before_install: - - go install github.com/mattn/goveralls - -# Only clone the most recent commit. -git: - depth: 1 - -script: - - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./... - -after_success: | - goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN \ No newline at end of file diff --git a/vendor/github.com/go-playground/locales/LICENSE b/vendor/github.com/go-playground/locales/LICENSE deleted file mode 100644 index 75854ac..0000000 --- a/vendor/github.com/go-playground/locales/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Go Playground - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/go-playground/locales/README.md b/vendor/github.com/go-playground/locales/README.md deleted file mode 100644 index 5b0694f..0000000 --- a/vendor/github.com/go-playground/locales/README.md +++ /dev/null @@ -1,172 +0,0 @@ -## locales -![Project status](https://img.shields.io/badge/version-0.14.0-green.svg) -[![Build Status](https://travis-ci.org/go-playground/locales.svg?branch=master)](https://travis-ci.org/go-playground/locales) -[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/locales)](https://goreportcard.com/report/github.com/go-playground/locales) -[![GoDoc](https://godoc.org/github.com/go-playground/locales?status.svg)](https://godoc.org/github.com/go-playground/locales) -![License](https://img.shields.io/dub/l/vibe-d.svg) -[![Gitter](https://badges.gitter.im/go-playground/locales.svg)](https://gitter.im/go-playground/locales?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) - -Locales is a set of locales generated from the [Unicode CLDR Project](http://cldr.unicode.org/) which can be used independently or within -an i18n package; these were built for use with, but not exclusive to, [Universal Translator](https://github.com/go-playground/universal-translator). - -Features --------- -- [x] Rules generated from the latest [CLDR](http://cldr.unicode.org/index/downloads) data, v36.0.1 -- [x] Contains Cardinal, Ordinal and Range Plural Rules -- [x] Contains Month, Weekday and Timezone translations built in -- [x] Contains Date & Time formatting functions -- [x] Contains Number, Currency, Accounting and Percent formatting functions -- [x] Supports the "Gregorian" calendar only ( my time isn't unlimited, had to draw the line somewhere ) - -Full Tests --------------------- -I could sure use your help adding tests for every locale, it is a huge undertaking and I just don't have the free time to do it all at the moment; -any help would be **greatly appreciated!!!!** please see [issue](https://github.com/go-playground/locales/issues/1) for details. - -Installation ------------ - -Use go get - -```shell -go get github.com/go-playground/locales -``` - -NOTES --------- -You'll notice most return types are []byte, this is because most of the time the results will be concatenated with a larger body -of text and can avoid some allocations if already appending to a byte array, otherwise just cast as string. - -Usage -------- -```go -package main - -import ( - "fmt" - "time" - - "github.com/go-playground/locales/currency" - "github.com/go-playground/locales/en_CA" -) - -func main() { - - loc, _ := time.LoadLocation("America/Toronto") - datetime := time.Date(2016, 02, 03, 9, 0, 1, 0, loc) - - l := en_CA.New() - - // Dates - fmt.Println(l.FmtDateFull(datetime)) - fmt.Println(l.FmtDateLong(datetime)) - fmt.Println(l.FmtDateMedium(datetime)) - fmt.Println(l.FmtDateShort(datetime)) - - // Times - fmt.Println(l.FmtTimeFull(datetime)) - fmt.Println(l.FmtTimeLong(datetime)) - fmt.Println(l.FmtTimeMedium(datetime)) - fmt.Println(l.FmtTimeShort(datetime)) - - // Months Wide - fmt.Println(l.MonthWide(time.January)) - fmt.Println(l.MonthWide(time.February)) - fmt.Println(l.MonthWide(time.March)) - // ... - - // Months Abbreviated - fmt.Println(l.MonthAbbreviated(time.January)) - fmt.Println(l.MonthAbbreviated(time.February)) - fmt.Println(l.MonthAbbreviated(time.March)) - // ... - - // Months Narrow - fmt.Println(l.MonthNarrow(time.January)) - fmt.Println(l.MonthNarrow(time.February)) - fmt.Println(l.MonthNarrow(time.March)) - // ... - - // Weekdays Wide - fmt.Println(l.WeekdayWide(time.Sunday)) - fmt.Println(l.WeekdayWide(time.Monday)) - fmt.Println(l.WeekdayWide(time.Tuesday)) - // ... - - // Weekdays Abbreviated - fmt.Println(l.WeekdayAbbreviated(time.Sunday)) - fmt.Println(l.WeekdayAbbreviated(time.Monday)) - fmt.Println(l.WeekdayAbbreviated(time.Tuesday)) - // ... - - // Weekdays Short - fmt.Println(l.WeekdayShort(time.Sunday)) - fmt.Println(l.WeekdayShort(time.Monday)) - fmt.Println(l.WeekdayShort(time.Tuesday)) - // ... - - // Weekdays Narrow - fmt.Println(l.WeekdayNarrow(time.Sunday)) - fmt.Println(l.WeekdayNarrow(time.Monday)) - fmt.Println(l.WeekdayNarrow(time.Tuesday)) - // ... - - var f64 float64 - - f64 = -10356.4523 - - // Number - fmt.Println(l.FmtNumber(f64, 2)) - - // Currency - fmt.Println(l.FmtCurrency(f64, 2, currency.CAD)) - fmt.Println(l.FmtCurrency(f64, 2, currency.USD)) - - // Accounting - fmt.Println(l.FmtAccounting(f64, 2, currency.CAD)) - fmt.Println(l.FmtAccounting(f64, 2, currency.USD)) - - f64 = 78.12 - - // Percent - fmt.Println(l.FmtPercent(f64, 0)) - - // Plural Rules for locale, so you know what rules you must cover - fmt.Println(l.PluralsCardinal()) - fmt.Println(l.PluralsOrdinal()) - - // Cardinal Plural Rules - fmt.Println(l.CardinalPluralRule(1, 0)) - fmt.Println(l.CardinalPluralRule(1.0, 0)) - fmt.Println(l.CardinalPluralRule(1.0, 1)) - fmt.Println(l.CardinalPluralRule(3, 0)) - - // Ordinal Plural Rules - fmt.Println(l.OrdinalPluralRule(21, 0)) // 21st - fmt.Println(l.OrdinalPluralRule(22, 0)) // 22nd - fmt.Println(l.OrdinalPluralRule(33, 0)) // 33rd - fmt.Println(l.OrdinalPluralRule(34, 0)) // 34th - - // Range Plural Rules - fmt.Println(l.RangePluralRule(1, 0, 1, 0)) // 1-1 - fmt.Println(l.RangePluralRule(1, 0, 2, 0)) // 1-2 - fmt.Println(l.RangePluralRule(5, 0, 8, 0)) // 5-8 -} -``` - -NOTES: -------- -These rules were generated from the [Unicode CLDR Project](http://cldr.unicode.org/), if you encounter any issues -I strongly encourage contributing to the CLDR project to get the locale information corrected and the next time -these locales are regenerated the fix will come with. - -I do however realize that time constraints are often important and so there are two options: - -1. Create your own locale, copy, paste and modify, and ensure it complies with the `Translator` interface. -2. Add an exception in the locale generation code directly and once regenerated, fix will be in place. - -Please to not make fixes inside the locale files, they WILL get overwritten when the locales are regenerated. - -License ------- -Distributed under MIT License, please see license file in code for more details. diff --git a/vendor/github.com/go-playground/locales/currency/currency.go b/vendor/github.com/go-playground/locales/currency/currency.go deleted file mode 100644 index b5a95fb..0000000 --- a/vendor/github.com/go-playground/locales/currency/currency.go +++ /dev/null @@ -1,311 +0,0 @@ -package currency - -// Type is the currency type associated with the locales currency enum -type Type int - -// locale currencies -const ( - ADP Type = iota - AED - AFA - AFN - ALK - ALL - AMD - ANG - AOA - AOK - AON - AOR - ARA - ARL - ARM - ARP - ARS - ATS - AUD - AWG - AZM - AZN - BAD - BAM - BAN - BBD - BDT - BEC - BEF - BEL - BGL - BGM - BGN - BGO - BHD - BIF - BMD - BND - BOB - BOL - BOP - BOV - BRB - BRC - BRE - BRL - BRN - BRR - BRZ - BSD - BTN - BUK - BWP - BYB - BYN - BYR - BZD - CAD - CDF - CHE - CHF - CHW - CLE - CLF - CLP - CNH - CNX - CNY - COP - COU - CRC - CSD - CSK - CUC - CUP - CVE - CYP - CZK - DDM - DEM - DJF - DKK - DOP - DZD - ECS - ECV - EEK - EGP - ERN - ESA - ESB - ESP - ETB - EUR - FIM - FJD - FKP - FRF - GBP - GEK - GEL - GHC - GHS - GIP - GMD - GNF - GNS - GQE - GRD - GTQ - GWE - GWP - GYD - HKD - HNL - HRD - HRK - HTG - HUF - IDR - IEP - ILP - ILR - ILS - INR - IQD - IRR - ISJ - ISK - ITL - JMD - JOD - JPY - KES - KGS - KHR - KMF - KPW - KRH - KRO - KRW - KWD - KYD - KZT - LAK - LBP - LKR - LRD - LSL - LTL - LTT - LUC - LUF - LUL - LVL - LVR - LYD - MAD - MAF - MCF - MDC - MDL - MGA - MGF - MKD - MKN - MLF - MMK - MNT - MOP - MRO - MRU - MTL - MTP - MUR - MVP - MVR - MWK - MXN - MXP - MXV - MYR - MZE - MZM - MZN - NAD - NGN - NIC - NIO - NLG - NOK - NPR - NZD - OMR - PAB - PEI - PEN - PES - PGK - PHP - PKR - PLN - PLZ - PTE - PYG - QAR - RHD - ROL - RON - RSD - RUB - RUR - RWF - SAR - SBD - SCR - SDD - SDG - SDP - SEK - SGD - SHP - SIT - SKK - SLL - SOS - SRD - SRG - SSP - STD - STN - SUR - SVC - SYP - SZL - THB - TJR - TJS - TMM - TMT - TND - TOP - TPE - TRL - TRY - TTD - TWD - TZS - UAH - UAK - UGS - UGX - USD - USN - USS - UYI - UYP - UYU - UYW - UZS - VEB - VEF - VES - VND - VNN - VUV - WST - XAF - XAG - XAU - XBA - XBB - XBC - XBD - XCD - XDR - XEU - XFO - XFU - XOF - XPD - XPF - XPT - XRE - XSU - XTS - XUA - XXX - YDD - YER - YUD - YUM - YUN - YUR - ZAL - ZAR - ZMK - ZMW - ZRN - ZRZ - ZWD - ZWL - ZWR -) diff --git a/vendor/github.com/go-playground/locales/logo.png b/vendor/github.com/go-playground/locales/logo.png deleted file mode 100644 index 3038276..0000000 Binary files a/vendor/github.com/go-playground/locales/logo.png and /dev/null differ diff --git a/vendor/github.com/go-playground/locales/rules.go b/vendor/github.com/go-playground/locales/rules.go deleted file mode 100644 index 9202900..0000000 --- a/vendor/github.com/go-playground/locales/rules.go +++ /dev/null @@ -1,293 +0,0 @@ -package locales - -import ( - "strconv" - "time" - - "github.com/go-playground/locales/currency" -) - -// // ErrBadNumberValue is returned when the number passed for -// // plural rule determination cannot be parsed -// type ErrBadNumberValue struct { -// NumberValue string -// InnerError error -// } - -// // Error returns ErrBadNumberValue error string -// func (e *ErrBadNumberValue) Error() string { -// return fmt.Sprintf("Invalid Number Value '%s' %s", e.NumberValue, e.InnerError) -// } - -// var _ error = new(ErrBadNumberValue) - -// PluralRule denotes the type of plural rules -type PluralRule int - -// PluralRule's -const ( - PluralRuleUnknown PluralRule = iota - PluralRuleZero // zero - PluralRuleOne // one - singular - PluralRuleTwo // two - dual - PluralRuleFew // few - paucal - PluralRuleMany // many - also used for fractions if they have a separate class - PluralRuleOther // other - required—general plural form—also used if the language only has a single form -) - -const ( - pluralsString = "UnknownZeroOneTwoFewManyOther" -) - -// Translator encapsulates an instance of a locale -// NOTE: some values are returned as a []byte just in case the caller -// wishes to add more and can help avoid allocations; otherwise just cast as string -type Translator interface { - - // The following Functions are for overriding, debugging or developing - // with a Translator Locale - - // Locale returns the string value of the translator - Locale() string - - // returns an array of cardinal plural rules associated - // with this translator - PluralsCardinal() []PluralRule - - // returns an array of ordinal plural rules associated - // with this translator - PluralsOrdinal() []PluralRule - - // returns an array of range plural rules associated - // with this translator - PluralsRange() []PluralRule - - // returns the cardinal PluralRule given 'num' and digits/precision of 'v' for locale - CardinalPluralRule(num float64, v uint64) PluralRule - - // returns the ordinal PluralRule given 'num' and digits/precision of 'v' for locale - OrdinalPluralRule(num float64, v uint64) PluralRule - - // returns the ordinal PluralRule given 'num1', 'num2' and digits/precision of 'v1' and 'v2' for locale - RangePluralRule(num1 float64, v1 uint64, num2 float64, v2 uint64) PluralRule - - // returns the locales abbreviated month given the 'month' provided - MonthAbbreviated(month time.Month) string - - // returns the locales abbreviated months - MonthsAbbreviated() []string - - // returns the locales narrow month given the 'month' provided - MonthNarrow(month time.Month) string - - // returns the locales narrow months - MonthsNarrow() []string - - // returns the locales wide month given the 'month' provided - MonthWide(month time.Month) string - - // returns the locales wide months - MonthsWide() []string - - // returns the locales abbreviated weekday given the 'weekday' provided - WeekdayAbbreviated(weekday time.Weekday) string - - // returns the locales abbreviated weekdays - WeekdaysAbbreviated() []string - - // returns the locales narrow weekday given the 'weekday' provided - WeekdayNarrow(weekday time.Weekday) string - - // WeekdaysNarrowreturns the locales narrow weekdays - WeekdaysNarrow() []string - - // returns the locales short weekday given the 'weekday' provided - WeekdayShort(weekday time.Weekday) string - - // returns the locales short weekdays - WeekdaysShort() []string - - // returns the locales wide weekday given the 'weekday' provided - WeekdayWide(weekday time.Weekday) string - - // returns the locales wide weekdays - WeekdaysWide() []string - - // The following Functions are common Formatting functionsfor the Translator's Locale - - // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v' - FmtNumber(num float64, v uint64) string - - // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v' - // NOTE: 'num' passed into FmtPercent is assumed to be in percent already - FmtPercent(num float64, v uint64) string - - // returns the currency representation of 'num' with digits/precision of 'v' for locale - FmtCurrency(num float64, v uint64, currency currency.Type) string - - // returns the currency representation of 'num' with digits/precision of 'v' for locale - // in accounting notation. - FmtAccounting(num float64, v uint64, currency currency.Type) string - - // returns the short date representation of 't' for locale - FmtDateShort(t time.Time) string - - // returns the medium date representation of 't' for locale - FmtDateMedium(t time.Time) string - - // returns the long date representation of 't' for locale - FmtDateLong(t time.Time) string - - // returns the full date representation of 't' for locale - FmtDateFull(t time.Time) string - - // returns the short time representation of 't' for locale - FmtTimeShort(t time.Time) string - - // returns the medium time representation of 't' for locale - FmtTimeMedium(t time.Time) string - - // returns the long time representation of 't' for locale - FmtTimeLong(t time.Time) string - - // returns the full time representation of 't' for locale - FmtTimeFull(t time.Time) string -} - -// String returns the string value of PluralRule -func (p PluralRule) String() string { - - switch p { - case PluralRuleZero: - return pluralsString[7:11] - case PluralRuleOne: - return pluralsString[11:14] - case PluralRuleTwo: - return pluralsString[14:17] - case PluralRuleFew: - return pluralsString[17:20] - case PluralRuleMany: - return pluralsString[20:24] - case PluralRuleOther: - return pluralsString[24:] - default: - return pluralsString[:7] - } -} - -// -// Precision Notes: -// -// must specify a precision >= 0, and here is why https://play.golang.org/p/LyL90U0Vyh -// -// v := float64(3.141) -// i := float64(int64(v)) -// -// fmt.Println(v - i) -// -// or -// -// s := strconv.FormatFloat(v-i, 'f', -1, 64) -// fmt.Println(s) -// -// these will not print what you'd expect: 0.14100000000000001 -// and so this library requires a precision to be specified, or -// inaccurate plural rules could be applied. -// -// -// -// n - absolute value of the source number (integer and decimals). -// i - integer digits of n. -// v - number of visible fraction digits in n, with trailing zeros. -// w - number of visible fraction digits in n, without trailing zeros. -// f - visible fractional digits in n, with trailing zeros. -// t - visible fractional digits in n, without trailing zeros. -// -// -// Func(num float64, v uint64) // v = digits/precision and prevents -1 as a special case as this can lead to very unexpected behaviour, see precision note's above. -// -// n := math.Abs(num) -// i := int64(n) -// v := v -// -// -// w := strconv.FormatFloat(num-float64(i), 'f', int(v), 64) // then parse backwards on string until no more zero's.... -// f := strconv.FormatFloat(n, 'f', int(v), 64) // then turn everything after decimal into an int64 -// t := strconv.FormatFloat(n, 'f', int(v), 64) // then parse backwards on string until no more zero's.... -// -// -// -// General Inclusion Rules -// - v will always be available inherently -// - all require n -// - w requires i -// - -// W returns the number of visible fraction digits in N, without trailing zeros. -func W(n float64, v uint64) (w int64) { - - s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) - - // with either be '0' or '0.xxxx', so if 1 then w will be zero - // otherwise need to parse - if len(s) != 1 { - - s = s[2:] - end := len(s) + 1 - - for i := end; i >= 0; i-- { - if s[i] != '0' { - end = i + 1 - break - } - } - - w = int64(len(s[:end])) - } - - return -} - -// F returns the visible fractional digits in N, with trailing zeros. -func F(n float64, v uint64) (f int64) { - - s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) - - // with either be '0' or '0.xxxx', so if 1 then f will be zero - // otherwise need to parse - if len(s) != 1 { - - // ignoring error, because it can't fail as we generated - // the string internally from a real number - f, _ = strconv.ParseInt(s[2:], 10, 64) - } - - return -} - -// T returns the visible fractional digits in N, without trailing zeros. -func T(n float64, v uint64) (t int64) { - - s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) - - // with either be '0' or '0.xxxx', so if 1 then t will be zero - // otherwise need to parse - if len(s) != 1 { - - s = s[2:] - end := len(s) + 1 - - for i := end; i >= 0; i-- { - if s[i] != '0' { - end = i + 1 - break - } - } - - // ignoring error, because it can't fail as we generated - // the string internally from a real number - t, _ = strconv.ParseInt(s[:end], 10, 64) - } - - return -} diff --git a/vendor/github.com/go-playground/universal-translator/.gitignore b/vendor/github.com/go-playground/universal-translator/.gitignore deleted file mode 100644 index bc4e07f..0000000 --- a/vendor/github.com/go-playground/universal-translator/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof -*.coverprofile \ No newline at end of file diff --git a/vendor/github.com/go-playground/universal-translator/.travis.yml b/vendor/github.com/go-playground/universal-translator/.travis.yml deleted file mode 100644 index 39b8b92..0000000 --- a/vendor/github.com/go-playground/universal-translator/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: go -go: - - 1.13.4 - - tip -matrix: - allow_failures: - - go: tip - -notifications: - email: - recipients: dean.karn@gmail.com - on_success: change - on_failure: always - -before_install: - - go install github.com/mattn/goveralls - -# Only clone the most recent commit. -git: - depth: 1 - -script: - - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./... - -after_success: | - [ $TRAVIS_GO_VERSION = 1.13.4 ] && - goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN \ No newline at end of file diff --git a/vendor/github.com/go-playground/universal-translator/LICENSE b/vendor/github.com/go-playground/universal-translator/LICENSE deleted file mode 100644 index 8d8aba1..0000000 --- a/vendor/github.com/go-playground/universal-translator/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Go Playground - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/go-playground/universal-translator/Makefile b/vendor/github.com/go-playground/universal-translator/Makefile deleted file mode 100644 index ec3455b..0000000 --- a/vendor/github.com/go-playground/universal-translator/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -GOCMD=GO111MODULE=on go - -linters-install: - @golangci-lint --version >/dev/null 2>&1 || { \ - echo "installing linting tools..."; \ - curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.41.1; \ - } - -lint: linters-install - golangci-lint run - -test: - $(GOCMD) test -cover -race ./... - -bench: - $(GOCMD) test -bench=. -benchmem ./... - -.PHONY: test lint linters-install \ No newline at end of file diff --git a/vendor/github.com/go-playground/universal-translator/README.md b/vendor/github.com/go-playground/universal-translator/README.md deleted file mode 100644 index 46dec6d..0000000 --- a/vendor/github.com/go-playground/universal-translator/README.md +++ /dev/null @@ -1,89 +0,0 @@ -## universal-translator -![Project status](https://img.shields.io/badge/version-0.18.0-green.svg) -[![Build Status](https://travis-ci.org/go-playground/universal-translator.svg?branch=master)](https://travis-ci.org/go-playground/universal-translator) -[![Coverage Status](https://coveralls.io/repos/github/go-playground/universal-translator/badge.svg)](https://coveralls.io/github/go-playground/universal-translator) -[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/universal-translator)](https://goreportcard.com/report/github.com/go-playground/universal-translator) -[![GoDoc](https://godoc.org/github.com/go-playground/universal-translator?status.svg)](https://godoc.org/github.com/go-playground/universal-translator) -![License](https://img.shields.io/dub/l/vibe-d.svg) -[![Gitter](https://badges.gitter.im/go-playground/universal-translator.svg)](https://gitter.im/go-playground/universal-translator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) - -Universal Translator is an i18n Translator for Go/Golang using CLDR data + pluralization rules - -Why another i18n library? --------------------------- -Because none of the plural rules seem to be correct out there, including the previous implementation of this package, -so I took it upon myself to create [locales](https://github.com/go-playground/locales) for everyone to use; this package -is a thin wrapper around [locales](https://github.com/go-playground/locales) in order to store and translate text for -use in your applications. - -Features --------- -- [x] Rules generated from the [CLDR](http://cldr.unicode.org/index/downloads) data, v36.0.1 -- [x] Contains Cardinal, Ordinal and Range Plural Rules -- [x] Contains Month, Weekday and Timezone translations built in -- [x] Contains Date & Time formatting functions -- [x] Contains Number, Currency, Accounting and Percent formatting functions -- [x] Supports the "Gregorian" calendar only ( my time isn't unlimited, had to draw the line somewhere ) -- [x] Support loading translations from files -- [x] Exporting translations to file(s), mainly for getting them professionally translated -- [ ] Code Generation for translation files -> Go code.. i.e. after it has been professionally translated -- [ ] Tests for all languages, I need help with this, please see [here](https://github.com/go-playground/locales/issues/1) - -Installation ------------ - -Use go get - -```shell -go get github.com/go-playground/universal-translator -``` - -Usage & Documentation -------- - -Please see https://godoc.org/github.com/go-playground/universal-translator for usage docs - -##### Examples: - -- [Basic](https://github.com/go-playground/universal-translator/tree/master/_examples/basic) -- [Full - no files](https://github.com/go-playground/universal-translator/tree/master/_examples/full-no-files) -- [Full - with files](https://github.com/go-playground/universal-translator/tree/master/_examples/full-with-files) - -File formatting --------------- -All types, Plain substitution, Cardinal, Ordinal and Range translations can all be contained within the same file(s); -they are only separated for easy viewing. - -##### Examples: - -- [Formats](https://github.com/go-playground/universal-translator/tree/master/_examples/file-formats) - -##### Basic Makeup -NOTE: not all fields are needed for all translation types, see [examples](https://github.com/go-playground/universal-translator/tree/master/_examples/file-formats) -```json -{ - "locale": "en", - "key": "days-left", - "trans": "You have {0} day left.", - "type": "Cardinal", - "rule": "One", - "override": false -} -``` -|Field|Description| -|---|---| -|locale|The locale for which the translation is for.| -|key|The translation key that will be used to store and lookup each translation; normally it is a string or integer.| -|trans|The actual translation text.| -|type|The type of translation Cardinal, Ordinal, Range or "" for a plain substitution(not required to be defined if plain used)| -|rule|The plural rule for which the translation is for eg. One, Two, Few, Many or Other.(not required to be defined if plain used)| -|override|If you wish to override an existing translation that has already been registered, set this to 'true'. 99% of the time there is no need to define it.| - -Help With Tests ---------------- -To anyone interesting in helping or contributing, I sure could use some help creating tests for each language. -Please see issue [here](https://github.com/go-playground/locales/issues/1) for details. - -License ------- -Distributed under MIT License, please see license file in code for more details. diff --git a/vendor/github.com/go-playground/universal-translator/errors.go b/vendor/github.com/go-playground/universal-translator/errors.go deleted file mode 100644 index 38b163b..0000000 --- a/vendor/github.com/go-playground/universal-translator/errors.go +++ /dev/null @@ -1,148 +0,0 @@ -package ut - -import ( - "errors" - "fmt" - - "github.com/go-playground/locales" -) - -var ( - // ErrUnknowTranslation indicates the translation could not be found - ErrUnknowTranslation = errors.New("Unknown Translation") -) - -var _ error = new(ErrConflictingTranslation) -var _ error = new(ErrRangeTranslation) -var _ error = new(ErrOrdinalTranslation) -var _ error = new(ErrCardinalTranslation) -var _ error = new(ErrMissingPluralTranslation) -var _ error = new(ErrExistingTranslator) - -// ErrExistingTranslator is the error representing a conflicting translator -type ErrExistingTranslator struct { - locale string -} - -// Error returns ErrExistingTranslator's internal error text -func (e *ErrExistingTranslator) Error() string { - return fmt.Sprintf("error: conflicting translator for locale '%s'", e.locale) -} - -// ErrConflictingTranslation is the error representing a conflicting translation -type ErrConflictingTranslation struct { - locale string - key interface{} - rule locales.PluralRule - text string -} - -// Error returns ErrConflictingTranslation's internal error text -func (e *ErrConflictingTranslation) Error() string { - - if _, ok := e.key.(string); !ok { - return fmt.Sprintf("error: conflicting key '%#v' rule '%s' with text '%s' for locale '%s', value being ignored", e.key, e.rule, e.text, e.locale) - } - - return fmt.Sprintf("error: conflicting key '%s' rule '%s' with text '%s' for locale '%s', value being ignored", e.key, e.rule, e.text, e.locale) -} - -// ErrRangeTranslation is the error representing a range translation error -type ErrRangeTranslation struct { - text string -} - -// Error returns ErrRangeTranslation's internal error text -func (e *ErrRangeTranslation) Error() string { - return e.text -} - -// ErrOrdinalTranslation is the error representing an ordinal translation error -type ErrOrdinalTranslation struct { - text string -} - -// Error returns ErrOrdinalTranslation's internal error text -func (e *ErrOrdinalTranslation) Error() string { - return e.text -} - -// ErrCardinalTranslation is the error representing a cardinal translation error -type ErrCardinalTranslation struct { - text string -} - -// Error returns ErrCardinalTranslation's internal error text -func (e *ErrCardinalTranslation) Error() string { - return e.text -} - -// ErrMissingPluralTranslation is the error signifying a missing translation given -// the locales plural rules. -type ErrMissingPluralTranslation struct { - locale string - key interface{} - rule locales.PluralRule - translationType string -} - -// Error returns ErrMissingPluralTranslation's internal error text -func (e *ErrMissingPluralTranslation) Error() string { - - if _, ok := e.key.(string); !ok { - return fmt.Sprintf("error: missing '%s' plural rule '%s' for translation with key '%#v' and locale '%s'", e.translationType, e.rule, e.key, e.locale) - } - - return fmt.Sprintf("error: missing '%s' plural rule '%s' for translation with key '%s' and locale '%s'", e.translationType, e.rule, e.key, e.locale) -} - -// ErrMissingBracket is the error representing a missing bracket in a translation -// eg. This is a {0 <-- missing ending '}' -type ErrMissingBracket struct { - locale string - key interface{} - text string -} - -// Error returns ErrMissingBracket error message -func (e *ErrMissingBracket) Error() string { - return fmt.Sprintf("error: missing bracket '{}', in translation. locale: '%s' key: '%v' text: '%s'", e.locale, e.key, e.text) -} - -// ErrBadParamSyntax is the error representing a bad parameter definition in a translation -// eg. This is a {must-be-int} -type ErrBadParamSyntax struct { - locale string - param string - key interface{} - text string -} - -// Error returns ErrBadParamSyntax error message -func (e *ErrBadParamSyntax) Error() string { - return fmt.Sprintf("error: bad parameter syntax, missing parameter '%s' in translation. locale: '%s' key: '%v' text: '%s'", e.param, e.locale, e.key, e.text) -} - -// import/export errors - -// ErrMissingLocale is the error representing an expected locale that could -// not be found aka locale not registered with the UniversalTranslator Instance -type ErrMissingLocale struct { - locale string -} - -// Error returns ErrMissingLocale's internal error text -func (e *ErrMissingLocale) Error() string { - return fmt.Sprintf("error: locale '%s' not registered.", e.locale) -} - -// ErrBadPluralDefinition is the error representing an incorrect plural definition -// usually found within translations defined within files during the import process. -type ErrBadPluralDefinition struct { - tl translation -} - -// Error returns ErrBadPluralDefinition's internal error text -func (e *ErrBadPluralDefinition) Error() string { - return fmt.Sprintf("error: bad plural definition '%#v'", e.tl) -} diff --git a/vendor/github.com/go-playground/universal-translator/import_export.go b/vendor/github.com/go-playground/universal-translator/import_export.go deleted file mode 100644 index 1216f19..0000000 --- a/vendor/github.com/go-playground/universal-translator/import_export.go +++ /dev/null @@ -1,276 +0,0 @@ -package ut - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "path/filepath" - - "io" - - "github.com/go-playground/locales" -) - -type translation struct { - Locale string `json:"locale"` - Key interface{} `json:"key"` // either string or integer - Translation string `json:"trans"` - PluralType string `json:"type,omitempty"` - PluralRule string `json:"rule,omitempty"` - OverrideExisting bool `json:"override,omitempty"` -} - -const ( - cardinalType = "Cardinal" - ordinalType = "Ordinal" - rangeType = "Range" -) - -// ImportExportFormat is the format of the file import or export -type ImportExportFormat uint8 - -// supported Export Formats -const ( - FormatJSON ImportExportFormat = iota -) - -// Export writes the translations out to a file on disk. -// -// NOTE: this currently only works with string or int translations keys. -func (t *UniversalTranslator) Export(format ImportExportFormat, dirname string) error { - - _, err := os.Stat(dirname) - fmt.Println(dirname, err, os.IsNotExist(err)) - if err != nil { - - if !os.IsNotExist(err) { - return err - } - - if err = os.MkdirAll(dirname, 0744); err != nil { - return err - } - } - - // build up translations - var trans []translation - var b []byte - var ext string - - for _, locale := range t.translators { - - for k, v := range locale.(*translator).translations { - trans = append(trans, translation{ - Locale: locale.Locale(), - Key: k, - Translation: v.text, - }) - } - - for k, pluralTrans := range locale.(*translator).cardinalTanslations { - - for i, plural := range pluralTrans { - - // leave enough for all plural rules - // but not all are set for all languages. - if plural == nil { - continue - } - - trans = append(trans, translation{ - Locale: locale.Locale(), - Key: k.(string), - Translation: plural.text, - PluralType: cardinalType, - PluralRule: locales.PluralRule(i).String(), - }) - } - } - - for k, pluralTrans := range locale.(*translator).ordinalTanslations { - - for i, plural := range pluralTrans { - - // leave enough for all plural rules - // but not all are set for all languages. - if plural == nil { - continue - } - - trans = append(trans, translation{ - Locale: locale.Locale(), - Key: k.(string), - Translation: plural.text, - PluralType: ordinalType, - PluralRule: locales.PluralRule(i).String(), - }) - } - } - - for k, pluralTrans := range locale.(*translator).rangeTanslations { - - for i, plural := range pluralTrans { - - // leave enough for all plural rules - // but not all are set for all languages. - if plural == nil { - continue - } - - trans = append(trans, translation{ - Locale: locale.Locale(), - Key: k.(string), - Translation: plural.text, - PluralType: rangeType, - PluralRule: locales.PluralRule(i).String(), - }) - } - } - - switch format { - case FormatJSON: - b, err = json.MarshalIndent(trans, "", " ") - ext = ".json" - } - - if err != nil { - return err - } - - err = ioutil.WriteFile(filepath.Join(dirname, fmt.Sprintf("%s%s", locale.Locale(), ext)), b, 0644) - if err != nil { - return err - } - - trans = trans[0:0] - } - - return nil -} - -// Import reads the translations out of a file or directory on disk. -// -// NOTE: this currently only works with string or int translations keys. -func (t *UniversalTranslator) Import(format ImportExportFormat, dirnameOrFilename string) error { - - fi, err := os.Stat(dirnameOrFilename) - if err != nil { - return err - } - - processFn := func(filename string) error { - - f, err := os.Open(filename) - if err != nil { - return err - } - defer f.Close() - - return t.ImportByReader(format, f) - } - - if !fi.IsDir() { - return processFn(dirnameOrFilename) - } - - // recursively go through directory - walker := func(path string, info os.FileInfo, err error) error { - - if info.IsDir() { - return nil - } - - switch format { - case FormatJSON: - // skip non JSON files - if filepath.Ext(info.Name()) != ".json" { - return nil - } - } - - return processFn(path) - } - - return filepath.Walk(dirnameOrFilename, walker) -} - -// ImportByReader imports the the translations found within the contents read from the supplied reader. -// -// NOTE: generally used when assets have been embedded into the binary and are already in memory. -func (t *UniversalTranslator) ImportByReader(format ImportExportFormat, reader io.Reader) error { - - b, err := ioutil.ReadAll(reader) - if err != nil { - return err - } - - var trans []translation - - switch format { - case FormatJSON: - err = json.Unmarshal(b, &trans) - } - - if err != nil { - return err - } - - for _, tl := range trans { - - locale, found := t.FindTranslator(tl.Locale) - if !found { - return &ErrMissingLocale{locale: tl.Locale} - } - - pr := stringToPR(tl.PluralRule) - - if pr == locales.PluralRuleUnknown { - - err = locale.Add(tl.Key, tl.Translation, tl.OverrideExisting) - if err != nil { - return err - } - - continue - } - - switch tl.PluralType { - case cardinalType: - err = locale.AddCardinal(tl.Key, tl.Translation, pr, tl.OverrideExisting) - case ordinalType: - err = locale.AddOrdinal(tl.Key, tl.Translation, pr, tl.OverrideExisting) - case rangeType: - err = locale.AddRange(tl.Key, tl.Translation, pr, tl.OverrideExisting) - default: - return &ErrBadPluralDefinition{tl: tl} - } - - if err != nil { - return err - } - } - - return nil -} - -func stringToPR(s string) locales.PluralRule { - - switch s { - case "Zero": - return locales.PluralRuleZero - case "One": - return locales.PluralRuleOne - case "Two": - return locales.PluralRuleTwo - case "Few": - return locales.PluralRuleFew - case "Many": - return locales.PluralRuleMany - case "Other": - return locales.PluralRuleOther - default: - return locales.PluralRuleUnknown - } - -} diff --git a/vendor/github.com/go-playground/universal-translator/logo.png b/vendor/github.com/go-playground/universal-translator/logo.png deleted file mode 100644 index a37aa8c..0000000 Binary files a/vendor/github.com/go-playground/universal-translator/logo.png and /dev/null differ diff --git a/vendor/github.com/go-playground/universal-translator/translator.go b/vendor/github.com/go-playground/universal-translator/translator.go deleted file mode 100644 index 24b18db..0000000 --- a/vendor/github.com/go-playground/universal-translator/translator.go +++ /dev/null @@ -1,420 +0,0 @@ -package ut - -import ( - "fmt" - "strconv" - "strings" - - "github.com/go-playground/locales" -) - -const ( - paramZero = "{0}" - paramOne = "{1}" - unknownTranslation = "" -) - -// Translator is universal translators -// translator instance which is a thin wrapper -// around locales.Translator instance providing -// some extra functionality -type Translator interface { - locales.Translator - - // adds a normal translation for a particular language/locale - // {#} is the only replacement type accepted and are ad infinitum - // eg. one: '{0} day left' other: '{0} days left' - Add(key interface{}, text string, override bool) error - - // adds a cardinal plural translation for a particular language/locale - // {0} is the only replacement type accepted and only one variable is accepted as - // multiple cannot be used for a plural rule determination, unless it is a range; - // see AddRange below. - // eg. in locale 'en' one: '{0} day left' other: '{0} days left' - AddCardinal(key interface{}, text string, rule locales.PluralRule, override bool) error - - // adds an ordinal plural translation for a particular language/locale - // {0} is the only replacement type accepted and only one variable is accepted as - // multiple cannot be used for a plural rule determination, unless it is a range; - // see AddRange below. - // eg. in locale 'en' one: '{0}st day of spring' other: '{0}nd day of spring' - // - 1st, 2nd, 3rd... - AddOrdinal(key interface{}, text string, rule locales.PluralRule, override bool) error - - // adds a range plural translation for a particular language/locale - // {0} and {1} are the only replacement types accepted and only these are accepted. - // eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left' - AddRange(key interface{}, text string, rule locales.PluralRule, override bool) error - - // creates the translation for the locale given the 'key' and params passed in - T(key interface{}, params ...string) (string, error) - - // creates the cardinal translation for the locale given the 'key', 'num' and 'digit' arguments - // and param passed in - C(key interface{}, num float64, digits uint64, param string) (string, error) - - // creates the ordinal translation for the locale given the 'key', 'num' and 'digit' arguments - // and param passed in - O(key interface{}, num float64, digits uint64, param string) (string, error) - - // creates the range translation for the locale given the 'key', 'num1', 'digit1', 'num2' and - // 'digit2' arguments and 'param1' and 'param2' passed in - R(key interface{}, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) (string, error) - - // VerifyTranslations checks to ensures that no plural rules have been - // missed within the translations. - VerifyTranslations() error -} - -var _ Translator = new(translator) -var _ locales.Translator = new(translator) - -type translator struct { - locales.Translator - translations map[interface{}]*transText - cardinalTanslations map[interface{}][]*transText // array index is mapped to locales.PluralRule index + the locales.PluralRuleUnknown - ordinalTanslations map[interface{}][]*transText - rangeTanslations map[interface{}][]*transText -} - -type transText struct { - text string - indexes []int -} - -func newTranslator(trans locales.Translator) Translator { - return &translator{ - Translator: trans, - translations: make(map[interface{}]*transText), // translation text broken up by byte index - cardinalTanslations: make(map[interface{}][]*transText), - ordinalTanslations: make(map[interface{}][]*transText), - rangeTanslations: make(map[interface{}][]*transText), - } -} - -// Add adds a normal translation for a particular language/locale -// {#} is the only replacement type accepted and are ad infinitum -// eg. one: '{0} day left' other: '{0} days left' -func (t *translator) Add(key interface{}, text string, override bool) error { - - if _, ok := t.translations[key]; ok && !override { - return &ErrConflictingTranslation{locale: t.Locale(), key: key, text: text} - } - - lb := strings.Count(text, "{") - rb := strings.Count(text, "}") - - if lb != rb { - return &ErrMissingBracket{locale: t.Locale(), key: key, text: text} - } - - trans := &transText{ - text: text, - } - - var idx int - - for i := 0; i < lb; i++ { - s := "{" + strconv.Itoa(i) + "}" - idx = strings.Index(text, s) - if idx == -1 { - return &ErrBadParamSyntax{locale: t.Locale(), param: s, key: key, text: text} - } - - trans.indexes = append(trans.indexes, idx) - trans.indexes = append(trans.indexes, idx+len(s)) - } - - t.translations[key] = trans - - return nil -} - -// AddCardinal adds a cardinal plural translation for a particular language/locale -// {0} is the only replacement type accepted and only one variable is accepted as -// multiple cannot be used for a plural rule determination, unless it is a range; -// see AddRange below. -// eg. in locale 'en' one: '{0} day left' other: '{0} days left' -func (t *translator) AddCardinal(key interface{}, text string, rule locales.PluralRule, override bool) error { - - var verified bool - - // verify plural rule exists for locale - for _, pr := range t.PluralsCardinal() { - if pr == rule { - verified = true - break - } - } - - if !verified { - return &ErrCardinalTranslation{text: fmt.Sprintf("error: cardinal plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)} - } - - tarr, ok := t.cardinalTanslations[key] - if ok { - // verify not adding a conflicting record - if len(tarr) > 0 && tarr[rule] != nil && !override { - return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text} - } - - } else { - tarr = make([]*transText, 7) - t.cardinalTanslations[key] = tarr - } - - trans := &transText{ - text: text, - indexes: make([]int, 2), - } - - tarr[rule] = trans - - idx := strings.Index(text, paramZero) - if idx == -1 { - tarr[rule] = nil - return &ErrCardinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddCardinal'. locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)} - } - - trans.indexes[0] = idx - trans.indexes[1] = idx + len(paramZero) - - return nil -} - -// AddOrdinal adds an ordinal plural translation for a particular language/locale -// {0} is the only replacement type accepted and only one variable is accepted as -// multiple cannot be used for a plural rule determination, unless it is a range; -// see AddRange below. -// eg. in locale 'en' one: '{0}st day of spring' other: '{0}nd day of spring' - 1st, 2nd, 3rd... -func (t *translator) AddOrdinal(key interface{}, text string, rule locales.PluralRule, override bool) error { - - var verified bool - - // verify plural rule exists for locale - for _, pr := range t.PluralsOrdinal() { - if pr == rule { - verified = true - break - } - } - - if !verified { - return &ErrOrdinalTranslation{text: fmt.Sprintf("error: ordinal plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)} - } - - tarr, ok := t.ordinalTanslations[key] - if ok { - // verify not adding a conflicting record - if len(tarr) > 0 && tarr[rule] != nil && !override { - return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text} - } - - } else { - tarr = make([]*transText, 7) - t.ordinalTanslations[key] = tarr - } - - trans := &transText{ - text: text, - indexes: make([]int, 2), - } - - tarr[rule] = trans - - idx := strings.Index(text, paramZero) - if idx == -1 { - tarr[rule] = nil - return &ErrOrdinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddOrdinal'. locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)} - } - - trans.indexes[0] = idx - trans.indexes[1] = idx + len(paramZero) - - return nil -} - -// AddRange adds a range plural translation for a particular language/locale -// {0} and {1} are the only replacement types accepted and only these are accepted. -// eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left' -func (t *translator) AddRange(key interface{}, text string, rule locales.PluralRule, override bool) error { - - var verified bool - - // verify plural rule exists for locale - for _, pr := range t.PluralsRange() { - if pr == rule { - verified = true - break - } - } - - if !verified { - return &ErrRangeTranslation{text: fmt.Sprintf("error: range plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)} - } - - tarr, ok := t.rangeTanslations[key] - if ok { - // verify not adding a conflicting record - if len(tarr) > 0 && tarr[rule] != nil && !override { - return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text} - } - - } else { - tarr = make([]*transText, 7) - t.rangeTanslations[key] = tarr - } - - trans := &transText{ - text: text, - indexes: make([]int, 4), - } - - tarr[rule] = trans - - idx := strings.Index(text, paramZero) - if idx == -1 { - tarr[rule] = nil - return &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, are you sure you're adding a Range Translation? locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)} - } - - trans.indexes[0] = idx - trans.indexes[1] = idx + len(paramZero) - - idx = strings.Index(text, paramOne) - if idx == -1 { - tarr[rule] = nil - return &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, a Range Translation requires two parameters. locale: '%s' key: '%v' text: '%s'", paramOne, t.Locale(), key, text)} - } - - trans.indexes[2] = idx - trans.indexes[3] = idx + len(paramOne) - - return nil -} - -// T creates the translation for the locale given the 'key' and params passed in -func (t *translator) T(key interface{}, params ...string) (string, error) { - - trans, ok := t.translations[key] - if !ok { - return unknownTranslation, ErrUnknowTranslation - } - - b := make([]byte, 0, 64) - - var start, end, count int - - for i := 0; i < len(trans.indexes); i++ { - end = trans.indexes[i] - b = append(b, trans.text[start:end]...) - b = append(b, params[count]...) - i++ - start = trans.indexes[i] - count++ - } - - b = append(b, trans.text[start:]...) - - return string(b), nil -} - -// C creates the cardinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in -func (t *translator) C(key interface{}, num float64, digits uint64, param string) (string, error) { - - tarr, ok := t.cardinalTanslations[key] - if !ok { - return unknownTranslation, ErrUnknowTranslation - } - - rule := t.CardinalPluralRule(num, digits) - - trans := tarr[rule] - - b := make([]byte, 0, 64) - b = append(b, trans.text[:trans.indexes[0]]...) - b = append(b, param...) - b = append(b, trans.text[trans.indexes[1]:]...) - - return string(b), nil -} - -// O creates the ordinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in -func (t *translator) O(key interface{}, num float64, digits uint64, param string) (string, error) { - - tarr, ok := t.ordinalTanslations[key] - if !ok { - return unknownTranslation, ErrUnknowTranslation - } - - rule := t.OrdinalPluralRule(num, digits) - - trans := tarr[rule] - - b := make([]byte, 0, 64) - b = append(b, trans.text[:trans.indexes[0]]...) - b = append(b, param...) - b = append(b, trans.text[trans.indexes[1]:]...) - - return string(b), nil -} - -// R creates the range translation for the locale given the 'key', 'num1', 'digit1', 'num2' and 'digit2' arguments -// and 'param1' and 'param2' passed in -func (t *translator) R(key interface{}, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) (string, error) { - - tarr, ok := t.rangeTanslations[key] - if !ok { - return unknownTranslation, ErrUnknowTranslation - } - - rule := t.RangePluralRule(num1, digits1, num2, digits2) - - trans := tarr[rule] - - b := make([]byte, 0, 64) - b = append(b, trans.text[:trans.indexes[0]]...) - b = append(b, param1...) - b = append(b, trans.text[trans.indexes[1]:trans.indexes[2]]...) - b = append(b, param2...) - b = append(b, trans.text[trans.indexes[3]:]...) - - return string(b), nil -} - -// VerifyTranslations checks to ensures that no plural rules have been -// missed within the translations. -func (t *translator) VerifyTranslations() error { - - for k, v := range t.cardinalTanslations { - - for _, rule := range t.PluralsCardinal() { - - if v[rule] == nil { - return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "plural", rule: rule, key: k} - } - } - } - - for k, v := range t.ordinalTanslations { - - for _, rule := range t.PluralsOrdinal() { - - if v[rule] == nil { - return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "ordinal", rule: rule, key: k} - } - } - } - - for k, v := range t.rangeTanslations { - - for _, rule := range t.PluralsRange() { - - if v[rule] == nil { - return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "range", rule: rule, key: k} - } - } - } - - return nil -} diff --git a/vendor/github.com/go-playground/universal-translator/universal_translator.go b/vendor/github.com/go-playground/universal-translator/universal_translator.go deleted file mode 100644 index dbf707f..0000000 --- a/vendor/github.com/go-playground/universal-translator/universal_translator.go +++ /dev/null @@ -1,113 +0,0 @@ -package ut - -import ( - "strings" - - "github.com/go-playground/locales" -) - -// UniversalTranslator holds all locale & translation data -type UniversalTranslator struct { - translators map[string]Translator - fallback Translator -} - -// New returns a new UniversalTranslator instance set with -// the fallback locale and locales it should support -func New(fallback locales.Translator, supportedLocales ...locales.Translator) *UniversalTranslator { - - t := &UniversalTranslator{ - translators: make(map[string]Translator), - } - - for _, v := range supportedLocales { - - trans := newTranslator(v) - t.translators[strings.ToLower(trans.Locale())] = trans - - if fallback.Locale() == v.Locale() { - t.fallback = trans - } - } - - if t.fallback == nil && fallback != nil { - t.fallback = newTranslator(fallback) - } - - return t -} - -// FindTranslator trys to find a Translator based on an array of locales -// and returns the first one it can find, otherwise returns the -// fallback translator. -func (t *UniversalTranslator) FindTranslator(locales ...string) (trans Translator, found bool) { - - for _, locale := range locales { - - if trans, found = t.translators[strings.ToLower(locale)]; found { - return - } - } - - return t.fallback, false -} - -// GetTranslator returns the specified translator for the given locale, -// or fallback if not found -func (t *UniversalTranslator) GetTranslator(locale string) (trans Translator, found bool) { - - if trans, found = t.translators[strings.ToLower(locale)]; found { - return - } - - return t.fallback, false -} - -// GetFallback returns the fallback locale -func (t *UniversalTranslator) GetFallback() Translator { - return t.fallback -} - -// AddTranslator adds the supplied translator, if it already exists the override param -// will be checked and if false an error will be returned, otherwise the translator will be -// overridden; if the fallback matches the supplied translator it will be overridden as well -// NOTE: this is normally only used when translator is embedded within a library -func (t *UniversalTranslator) AddTranslator(translator locales.Translator, override bool) error { - - lc := strings.ToLower(translator.Locale()) - _, ok := t.translators[lc] - if ok && !override { - return &ErrExistingTranslator{locale: translator.Locale()} - } - - trans := newTranslator(translator) - - if t.fallback.Locale() == translator.Locale() { - - // because it's optional to have a fallback, I don't impose that limitation - // don't know why you wouldn't but... - if !override { - return &ErrExistingTranslator{locale: translator.Locale()} - } - - t.fallback = trans - } - - t.translators[lc] = trans - - return nil -} - -// VerifyTranslations runs through all locales and identifies any issues -// eg. missing plural rules for a locale -func (t *UniversalTranslator) VerifyTranslations() (err error) { - - for _, trans := range t.translators { - err = trans.VerifyTranslations() - if err != nil { - return - } - } - - return -} diff --git a/vendor/github.com/go-playground/validator/v10/.gitignore b/vendor/github.com/go-playground/validator/v10/.gitignore deleted file mode 100644 index 6e43fac..0000000 --- a/vendor/github.com/go-playground/validator/v10/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test -bin - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof -*.test -*.out -*.txt -cover.html -README.html diff --git a/vendor/github.com/go-playground/validator/v10/LICENSE b/vendor/github.com/go-playground/validator/v10/LICENSE deleted file mode 100644 index 6a2ae9a..0000000 --- a/vendor/github.com/go-playground/validator/v10/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Dean Karn - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/vendor/github.com/go-playground/validator/v10/MAINTAINERS.md b/vendor/github.com/go-playground/validator/v10/MAINTAINERS.md deleted file mode 100644 index b809c4c..0000000 --- a/vendor/github.com/go-playground/validator/v10/MAINTAINERS.md +++ /dev/null @@ -1,16 +0,0 @@ -## Maintainers Guide - -### Semantic Versioning -Semantic versioning as defined [here](https://semver.org) must be strictly adhered to. - -### External Dependencies -Any new external dependencies MUST: -- Have a compatible LICENSE present. -- Be actively maintained. -- Be approved by @go-playground/admins - -### PR Merge Requirements -- Up-to-date branch. -- Passing tests and linting. -- CODEOWNERS approval. -- Tests that cover both the Happy and Unhappy paths. \ No newline at end of file diff --git a/vendor/github.com/go-playground/validator/v10/Makefile b/vendor/github.com/go-playground/validator/v10/Makefile deleted file mode 100644 index ec3455b..0000000 --- a/vendor/github.com/go-playground/validator/v10/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -GOCMD=GO111MODULE=on go - -linters-install: - @golangci-lint --version >/dev/null 2>&1 || { \ - echo "installing linting tools..."; \ - curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.41.1; \ - } - -lint: linters-install - golangci-lint run - -test: - $(GOCMD) test -cover -race ./... - -bench: - $(GOCMD) test -bench=. -benchmem ./... - -.PHONY: test lint linters-install \ No newline at end of file diff --git a/vendor/github.com/go-playground/validator/v10/README.md b/vendor/github.com/go-playground/validator/v10/README.md deleted file mode 100644 index 8b730b6..0000000 --- a/vendor/github.com/go-playground/validator/v10/README.md +++ /dev/null @@ -1,338 +0,0 @@ -Package validator -================= -[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -![Project status](https://img.shields.io/badge/version-10.11.0-green.svg) -[![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) -[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master) -[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) -[![GoDoc](https://godoc.org/github.com/go-playground/validator?status.svg)](https://pkg.go.dev/github.com/go-playground/validator/v10) -![License](https://img.shields.io/dub/l/vibe-d.svg) - -Package validator implements value validations for structs and individual fields based on tags. - -It has the following **unique** features: - -- Cross Field and Cross Struct validations by using validation tags or custom validators. -- Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated. -- Ability to dive into both map keys and values for validation -- Handles type interface by determining it's underlying type prior to validation. -- Handles custom field types such as sql driver Valuer see [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29) -- Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs -- Extraction of custom defined Field Name e.g. can specify to extract the JSON name while validating and have it available in the resulting FieldError -- Customizable i18n aware error messages. -- Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/master/_examples/gin-upgrading-overriding) - -Installation ------------- - -Use go get. - - go get github.com/go-playground/validator/v10 - -Then import the validator package into your own code. - - import "github.com/go-playground/validator/v10" - -Error Return Value -------- - -Validation functions return type error - -They return type error to avoid the issue discussed in the following, where err is always != nil: - -* http://stackoverflow.com/a/29138676/3158232 -* https://github.com/go-playground/validator/issues/134 - -Validator returns only InvalidValidationError for bad validation input, nil or ValidationErrors as type error; so, in your code all you need to do is check if the error returned is not nil, and if it's not check if error is InvalidValidationError ( if necessary, most of the time it isn't ) type cast it to type ValidationErrors like so: - -```go -err := validate.Struct(mystruct) -validationErrors := err.(validator.ValidationErrors) - ``` - -Usage and documentation ------- - -Please see https://pkg.go.dev/github.com/go-playground/validator/v10 for detailed usage docs. - -##### Examples: - -- [Simple](https://github.com/go-playground/validator/blob/master/_examples/simple/main.go) -- [Custom Field Types](https://github.com/go-playground/validator/blob/master/_examples/custom/main.go) -- [Struct Level](https://github.com/go-playground/validator/blob/master/_examples/struct-level/main.go) -- [Translations & Custom Errors](https://github.com/go-playground/validator/blob/master/_examples/translations/main.go) -- [Gin upgrade and/or override validator](https://github.com/go-playground/validator/tree/v9/_examples/gin-upgrading-overriding) -- [wash - an example application putting it all together](https://github.com/bluesuncorp/wash) - -Baked-in Validations ------- - -### Fields: - -| Tag | Description | -| - | - | -| eqcsfield | Field Equals Another Field (relative)| -| eqfield | Field Equals Another Field | -| fieldcontains | NOT DOCUMENTED IN doc.go | -| fieldexcludes | NOT DOCUMENTED IN doc.go | -| gtcsfield | Field Greater Than Another Relative Field | -| gtecsfield | Field Greater Than or Equal To Another Relative Field | -| gtefield | Field Greater Than or Equal To Another Field | -| gtfield | Field Greater Than Another Field | -| ltcsfield | Less Than Another Relative Field | -| ltecsfield | Less Than or Equal To Another Relative Field | -| ltefield | Less Than or Equal To Another Field | -| ltfield | Less Than Another Field | -| necsfield | Field Does Not Equal Another Field (relative) | -| nefield | Field Does Not Equal Another Field | - -### Network: - -| Tag | Description | -| - | - | -| cidr | Classless Inter-Domain Routing CIDR | -| cidrv4 | Classless Inter-Domain Routing CIDRv4 | -| cidrv6 | Classless Inter-Domain Routing CIDRv6 | -| datauri | Data URL | -| fqdn | Full Qualified Domain Name (FQDN) | -| hostname | Hostname RFC 952 | -| hostname_port | HostPort | -| hostname_rfc1123 | Hostname RFC 1123 | -| ip | Internet Protocol Address IP | -| ip4_addr | Internet Protocol Address IPv4 | -| ip6_addr | Internet Protocol Address IPv6 | -| ip_addr | Internet Protocol Address IP | -| ipv4 | Internet Protocol Address IPv4 | -| ipv6 | Internet Protocol Address IPv6 | -| mac | Media Access Control Address MAC | -| tcp4_addr | Transmission Control Protocol Address TCPv4 | -| tcp6_addr | Transmission Control Protocol Address TCPv6 | -| tcp_addr | Transmission Control Protocol Address TCP | -| udp4_addr | User Datagram Protocol Address UDPv4 | -| udp6_addr | User Datagram Protocol Address UDPv6 | -| udp_addr | User Datagram Protocol Address UDP | -| unix_addr | Unix domain socket end point Address | -| uri | URI String | -| url | URL String | -| url_encoded | URL Encoded | -| urn_rfc2141 | Urn RFC 2141 String | - -### Strings: - -| Tag | Description | -| - | - | -| alpha | Alpha Only | -| alphanum | Alphanumeric | -| alphanumunicode | Alphanumeric Unicode | -| alphaunicode | Alpha Unicode | -| ascii | ASCII | -| boolean | Boolean | -| contains | Contains | -| containsany | Contains Any | -| containsrune | Contains Rune | -| endsnotwith | Ends Not With | -| endswith | Ends With | -| excludes | Excludes | -| excludesall | Excludes All | -| excludesrune | Excludes Rune | -| lowercase | Lowercase | -| multibyte | Multi-Byte Characters | -| number | NOT DOCUMENTED IN doc.go | -| numeric | Numeric | -| printascii | Printable ASCII | -| startsnotwith | Starts Not With | -| startswith | Starts With | -| uppercase | Uppercase | - -### Format: -| Tag | Description | -| - | - | -| base64 | Base64 String | -| base64url | Base64URL String | -| bic | Business Identifier Code (ISO 9362) | -| bcp47_language_tag | Language tag (BCP 47) | -| btc_addr | Bitcoin Address | -| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) | -| credit_card | Credit Card Number | -| datetime | Datetime | -| e164 | e164 formatted phone number | -| email | E-mail String -| eth_addr | Ethereum Address | -| hexadecimal | Hexadecimal String | -| hexcolor | Hexcolor String | -| hsl | HSL String | -| hsla | HSLA String | -| html | HTML Tags | -| html_encoded | HTML Encoded | -| isbn | International Standard Book Number | -| isbn10 | International Standard Book Number 10 | -| isbn13 | International Standard Book Number 13 | -| iso3166_1_alpha2 | Two-letter country code (ISO 3166-1 alpha-2) | -| iso3166_1_alpha3 | Three-letter country code (ISO 3166-1 alpha-3) | -| iso3166_1_alpha_numeric | Numeric country code (ISO 3166-1 numeric) | -| iso3166_2 | Country subdivision code (ISO 3166-2) | -| iso4217 | Currency code (ISO 4217) | -| json | JSON | -| jwt | JSON Web Token (JWT) | -| latitude | Latitude | -| longitude | Longitude | -| postcode_iso3166_alpha2 | Postcode | -| postcode_iso3166_alpha2_field | Postcode | -| rgb | RGB String | -| rgba | RGBA String | -| ssn | Social Security Number SSN | -| timezone | Timezone | -| uuid | Universally Unique Identifier UUID | -| uuid3 | Universally Unique Identifier UUID v3 | -| uuid3_rfc4122 | Universally Unique Identifier UUID v3 RFC4122 | -| uuid4 | Universally Unique Identifier UUID v4 | -| uuid4_rfc4122 | Universally Unique Identifier UUID v4 RFC4122 | -| uuid5 | Universally Unique Identifier UUID v5 | -| uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 | -| uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 | -| md4 | MD4 hash | -| md5 | MD5 hash | -| sha256 | SHA256 hash | -| sha384 | SHA384 hash | -| sha512 | SHA512 hash | -| ripemd128 | RIPEMD-128 hash | -| ripemd128 | RIPEMD-160 hash | -| tiger128 | TIGER128 hash | -| tiger160 | TIGER160 hash | -| tiger192 | TIGER192 hash | -| semver | Semantic Versioning 2.0.0 | -| ulid | Universally Unique Lexicographically Sortable Identifier ULID | - -### Comparisons: -| Tag | Description | -| - | - | -| eq | Equals | -| gt | Greater than| -| gte | Greater than or equal | -| lt | Less Than | -| lte | Less Than or Equal | -| ne | Not Equal | - -### Other: -| Tag | Description | -| - | - | -| dir | Directory | -| file | File path | -| isdefault | Is Default | -| len | Length | -| max | Maximum | -| min | Minimum | -| oneof | One Of | -| required | Required | -| required_if | Required If | -| required_unless | Required Unless | -| required_with | Required With | -| required_with_all | Required With All | -| required_without | Required Without | -| required_without_all | Required Without All | -| excluded_if | Excluded If | -| excluded_unless | Excluded Unless | -| excluded_with | Excluded With | -| excluded_with_all | Excluded With All | -| excluded_without | Excluded Without | -| excluded_without_all | Excluded Without All | -| unique | Unique | - -#### Aliases: -| Tag | Description | -| - | - | -| iscolor | hexcolor\|rgb\|rgba\|hsl\|hsla | -| country_code | iso3166_1_alpha2\|iso3166_1_alpha3\|iso3166_1_alpha_numeric | - -Benchmarks ------- -###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64 -```go -goos: darwin -goarch: amd64 -pkg: github.com/go-playground/validator -BenchmarkFieldSuccess-8 20000000 83.6 ns/op 0 B/op 0 allocs/op -BenchmarkFieldSuccessParallel-8 50000000 26.8 ns/op 0 B/op 0 allocs/op -BenchmarkFieldFailure-8 5000000 291 ns/op 208 B/op 4 allocs/op -BenchmarkFieldFailureParallel-8 20000000 107 ns/op 208 B/op 4 allocs/op -BenchmarkFieldArrayDiveSuccess-8 2000000 623 ns/op 201 B/op 11 allocs/op -BenchmarkFieldArrayDiveSuccessParallel-8 10000000 237 ns/op 201 B/op 11 allocs/op -BenchmarkFieldArrayDiveFailure-8 2000000 859 ns/op 412 B/op 16 allocs/op -BenchmarkFieldArrayDiveFailureParallel-8 5000000 335 ns/op 413 B/op 16 allocs/op -BenchmarkFieldMapDiveSuccess-8 1000000 1292 ns/op 432 B/op 18 allocs/op -BenchmarkFieldMapDiveSuccessParallel-8 3000000 467 ns/op 432 B/op 18 allocs/op -BenchmarkFieldMapDiveFailure-8 1000000 1082 ns/op 512 B/op 16 allocs/op -BenchmarkFieldMapDiveFailureParallel-8 5000000 425 ns/op 512 B/op 16 allocs/op -BenchmarkFieldMapDiveWithKeysSuccess-8 1000000 1539 ns/op 480 B/op 21 allocs/op -BenchmarkFieldMapDiveWithKeysSuccessParallel-8 3000000 613 ns/op 480 B/op 21 allocs/op -BenchmarkFieldMapDiveWithKeysFailure-8 1000000 1413 ns/op 721 B/op 21 allocs/op -BenchmarkFieldMapDiveWithKeysFailureParallel-8 3000000 575 ns/op 721 B/op 21 allocs/op -BenchmarkFieldCustomTypeSuccess-8 10000000 216 ns/op 32 B/op 2 allocs/op -BenchmarkFieldCustomTypeSuccessParallel-8 20000000 82.2 ns/op 32 B/op 2 allocs/op -BenchmarkFieldCustomTypeFailure-8 5000000 274 ns/op 208 B/op 4 allocs/op -BenchmarkFieldCustomTypeFailureParallel-8 20000000 116 ns/op 208 B/op 4 allocs/op -BenchmarkFieldOrTagSuccess-8 2000000 740 ns/op 16 B/op 1 allocs/op -BenchmarkFieldOrTagSuccessParallel-8 3000000 474 ns/op 16 B/op 1 allocs/op -BenchmarkFieldOrTagFailure-8 3000000 471 ns/op 224 B/op 5 allocs/op -BenchmarkFieldOrTagFailureParallel-8 3000000 414 ns/op 224 B/op 5 allocs/op -BenchmarkStructLevelValidationSuccess-8 10000000 213 ns/op 32 B/op 2 allocs/op -BenchmarkStructLevelValidationSuccessParallel-8 20000000 91.8 ns/op 32 B/op 2 allocs/op -BenchmarkStructLevelValidationFailure-8 3000000 473 ns/op 304 B/op 8 allocs/op -BenchmarkStructLevelValidationFailureParallel-8 10000000 234 ns/op 304 B/op 8 allocs/op -BenchmarkStructSimpleCustomTypeSuccess-8 5000000 385 ns/op 32 B/op 2 allocs/op -BenchmarkStructSimpleCustomTypeSuccessParallel-8 10000000 161 ns/op 32 B/op 2 allocs/op -BenchmarkStructSimpleCustomTypeFailure-8 2000000 640 ns/op 424 B/op 9 allocs/op -BenchmarkStructSimpleCustomTypeFailureParallel-8 5000000 318 ns/op 440 B/op 10 allocs/op -BenchmarkStructFilteredSuccess-8 2000000 597 ns/op 288 B/op 9 allocs/op -BenchmarkStructFilteredSuccessParallel-8 10000000 266 ns/op 288 B/op 9 allocs/op -BenchmarkStructFilteredFailure-8 3000000 454 ns/op 256 B/op 7 allocs/op -BenchmarkStructFilteredFailureParallel-8 10000000 214 ns/op 256 B/op 7 allocs/op -BenchmarkStructPartialSuccess-8 3000000 502 ns/op 256 B/op 6 allocs/op -BenchmarkStructPartialSuccessParallel-8 10000000 225 ns/op 256 B/op 6 allocs/op -BenchmarkStructPartialFailure-8 2000000 702 ns/op 480 B/op 11 allocs/op -BenchmarkStructPartialFailureParallel-8 5000000 329 ns/op 480 B/op 11 allocs/op -BenchmarkStructExceptSuccess-8 2000000 793 ns/op 496 B/op 12 allocs/op -BenchmarkStructExceptSuccessParallel-8 10000000 193 ns/op 240 B/op 5 allocs/op -BenchmarkStructExceptFailure-8 2000000 639 ns/op 464 B/op 10 allocs/op -BenchmarkStructExceptFailureParallel-8 5000000 300 ns/op 464 B/op 10 allocs/op -BenchmarkStructSimpleCrossFieldSuccess-8 3000000 417 ns/op 72 B/op 3 allocs/op -BenchmarkStructSimpleCrossFieldSuccessParallel-8 10000000 163 ns/op 72 B/op 3 allocs/op -BenchmarkStructSimpleCrossFieldFailure-8 2000000 645 ns/op 304 B/op 8 allocs/op -BenchmarkStructSimpleCrossFieldFailureParallel-8 5000000 285 ns/op 304 B/op 8 allocs/op -BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 3000000 588 ns/op 80 B/op 4 allocs/op -BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 221 ns/op 80 B/op 4 allocs/op -BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2000000 868 ns/op 320 B/op 9 allocs/op -BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 337 ns/op 320 B/op 9 allocs/op -BenchmarkStructSimpleSuccess-8 5000000 260 ns/op 0 B/op 0 allocs/op -BenchmarkStructSimpleSuccessParallel-8 20000000 90.6 ns/op 0 B/op 0 allocs/op -BenchmarkStructSimpleFailure-8 2000000 619 ns/op 424 B/op 9 allocs/op -BenchmarkStructSimpleFailureParallel-8 5000000 296 ns/op 424 B/op 9 allocs/op -BenchmarkStructComplexSuccess-8 1000000 1454 ns/op 128 B/op 8 allocs/op -BenchmarkStructComplexSuccessParallel-8 3000000 579 ns/op 128 B/op 8 allocs/op -BenchmarkStructComplexFailure-8 300000 4140 ns/op 3041 B/op 53 allocs/op -BenchmarkStructComplexFailureParallel-8 1000000 2127 ns/op 3041 B/op 53 allocs/op -BenchmarkOneof-8 10000000 140 ns/op 0 B/op 0 allocs/op -BenchmarkOneofParallel-8 20000000 70.1 ns/op 0 B/op 0 allocs/op -``` - -Complementary Software ----------------------- - -Here is a list of software that complements using this library either pre or post validation. - -* [form](https://github.com/go-playground/form) - Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support. -* [mold](https://github.com/go-playground/mold) - A general library to help modify or set data within data structures and other objects - -How to Contribute ------- - -Make a pull request... - -License -------- -Distributed under MIT License, please see license file within the code for more details. - -Maintainers ------------ -This project has grown large enough that more than one person is required to properly support the community. -If you are interested in becoming a maintainer please reach out to me https://github.com/deankarn diff --git a/vendor/github.com/go-playground/validator/v10/baked_in.go b/vendor/github.com/go-playground/validator/v10/baked_in.go deleted file mode 100644 index f2f0939..0000000 --- a/vendor/github.com/go-playground/validator/v10/baked_in.go +++ /dev/null @@ -1,2521 +0,0 @@ -package validator - -import ( - "bytes" - "context" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "fmt" - "net" - "net/url" - "os" - "reflect" - "strconv" - "strings" - "sync" - "time" - "unicode/utf8" - - "golang.org/x/crypto/sha3" - "golang.org/x/text/language" - - urn "github.com/leodido/go-urn" -) - -// Func accepts a FieldLevel interface for all validation needs. The return -// value should be true when validation succeeds. -type Func func(fl FieldLevel) bool - -// FuncCtx accepts a context.Context and FieldLevel interface for all -// validation needs. The return value should be true when validation succeeds. -type FuncCtx func(ctx context.Context, fl FieldLevel) bool - -// wrapFunc wraps noramal Func makes it compatible with FuncCtx -func wrapFunc(fn Func) FuncCtx { - if fn == nil { - return nil // be sure not to wrap a bad function. - } - return func(ctx context.Context, fl FieldLevel) bool { - return fn(fl) - } -} - -var ( - restrictedTags = map[string]struct{}{ - diveTag: {}, - keysTag: {}, - endKeysTag: {}, - structOnlyTag: {}, - omitempty: {}, - skipValidationTag: {}, - utf8HexComma: {}, - utf8Pipe: {}, - noStructLevelTag: {}, - requiredTag: {}, - isdefault: {}, - } - - // bakedInAliases is a default mapping of a single validation tag that - // defines a common or complex set of validation(s) to simplify - // adding validation to structs. - bakedInAliases = map[string]string{ - "iscolor": "hexcolor|rgb|rgba|hsl|hsla", - "country_code": "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric", - } - - // bakedInValidators is the default map of ValidationFunc - // you can add, remove or even replace items to suite your needs, - // or even disregard and use your own map if so desired. - bakedInValidators = map[string]Func{ - "required": hasValue, - "required_if": requiredIf, - "required_unless": requiredUnless, - "required_with": requiredWith, - "required_with_all": requiredWithAll, - "required_without": requiredWithout, - "required_without_all": requiredWithoutAll, - "excluded_if": excludedIf, - "excluded_unless": excludedUnless, - "excluded_with": excludedWith, - "excluded_with_all": excludedWithAll, - "excluded_without": excludedWithout, - "excluded_without_all": excludedWithoutAll, - "isdefault": isDefault, - "len": hasLengthOf, - "min": hasMinOf, - "max": hasMaxOf, - "eq": isEq, - "ne": isNe, - "lt": isLt, - "lte": isLte, - "gt": isGt, - "gte": isGte, - "eqfield": isEqField, - "eqcsfield": isEqCrossStructField, - "necsfield": isNeCrossStructField, - "gtcsfield": isGtCrossStructField, - "gtecsfield": isGteCrossStructField, - "ltcsfield": isLtCrossStructField, - "ltecsfield": isLteCrossStructField, - "nefield": isNeField, - "gtefield": isGteField, - "gtfield": isGtField, - "ltefield": isLteField, - "ltfield": isLtField, - "fieldcontains": fieldContains, - "fieldexcludes": fieldExcludes, - "alpha": isAlpha, - "alphanum": isAlphanum, - "alphaunicode": isAlphaUnicode, - "alphanumunicode": isAlphanumUnicode, - "boolean": isBoolean, - "numeric": isNumeric, - "number": isNumber, - "hexadecimal": isHexadecimal, - "hexcolor": isHEXColor, - "rgb": isRGB, - "rgba": isRGBA, - "hsl": isHSL, - "hsla": isHSLA, - "e164": isE164, - "email": isEmail, - "url": isURL, - "uri": isURI, - "urn_rfc2141": isUrnRFC2141, // RFC 2141 - "file": isFile, - "base64": isBase64, - "base64url": isBase64URL, - "contains": contains, - "containsany": containsAny, - "containsrune": containsRune, - "excludes": excludes, - "excludesall": excludesAll, - "excludesrune": excludesRune, - "startswith": startsWith, - "endswith": endsWith, - "startsnotwith": startsNotWith, - "endsnotwith": endsNotWith, - "isbn": isISBN, - "isbn10": isISBN10, - "isbn13": isISBN13, - "eth_addr": isEthereumAddress, - "btc_addr": isBitcoinAddress, - "btc_addr_bech32": isBitcoinBech32Address, - "uuid": isUUID, - "uuid3": isUUID3, - "uuid4": isUUID4, - "uuid5": isUUID5, - "uuid_rfc4122": isUUIDRFC4122, - "uuid3_rfc4122": isUUID3RFC4122, - "uuid4_rfc4122": isUUID4RFC4122, - "uuid5_rfc4122": isUUID5RFC4122, - "ulid": isULID, - "md4": isMD4, - "md5": isMD5, - "sha256": isSHA256, - "sha384": isSHA384, - "sha512": isSHA512, - "ripemd128": isRIPEMD128, - "ripemd160": isRIPEMD160, - "tiger128": isTIGER128, - "tiger160": isTIGER160, - "tiger192": isTIGER192, - "ascii": isASCII, - "printascii": isPrintableASCII, - "multibyte": hasMultiByteCharacter, - "datauri": isDataURI, - "latitude": isLatitude, - "longitude": isLongitude, - "ssn": isSSN, - "ipv4": isIPv4, - "ipv6": isIPv6, - "ip": isIP, - "cidrv4": isCIDRv4, - "cidrv6": isCIDRv6, - "cidr": isCIDR, - "tcp4_addr": isTCP4AddrResolvable, - "tcp6_addr": isTCP6AddrResolvable, - "tcp_addr": isTCPAddrResolvable, - "udp4_addr": isUDP4AddrResolvable, - "udp6_addr": isUDP6AddrResolvable, - "udp_addr": isUDPAddrResolvable, - "ip4_addr": isIP4AddrResolvable, - "ip6_addr": isIP6AddrResolvable, - "ip_addr": isIPAddrResolvable, - "unix_addr": isUnixAddrResolvable, - "mac": isMAC, - "hostname": isHostnameRFC952, // RFC 952 - "hostname_rfc1123": isHostnameRFC1123, // RFC 1123 - "fqdn": isFQDN, - "unique": isUnique, - "oneof": isOneOf, - "html": isHTML, - "html_encoded": isHTMLEncoded, - "url_encoded": isURLEncoded, - "dir": isDir, - "json": isJSON, - "jwt": isJWT, - "hostname_port": isHostnamePort, - "lowercase": isLowercase, - "uppercase": isUppercase, - "datetime": isDatetime, - "timezone": isTimeZone, - "iso3166_1_alpha2": isIso3166Alpha2, - "iso3166_1_alpha3": isIso3166Alpha3, - "iso3166_1_alpha_numeric": isIso3166AlphaNumeric, - "iso3166_2": isIso31662, - "iso4217": isIso4217, - "iso4217_numeric": isIso4217Numeric, - "bcp47_language_tag": isBCP47LanguageTag, - "postcode_iso3166_alpha2": isPostcodeByIso3166Alpha2, - "postcode_iso3166_alpha2_field": isPostcodeByIso3166Alpha2Field, - "bic": isIsoBicFormat, - "semver": isSemverFormat, - "dns_rfc1035_label": isDnsRFC1035LabelFormat, - "credit_card": isCreditCard, - } -) - -var ( - oneofValsCache = map[string][]string{} - oneofValsCacheRWLock = sync.RWMutex{} -) - -func parseOneOfParam2(s string) []string { - oneofValsCacheRWLock.RLock() - vals, ok := oneofValsCache[s] - oneofValsCacheRWLock.RUnlock() - if !ok { - oneofValsCacheRWLock.Lock() - vals = splitParamsRegex.FindAllString(s, -1) - for i := 0; i < len(vals); i++ { - vals[i] = strings.Replace(vals[i], "'", "", -1) - } - oneofValsCache[s] = vals - oneofValsCacheRWLock.Unlock() - } - return vals -} - -func isURLEncoded(fl FieldLevel) bool { - return uRLEncodedRegex.MatchString(fl.Field().String()) -} - -func isHTMLEncoded(fl FieldLevel) bool { - return hTMLEncodedRegex.MatchString(fl.Field().String()) -} - -func isHTML(fl FieldLevel) bool { - return hTMLRegex.MatchString(fl.Field().String()) -} - -func isOneOf(fl FieldLevel) bool { - vals := parseOneOfParam2(fl.Param()) - - field := fl.Field() - - var v string - switch field.Kind() { - case reflect.String: - v = field.String() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - v = strconv.FormatInt(field.Int(), 10) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - v = strconv.FormatUint(field.Uint(), 10) - default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) - } - for i := 0; i < len(vals); i++ { - if vals[i] == v { - return true - } - } - return false -} - -// isUnique is the validation function for validating if each array|slice|map value is unique -func isUnique(fl FieldLevel) bool { - field := fl.Field() - param := fl.Param() - v := reflect.ValueOf(struct{}{}) - - switch field.Kind() { - case reflect.Slice, reflect.Array: - elem := field.Type().Elem() - if elem.Kind() == reflect.Ptr { - elem = elem.Elem() - } - - if param == "" { - m := reflect.MakeMap(reflect.MapOf(elem, v.Type())) - - for i := 0; i < field.Len(); i++ { - m.SetMapIndex(reflect.Indirect(field.Index(i)), v) - } - return field.Len() == m.Len() - } - - sf, ok := elem.FieldByName(param) - if !ok { - panic(fmt.Sprintf("Bad field name %s", param)) - } - - sfTyp := sf.Type - if sfTyp.Kind() == reflect.Ptr { - sfTyp = sfTyp.Elem() - } - - m := reflect.MakeMap(reflect.MapOf(sfTyp, v.Type())) - for i := 0; i < field.Len(); i++ { - m.SetMapIndex(reflect.Indirect(reflect.Indirect(field.Index(i)).FieldByName(param)), v) - } - return field.Len() == m.Len() - case reflect.Map: - m := reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type())) - - for _, k := range field.MapKeys() { - m.SetMapIndex(field.MapIndex(k), v) - } - return field.Len() == m.Len() - default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) - } -} - -// isMAC is the validation function for validating if the field's value is a valid MAC address. -func isMAC(fl FieldLevel) bool { - _, err := net.ParseMAC(fl.Field().String()) - - return err == nil -} - -// isCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address. -func isCIDRv4(fl FieldLevel) bool { - ip, _, err := net.ParseCIDR(fl.Field().String()) - - return err == nil && ip.To4() != nil -} - -// isCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address. -func isCIDRv6(fl FieldLevel) bool { - ip, _, err := net.ParseCIDR(fl.Field().String()) - - return err == nil && ip.To4() == nil -} - -// isCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address. -func isCIDR(fl FieldLevel) bool { - _, _, err := net.ParseCIDR(fl.Field().String()) - - return err == nil -} - -// isIPv4 is the validation function for validating if a value is a valid v4 IP address. -func isIPv4(fl FieldLevel) bool { - ip := net.ParseIP(fl.Field().String()) - - return ip != nil && ip.To4() != nil -} - -// isIPv6 is the validation function for validating if the field's value is a valid v6 IP address. -func isIPv6(fl FieldLevel) bool { - ip := net.ParseIP(fl.Field().String()) - - return ip != nil && ip.To4() == nil -} - -// isIP is the validation function for validating if the field's value is a valid v4 or v6 IP address. -func isIP(fl FieldLevel) bool { - ip := net.ParseIP(fl.Field().String()) - - return ip != nil -} - -// isSSN is the validation function for validating if the field's value is a valid SSN. -func isSSN(fl FieldLevel) bool { - field := fl.Field() - - if field.Len() != 11 { - return false - } - - return sSNRegex.MatchString(field.String()) -} - -// isLongitude is the validation function for validating if the field's value is a valid longitude coordinate. -func isLongitude(fl FieldLevel) bool { - field := fl.Field() - - var v string - switch field.Kind() { - case reflect.String: - v = field.String() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - v = strconv.FormatInt(field.Int(), 10) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - v = strconv.FormatUint(field.Uint(), 10) - case reflect.Float32: - v = strconv.FormatFloat(field.Float(), 'f', -1, 32) - case reflect.Float64: - v = strconv.FormatFloat(field.Float(), 'f', -1, 64) - default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) - } - - return longitudeRegex.MatchString(v) -} - -// isLatitude is the validation function for validating if the field's value is a valid latitude coordinate. -func isLatitude(fl FieldLevel) bool { - field := fl.Field() - - var v string - switch field.Kind() { - case reflect.String: - v = field.String() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - v = strconv.FormatInt(field.Int(), 10) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - v = strconv.FormatUint(field.Uint(), 10) - case reflect.Float32: - v = strconv.FormatFloat(field.Float(), 'f', -1, 32) - case reflect.Float64: - v = strconv.FormatFloat(field.Float(), 'f', -1, 64) - default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) - } - - return latitudeRegex.MatchString(v) -} - -// isDataURI is the validation function for validating if the field's value is a valid data URI. -func isDataURI(fl FieldLevel) bool { - uri := strings.SplitN(fl.Field().String(), ",", 2) - - if len(uri) != 2 { - return false - } - - if !dataURIRegex.MatchString(uri[0]) { - return false - } - - return base64Regex.MatchString(uri[1]) -} - -// hasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character. -func hasMultiByteCharacter(fl FieldLevel) bool { - field := fl.Field() - - if field.Len() == 0 { - return true - } - - return multibyteRegex.MatchString(field.String()) -} - -// isPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character. -func isPrintableASCII(fl FieldLevel) bool { - return printableASCIIRegex.MatchString(fl.Field().String()) -} - -// isASCII is the validation function for validating if the field's value is a valid ASCII character. -func isASCII(fl FieldLevel) bool { - return aSCIIRegex.MatchString(fl.Field().String()) -} - -// isUUID5 is the validation function for validating if the field's value is a valid v5 UUID. -func isUUID5(fl FieldLevel) bool { - return uUID5Regex.MatchString(fl.Field().String()) -} - -// isUUID4 is the validation function for validating if the field's value is a valid v4 UUID. -func isUUID4(fl FieldLevel) bool { - return uUID4Regex.MatchString(fl.Field().String()) -} - -// isUUID3 is the validation function for validating if the field's value is a valid v3 UUID. -func isUUID3(fl FieldLevel) bool { - return uUID3Regex.MatchString(fl.Field().String()) -} - -// isUUID is the validation function for validating if the field's value is a valid UUID of any version. -func isUUID(fl FieldLevel) bool { - return uUIDRegex.MatchString(fl.Field().String()) -} - -// isUUID5RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v5 UUID. -func isUUID5RFC4122(fl FieldLevel) bool { - return uUID5RFC4122Regex.MatchString(fl.Field().String()) -} - -// isUUID4RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v4 UUID. -func isUUID4RFC4122(fl FieldLevel) bool { - return uUID4RFC4122Regex.MatchString(fl.Field().String()) -} - -// isUUID3RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v3 UUID. -func isUUID3RFC4122(fl FieldLevel) bool { - return uUID3RFC4122Regex.MatchString(fl.Field().String()) -} - -// isUUIDRFC4122 is the validation function for validating if the field's value is a valid RFC4122 UUID of any version. -func isUUIDRFC4122(fl FieldLevel) bool { - return uUIDRFC4122Regex.MatchString(fl.Field().String()) -} - -// isULID is the validation function for validating if the field's value is a valid ULID. -func isULID(fl FieldLevel) bool { - return uLIDRegex.MatchString(fl.Field().String()) -} - -// isMD4 is the validation function for validating if the field's value is a valid MD4. -func isMD4(fl FieldLevel) bool { - return md4Regex.MatchString(fl.Field().String()) -} - -// isMD5 is the validation function for validating if the field's value is a valid MD5. -func isMD5(fl FieldLevel) bool { - return md5Regex.MatchString(fl.Field().String()) -} - -// isSHA256 is the validation function for validating if the field's value is a valid SHA256. -func isSHA256(fl FieldLevel) bool { - return sha256Regex.MatchString(fl.Field().String()) -} - -// isSHA384 is the validation function for validating if the field's value is a valid SHA384. -func isSHA384(fl FieldLevel) bool { - return sha384Regex.MatchString(fl.Field().String()) -} - -// isSHA512 is the validation function for validating if the field's value is a valid SHA512. -func isSHA512(fl FieldLevel) bool { - return sha512Regex.MatchString(fl.Field().String()) -} - -// isRIPEMD128 is the validation function for validating if the field's value is a valid PIPEMD128. -func isRIPEMD128(fl FieldLevel) bool { - return ripemd128Regex.MatchString(fl.Field().String()) -} - -// isRIPEMD160 is the validation function for validating if the field's value is a valid PIPEMD160. -func isRIPEMD160(fl FieldLevel) bool { - return ripemd160Regex.MatchString(fl.Field().String()) -} - -// isTIGER128 is the validation function for validating if the field's value is a valid TIGER128. -func isTIGER128(fl FieldLevel) bool { - return tiger128Regex.MatchString(fl.Field().String()) -} - -// isTIGER160 is the validation function for validating if the field's value is a valid TIGER160. -func isTIGER160(fl FieldLevel) bool { - return tiger160Regex.MatchString(fl.Field().String()) -} - -// isTIGER192 is the validation function for validating if the field's value is a valid isTIGER192. -func isTIGER192(fl FieldLevel) bool { - return tiger192Regex.MatchString(fl.Field().String()) -} - -// isISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN. -func isISBN(fl FieldLevel) bool { - return isISBN10(fl) || isISBN13(fl) -} - -// isISBN13 is the validation function for validating if the field's value is a valid v13 ISBN. -func isISBN13(fl FieldLevel) bool { - s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4) - - if !iSBN13Regex.MatchString(s) { - return false - } - - var checksum int32 - var i int32 - - factor := []int32{1, 3} - - for i = 0; i < 12; i++ { - checksum += factor[i%2] * int32(s[i]-'0') - } - - return (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0 -} - -// isISBN10 is the validation function for validating if the field's value is a valid v10 ISBN. -func isISBN10(fl FieldLevel) bool { - s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3) - - if !iSBN10Regex.MatchString(s) { - return false - } - - var checksum int32 - var i int32 - - for i = 0; i < 9; i++ { - checksum += (i + 1) * int32(s[i]-'0') - } - - if s[9] == 'X' { - checksum += 10 * 10 - } else { - checksum += 10 * int32(s[9]-'0') - } - - return checksum%11 == 0 -} - -// isEthereumAddress is the validation function for validating if the field's value is a valid Ethereum address. -func isEthereumAddress(fl FieldLevel) bool { - address := fl.Field().String() - - if !ethAddressRegex.MatchString(address) { - return false - } - - if ethAddressRegexUpper.MatchString(address) || ethAddressRegexLower.MatchString(address) { - return true - } - - // Checksum validation. Reference: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md - address = address[2:] // Skip "0x" prefix. - h := sha3.NewLegacyKeccak256() - // hash.Hash's io.Writer implementation says it never returns an error. https://golang.org/pkg/hash/#Hash - _, _ = h.Write([]byte(strings.ToLower(address))) - hash := hex.EncodeToString(h.Sum(nil)) - - for i := 0; i < len(address); i++ { - if address[i] <= '9' { // Skip 0-9 digits: they don't have upper/lower-case. - continue - } - if hash[i] > '7' && address[i] >= 'a' || hash[i] <= '7' && address[i] <= 'F' { - return false - } - } - - return true -} - -// isBitcoinAddress is the validation function for validating if the field's value is a valid btc address -func isBitcoinAddress(fl FieldLevel) bool { - address := fl.Field().String() - - if !btcAddressRegex.MatchString(address) { - return false - } - - alphabet := []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") - - decode := [25]byte{} - - for _, n := range []byte(address) { - d := bytes.IndexByte(alphabet, n) - - for i := 24; i >= 0; i-- { - d += 58 * int(decode[i]) - decode[i] = byte(d % 256) - d /= 256 - } - } - - h := sha256.New() - _, _ = h.Write(decode[:21]) - d := h.Sum([]byte{}) - h = sha256.New() - _, _ = h.Write(d) - - validchecksum := [4]byte{} - computedchecksum := [4]byte{} - - copy(computedchecksum[:], h.Sum(d[:0])) - copy(validchecksum[:], decode[21:]) - - return validchecksum == computedchecksum -} - -// isBitcoinBech32Address is the validation function for validating if the field's value is a valid bech32 btc address -func isBitcoinBech32Address(fl FieldLevel) bool { - address := fl.Field().String() - - if !btcLowerAddressRegexBech32.MatchString(address) && !btcUpperAddressRegexBech32.MatchString(address) { - return false - } - - am := len(address) % 8 - - if am == 0 || am == 3 || am == 5 { - return false - } - - address = strings.ToLower(address) - - alphabet := "qpzry9x8gf2tvdw0s3jn54khce6mua7l" - - hr := []int{3, 3, 0, 2, 3} // the human readable part will always be bc - addr := address[3:] - dp := make([]int, 0, len(addr)) - - for _, c := range addr { - dp = append(dp, strings.IndexRune(alphabet, c)) - } - - ver := dp[0] - - if ver < 0 || ver > 16 { - return false - } - - if ver == 0 { - if len(address) != 42 && len(address) != 62 { - return false - } - } - - values := append(hr, dp...) - - GEN := []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3} - - p := 1 - - for _, v := range values { - b := p >> 25 - p = (p&0x1ffffff)<<5 ^ v - - for i := 0; i < 5; i++ { - if (b>>uint(i))&1 == 1 { - p ^= GEN[i] - } - } - } - - if p != 1 { - return false - } - - b := uint(0) - acc := 0 - mv := (1 << 5) - 1 - var sw []int - - for _, v := range dp[1 : len(dp)-6] { - acc = (acc << 5) | v - b += 5 - for b >= 8 { - b -= 8 - sw = append(sw, (acc>>b)&mv) - } - } - - if len(sw) < 2 || len(sw) > 40 { - return false - } - - return true -} - -// excludesRune is the validation function for validating that the field's value does not contain the rune specified within the param. -func excludesRune(fl FieldLevel) bool { - return !containsRune(fl) -} - -// excludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param. -func excludesAll(fl FieldLevel) bool { - return !containsAny(fl) -} - -// excludes is the validation function for validating that the field's value does not contain the text specified within the param. -func excludes(fl FieldLevel) bool { - return !contains(fl) -} - -// containsRune is the validation function for validating that the field's value contains the rune specified within the param. -func containsRune(fl FieldLevel) bool { - r, _ := utf8.DecodeRuneInString(fl.Param()) - - return strings.ContainsRune(fl.Field().String(), r) -} - -// containsAny is the validation function for validating that the field's value contains any of the characters specified within the param. -func containsAny(fl FieldLevel) bool { - return strings.ContainsAny(fl.Field().String(), fl.Param()) -} - -// contains is the validation function for validating that the field's value contains the text specified within the param. -func contains(fl FieldLevel) bool { - return strings.Contains(fl.Field().String(), fl.Param()) -} - -// startsWith is the validation function for validating that the field's value starts with the text specified within the param. -func startsWith(fl FieldLevel) bool { - return strings.HasPrefix(fl.Field().String(), fl.Param()) -} - -// endsWith is the validation function for validating that the field's value ends with the text specified within the param. -func endsWith(fl FieldLevel) bool { - return strings.HasSuffix(fl.Field().String(), fl.Param()) -} - -// startsNotWith is the validation function for validating that the field's value does not start with the text specified within the param. -func startsNotWith(fl FieldLevel) bool { - return !startsWith(fl) -} - -// endsNotWith is the validation function for validating that the field's value does not end with the text specified within the param. -func endsNotWith(fl FieldLevel) bool { - return !endsWith(fl) -} - -// fieldContains is the validation function for validating if the current field's value contains the field specified by the param's value. -func fieldContains(fl FieldLevel) bool { - field := fl.Field() - - currentField, _, ok := fl.GetStructFieldOK() - - if !ok { - return false - } - - return strings.Contains(field.String(), currentField.String()) -} - -// fieldExcludes is the validation function for validating if the current field's value excludes the field specified by the param's value. -func fieldExcludes(fl FieldLevel) bool { - field := fl.Field() - - currentField, _, ok := fl.GetStructFieldOK() - if !ok { - return true - } - - return !strings.Contains(field.String(), currentField.String()) -} - -// isNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value. -func isNeField(fl FieldLevel) bool { - field := fl.Field() - kind := field.Kind() - - currentField, currentKind, ok := fl.GetStructFieldOK() - - if !ok || currentKind != kind { - return true - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() != currentField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() != currentField.Uint() - - case reflect.Float32, reflect.Float64: - return field.Float() != currentField.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) != int64(currentField.Len()) - - case reflect.Bool: - return field.Bool() != currentField.Bool() - - case reflect.Struct: - - fieldType := field.Type() - - if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { - - t := currentField.Interface().(time.Time) - fieldTime := field.Interface().(time.Time) - - return !fieldTime.Equal(t) - } - - // Not Same underlying type i.e. struct and time - if fieldType != currentField.Type() { - return true - } - } - - // default reflect.String: - return field.String() != currentField.String() -} - -// isNe is the validation function for validating that the field's value does not equal the provided param value. -func isNe(fl FieldLevel) bool { - return !isEq(fl) -} - -// isLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value. -func isLteCrossStructField(fl FieldLevel) bool { - field := fl.Field() - kind := field.Kind() - - topField, topKind, ok := fl.GetStructFieldOK() - if !ok || topKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() <= topField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() <= topField.Uint() - - case reflect.Float32, reflect.Float64: - return field.Float() <= topField.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) <= int64(topField.Len()) - - case reflect.Struct: - - fieldType := field.Type() - - if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { - - fieldTime := field.Convert(timeType).Interface().(time.Time) - topTime := topField.Convert(timeType).Interface().(time.Time) - - return fieldTime.Before(topTime) || fieldTime.Equal(topTime) - } - - // Not Same underlying type i.e. struct and time - if fieldType != topField.Type() { - return false - } - } - - // default reflect.String: - return field.String() <= topField.String() -} - -// isLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func isLtCrossStructField(fl FieldLevel) bool { - field := fl.Field() - kind := field.Kind() - - topField, topKind, ok := fl.GetStructFieldOK() - if !ok || topKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() < topField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() < topField.Uint() - - case reflect.Float32, reflect.Float64: - return field.Float() < topField.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) < int64(topField.Len()) - - case reflect.Struct: - - fieldType := field.Type() - - if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { - - fieldTime := field.Convert(timeType).Interface().(time.Time) - topTime := topField.Convert(timeType).Interface().(time.Time) - - return fieldTime.Before(topTime) - } - - // Not Same underlying type i.e. struct and time - if fieldType != topField.Type() { - return false - } - } - - // default reflect.String: - return field.String() < topField.String() -} - -// isGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value. -func isGteCrossStructField(fl FieldLevel) bool { - field := fl.Field() - kind := field.Kind() - - topField, topKind, ok := fl.GetStructFieldOK() - if !ok || topKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() >= topField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() >= topField.Uint() - - case reflect.Float32, reflect.Float64: - return field.Float() >= topField.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) >= int64(topField.Len()) - - case reflect.Struct: - - fieldType := field.Type() - - if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { - - fieldTime := field.Convert(timeType).Interface().(time.Time) - topTime := topField.Convert(timeType).Interface().(time.Time) - - return fieldTime.After(topTime) || fieldTime.Equal(topTime) - } - - // Not Same underlying type i.e. struct and time - if fieldType != topField.Type() { - return false - } - } - - // default reflect.String: - return field.String() >= topField.String() -} - -// isGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value. -func isGtCrossStructField(fl FieldLevel) bool { - field := fl.Field() - kind := field.Kind() - - topField, topKind, ok := fl.GetStructFieldOK() - if !ok || topKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() > topField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() > topField.Uint() - - case reflect.Float32, reflect.Float64: - return field.Float() > topField.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) > int64(topField.Len()) - - case reflect.Struct: - - fieldType := field.Type() - - if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { - - fieldTime := field.Convert(timeType).Interface().(time.Time) - topTime := topField.Convert(timeType).Interface().(time.Time) - - return fieldTime.After(topTime) - } - - // Not Same underlying type i.e. struct and time - if fieldType != topField.Type() { - return false - } - } - - // default reflect.String: - return field.String() > topField.String() -} - -// isNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value. -func isNeCrossStructField(fl FieldLevel) bool { - field := fl.Field() - kind := field.Kind() - - topField, currentKind, ok := fl.GetStructFieldOK() - if !ok || currentKind != kind { - return true - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return topField.Int() != field.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return topField.Uint() != field.Uint() - - case reflect.Float32, reflect.Float64: - return topField.Float() != field.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(topField.Len()) != int64(field.Len()) - - case reflect.Bool: - return topField.Bool() != field.Bool() - - case reflect.Struct: - - fieldType := field.Type() - - if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { - - t := field.Convert(timeType).Interface().(time.Time) - fieldTime := topField.Convert(timeType).Interface().(time.Time) - - return !fieldTime.Equal(t) - } - - // Not Same underlying type i.e. struct and time - if fieldType != topField.Type() { - return true - } - } - - // default reflect.String: - return topField.String() != field.String() -} - -// isEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value. -func isEqCrossStructField(fl FieldLevel) bool { - field := fl.Field() - kind := field.Kind() - - topField, topKind, ok := fl.GetStructFieldOK() - if !ok || topKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return topField.Int() == field.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return topField.Uint() == field.Uint() - - case reflect.Float32, reflect.Float64: - return topField.Float() == field.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(topField.Len()) == int64(field.Len()) - - case reflect.Bool: - return topField.Bool() == field.Bool() - - case reflect.Struct: - - fieldType := field.Type() - - if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { - - t := field.Convert(timeType).Interface().(time.Time) - fieldTime := topField.Convert(timeType).Interface().(time.Time) - - return fieldTime.Equal(t) - } - - // Not Same underlying type i.e. struct and time - if fieldType != topField.Type() { - return false - } - } - - // default reflect.String: - return topField.String() == field.String() -} - -// isEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value. -func isEqField(fl FieldLevel) bool { - field := fl.Field() - kind := field.Kind() - - currentField, currentKind, ok := fl.GetStructFieldOK() - if !ok || currentKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() == currentField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() == currentField.Uint() - - case reflect.Float32, reflect.Float64: - return field.Float() == currentField.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) == int64(currentField.Len()) - - case reflect.Bool: - return field.Bool() == currentField.Bool() - - case reflect.Struct: - - fieldType := field.Type() - - if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { - - t := currentField.Convert(timeType).Interface().(time.Time) - fieldTime := field.Convert(timeType).Interface().(time.Time) - - return fieldTime.Equal(t) - } - - // Not Same underlying type i.e. struct and time - if fieldType != currentField.Type() { - return false - } - } - - // default reflect.String: - return field.String() == currentField.String() -} - -// isEq is the validation function for validating if the current field's value is equal to the param's value. -func isEq(fl FieldLevel) bool { - field := fl.Field() - param := fl.Param() - - switch field.Kind() { - - case reflect.String: - return field.String() == param - - case reflect.Slice, reflect.Map, reflect.Array: - p := asInt(param) - - return int64(field.Len()) == p - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asIntFromType(field.Type(), param) - - return field.Int() == p - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p := asUint(param) - - return field.Uint() == p - - case reflect.Float32, reflect.Float64: - p := asFloat(param) - - return field.Float() == p - - case reflect.Bool: - p := asBool(param) - - return field.Bool() == p - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isPostcodeByIso3166Alpha2 validates by value which is country code in iso 3166 alpha 2 -// example: `postcode_iso3166_alpha2=US` -func isPostcodeByIso3166Alpha2(fl FieldLevel) bool { - field := fl.Field() - param := fl.Param() - - reg, found := postCodeRegexDict[param] - if !found { - return false - } - - return reg.MatchString(field.String()) -} - -// isPostcodeByIso3166Alpha2Field validates by field which represents for a value of country code in iso 3166 alpha 2 -// example: `postcode_iso3166_alpha2_field=CountryCode` -func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool { - field := fl.Field() - params := parseOneOfParam2(fl.Param()) - - if len(params) != 1 { - return false - } - - currentField, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), params[0]) - if !found { - return false - } - - if kind != reflect.String { - panic(fmt.Sprintf("Bad field type %T", currentField.Interface())) - } - - reg, found := postCodeRegexDict[currentField.String()] - if !found { - return false - } - - return reg.MatchString(field.String()) -} - -// isBase64 is the validation function for validating if the current field's value is a valid base 64. -func isBase64(fl FieldLevel) bool { - return base64Regex.MatchString(fl.Field().String()) -} - -// isBase64URL is the validation function for validating if the current field's value is a valid base64 URL safe string. -func isBase64URL(fl FieldLevel) bool { - return base64URLRegex.MatchString(fl.Field().String()) -} - -// isURI is the validation function for validating if the current field's value is a valid URI. -func isURI(fl FieldLevel) bool { - field := fl.Field() - - switch field.Kind() { - case reflect.String: - - s := field.String() - - // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195 - // emulate browser and strip the '#' suffix prior to validation. see issue-#237 - if i := strings.Index(s, "#"); i > -1 { - s = s[:i] - } - - if len(s) == 0 { - return false - } - - _, err := url.ParseRequestURI(s) - - return err == nil - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isURL is the validation function for validating if the current field's value is a valid URL. -func isURL(fl FieldLevel) bool { - field := fl.Field() - - switch field.Kind() { - case reflect.String: - - var i int - s := field.String() - - // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195 - // emulate browser and strip the '#' suffix prior to validation. see issue-#237 - if i = strings.Index(s, "#"); i > -1 { - s = s[:i] - } - - if len(s) == 0 { - return false - } - - url, err := url.ParseRequestURI(s) - - if err != nil || url.Scheme == "" { - return false - } - - return true - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isUrnRFC2141 is the validation function for validating if the current field's value is a valid URN as per RFC 2141. -func isUrnRFC2141(fl FieldLevel) bool { - field := fl.Field() - - switch field.Kind() { - case reflect.String: - - str := field.String() - - _, match := urn.Parse([]byte(str)) - - return match - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isFile is the validation function for validating if the current field's value is a valid file path. -func isFile(fl FieldLevel) bool { - field := fl.Field() - - switch field.Kind() { - case reflect.String: - fileInfo, err := os.Stat(field.String()) - if err != nil { - return false - } - - return !fileInfo.IsDir() - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isE164 is the validation function for validating if the current field's value is a valid e.164 formatted phone number. -func isE164(fl FieldLevel) bool { - return e164Regex.MatchString(fl.Field().String()) -} - -// isEmail is the validation function for validating if the current field's value is a valid email address. -func isEmail(fl FieldLevel) bool { - return emailRegex.MatchString(fl.Field().String()) -} - -// isHSLA is the validation function for validating if the current field's value is a valid HSLA color. -func isHSLA(fl FieldLevel) bool { - return hslaRegex.MatchString(fl.Field().String()) -} - -// isHSL is the validation function for validating if the current field's value is a valid HSL color. -func isHSL(fl FieldLevel) bool { - return hslRegex.MatchString(fl.Field().String()) -} - -// isRGBA is the validation function for validating if the current field's value is a valid RGBA color. -func isRGBA(fl FieldLevel) bool { - return rgbaRegex.MatchString(fl.Field().String()) -} - -// isRGB is the validation function for validating if the current field's value is a valid RGB color. -func isRGB(fl FieldLevel) bool { - return rgbRegex.MatchString(fl.Field().String()) -} - -// isHEXColor is the validation function for validating if the current field's value is a valid HEX color. -func isHEXColor(fl FieldLevel) bool { - return hexColorRegex.MatchString(fl.Field().String()) -} - -// isHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal. -func isHexadecimal(fl FieldLevel) bool { - return hexadecimalRegex.MatchString(fl.Field().String()) -} - -// isNumber is the validation function for validating if the current field's value is a valid number. -func isNumber(fl FieldLevel) bool { - switch fl.Field().Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64: - return true - default: - return numberRegex.MatchString(fl.Field().String()) - } -} - -// isNumeric is the validation function for validating if the current field's value is a valid numeric value. -func isNumeric(fl FieldLevel) bool { - switch fl.Field().Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64: - return true - default: - return numericRegex.MatchString(fl.Field().String()) - } -} - -// isAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value. -func isAlphanum(fl FieldLevel) bool { - return alphaNumericRegex.MatchString(fl.Field().String()) -} - -// isAlpha is the validation function for validating if the current field's value is a valid alpha value. -func isAlpha(fl FieldLevel) bool { - return alphaRegex.MatchString(fl.Field().String()) -} - -// isAlphanumUnicode is the validation function for validating if the current field's value is a valid alphanumeric unicode value. -func isAlphanumUnicode(fl FieldLevel) bool { - return alphaUnicodeNumericRegex.MatchString(fl.Field().String()) -} - -// isAlphaUnicode is the validation function for validating if the current field's value is a valid alpha unicode value. -func isAlphaUnicode(fl FieldLevel) bool { - return alphaUnicodeRegex.MatchString(fl.Field().String()) -} - -// isBoolean is the validation function for validating if the current field's value can be safely converted to a boolean. -func isBoolean(fl FieldLevel) bool { - _, err := strconv.ParseBool(fl.Field().String()) - return err == nil -} - -// isDefault is the opposite of required aka hasValue -func isDefault(fl FieldLevel) bool { - return !hasValue(fl) -} - -// hasValue is the validation function for validating if the current field's value is not the default static value. -func hasValue(fl FieldLevel) bool { - field := fl.Field() - switch field.Kind() { - case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: - return !field.IsNil() - default: - if fl.(*validate).fldIsPointer && field.Interface() != nil { - return true - } - return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface() - } -} - -// requireCheckField is a func for check field kind -func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue bool) bool { - field := fl.Field() - kind := field.Kind() - var nullable, found bool - if len(param) > 0 { - field, kind, nullable, found = fl.GetStructFieldOKAdvanced2(fl.Parent(), param) - if !found { - return defaultNotFoundValue - } - } - switch kind { - case reflect.Invalid: - return defaultNotFoundValue - case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: - return field.IsNil() - default: - if nullable && field.Interface() != nil { - return false - } - return field.IsValid() && field.Interface() == reflect.Zero(field.Type()).Interface() - } -} - -// requireCheckFieldValue is a func for check field value -func requireCheckFieldValue(fl FieldLevel, param string, value string, defaultNotFoundValue bool) bool { - field, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), param) - if !found { - return defaultNotFoundValue - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() == asInt(value) - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() == asUint(value) - - case reflect.Float32, reflect.Float64: - return field.Float() == asFloat(value) - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) == asInt(value) - - case reflect.Bool: - return field.Bool() == asBool(value) - } - - // default reflect.String: - return field.String() == value -} - -// requiredIf is the validation function -// The field under validation must be present and not empty only if all the other specified fields are equal to the value following with the specified field. -func requiredIf(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - if len(params)%2 != 0 { - panic(fmt.Sprintf("Bad param number for required_if %s", fl.FieldName())) - } - for i := 0; i < len(params); i += 2 { - if !requireCheckFieldValue(fl, params[i], params[i+1], false) { - return true - } - } - return hasValue(fl) -} - -// excludedIf is the validation function -// The field under validation must not be present or is empty only if all the other specified fields are equal to the value following with the specified field. -func excludedIf(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - if len(params)%2 != 0 { - panic(fmt.Sprintf("Bad param number for excluded_if %s", fl.FieldName())) - } - - for i := 0; i < len(params); i += 2 { - if !requireCheckFieldValue(fl, params[i], params[i+1], false) { - return false - } - } - return true -} - -// requiredUnless is the validation function -// The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field. -func requiredUnless(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - if len(params)%2 != 0 { - panic(fmt.Sprintf("Bad param number for required_unless %s", fl.FieldName())) - } - - for i := 0; i < len(params); i += 2 { - if requireCheckFieldValue(fl, params[i], params[i+1], false) { - return true - } - } - return hasValue(fl) -} - -// excludedUnless is the validation function -// The field under validation must not be present or is empty unless all the other specified fields are equal to the value following with the specified field. -func excludedUnless(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - if len(params)%2 != 0 { - panic(fmt.Sprintf("Bad param number for excluded_unless %s", fl.FieldName())) - } - for i := 0; i < len(params); i += 2 { - if !requireCheckFieldValue(fl, params[i], params[i+1], false) { - return true - } - } - return !hasValue(fl) -} - -// excludedWith is the validation function -// The field under validation must not be present or is empty if any of the other specified fields are present. -func excludedWith(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - for _, param := range params { - if !requireCheckFieldKind(fl, param, true) { - return !hasValue(fl) - } - } - return true -} - -// requiredWith is the validation function -// The field under validation must be present and not empty only if any of the other specified fields are present. -func requiredWith(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - for _, param := range params { - if !requireCheckFieldKind(fl, param, true) { - return hasValue(fl) - } - } - return true -} - -// excludedWithAll is the validation function -// The field under validation must not be present or is empty if all of the other specified fields are present. -func excludedWithAll(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - for _, param := range params { - if requireCheckFieldKind(fl, param, true) { - return true - } - } - return !hasValue(fl) -} - -// requiredWithAll is the validation function -// The field under validation must be present and not empty only if all of the other specified fields are present. -func requiredWithAll(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - for _, param := range params { - if requireCheckFieldKind(fl, param, true) { - return true - } - } - return hasValue(fl) -} - -// excludedWithout is the validation function -// The field under validation must not be present or is empty when any of the other specified fields are not present. -func excludedWithout(fl FieldLevel) bool { - if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) { - return !hasValue(fl) - } - return true -} - -// requiredWithout is the validation function -// The field under validation must be present and not empty only when any of the other specified fields are not present. -func requiredWithout(fl FieldLevel) bool { - if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) { - return hasValue(fl) - } - return true -} - -// excludedWithoutAll is the validation function -// The field under validation must not be present or is empty when all of the other specified fields are not present. -func excludedWithoutAll(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - for _, param := range params { - if !requireCheckFieldKind(fl, param, true) { - return true - } - } - return !hasValue(fl) -} - -// requiredWithoutAll is the validation function -// The field under validation must be present and not empty only when all of the other specified fields are not present. -func requiredWithoutAll(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - for _, param := range params { - if !requireCheckFieldKind(fl, param, true) { - return true - } - } - return hasValue(fl) -} - -// isGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value. -func isGteField(fl FieldLevel) bool { - field := fl.Field() - kind := field.Kind() - - currentField, currentKind, ok := fl.GetStructFieldOK() - if !ok || currentKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - - return field.Int() >= currentField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - - return field.Uint() >= currentField.Uint() - - case reflect.Float32, reflect.Float64: - - return field.Float() >= currentField.Float() - - case reflect.Struct: - - fieldType := field.Type() - - if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { - - t := currentField.Convert(timeType).Interface().(time.Time) - fieldTime := field.Convert(timeType).Interface().(time.Time) - - return fieldTime.After(t) || fieldTime.Equal(t) - } - - // Not Same underlying type i.e. struct and time - if fieldType != currentField.Type() { - return false - } - } - - // default reflect.String - return len(field.String()) >= len(currentField.String()) -} - -// isGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value. -func isGtField(fl FieldLevel) bool { - field := fl.Field() - kind := field.Kind() - - currentField, currentKind, ok := fl.GetStructFieldOK() - if !ok || currentKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - - return field.Int() > currentField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - - return field.Uint() > currentField.Uint() - - case reflect.Float32, reflect.Float64: - - return field.Float() > currentField.Float() - - case reflect.Struct: - - fieldType := field.Type() - - if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { - - t := currentField.Convert(timeType).Interface().(time.Time) - fieldTime := field.Convert(timeType).Interface().(time.Time) - - return fieldTime.After(t) - } - - // Not Same underlying type i.e. struct and time - if fieldType != currentField.Type() { - return false - } - } - - // default reflect.String - return len(field.String()) > len(currentField.String()) -} - -// isGte is the validation function for validating if the current field's value is greater than or equal to the param's value. -func isGte(fl FieldLevel) bool { - field := fl.Field() - param := fl.Param() - - switch field.Kind() { - - case reflect.String: - p := asInt(param) - - return int64(utf8.RuneCountInString(field.String())) >= p - - case reflect.Slice, reflect.Map, reflect.Array: - p := asInt(param) - - return int64(field.Len()) >= p - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asIntFromType(field.Type(), param) - - return field.Int() >= p - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p := asUint(param) - - return field.Uint() >= p - - case reflect.Float32, reflect.Float64: - p := asFloat(param) - - return field.Float() >= p - - case reflect.Struct: - - if field.Type().ConvertibleTo(timeType) { - - now := time.Now().UTC() - t := field.Convert(timeType).Interface().(time.Time) - - return t.After(now) || t.Equal(now) - } - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isGt is the validation function for validating if the current field's value is greater than the param's value. -func isGt(fl FieldLevel) bool { - field := fl.Field() - param := fl.Param() - - switch field.Kind() { - - case reflect.String: - p := asInt(param) - - return int64(utf8.RuneCountInString(field.String())) > p - - case reflect.Slice, reflect.Map, reflect.Array: - p := asInt(param) - - return int64(field.Len()) > p - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asIntFromType(field.Type(), param) - - return field.Int() > p - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p := asUint(param) - - return field.Uint() > p - - case reflect.Float32, reflect.Float64: - p := asFloat(param) - - return field.Float() > p - case reflect.Struct: - - if field.Type().ConvertibleTo(timeType) { - - return field.Convert(timeType).Interface().(time.Time).After(time.Now().UTC()) - } - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// hasLengthOf is the validation function for validating if the current field's value is equal to the param's value. -func hasLengthOf(fl FieldLevel) bool { - field := fl.Field() - param := fl.Param() - - switch field.Kind() { - - case reflect.String: - p := asInt(param) - - return int64(utf8.RuneCountInString(field.String())) == p - - case reflect.Slice, reflect.Map, reflect.Array: - p := asInt(param) - - return int64(field.Len()) == p - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asIntFromType(field.Type(), param) - - return field.Int() == p - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p := asUint(param) - - return field.Uint() == p - - case reflect.Float32, reflect.Float64: - p := asFloat(param) - - return field.Float() == p - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// hasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value. -func hasMinOf(fl FieldLevel) bool { - return isGte(fl) -} - -// isLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value. -func isLteField(fl FieldLevel) bool { - field := fl.Field() - kind := field.Kind() - - currentField, currentKind, ok := fl.GetStructFieldOK() - if !ok || currentKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - - return field.Int() <= currentField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - - return field.Uint() <= currentField.Uint() - - case reflect.Float32, reflect.Float64: - - return field.Float() <= currentField.Float() - - case reflect.Struct: - - fieldType := field.Type() - - if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { - - t := currentField.Convert(timeType).Interface().(time.Time) - fieldTime := field.Convert(timeType).Interface().(time.Time) - - return fieldTime.Before(t) || fieldTime.Equal(t) - } - - // Not Same underlying type i.e. struct and time - if fieldType != currentField.Type() { - return false - } - } - - // default reflect.String - return len(field.String()) <= len(currentField.String()) -} - -// isLtField is the validation function for validating if the current field's value is less than the field specified by the param's value. -func isLtField(fl FieldLevel) bool { - field := fl.Field() - kind := field.Kind() - - currentField, currentKind, ok := fl.GetStructFieldOK() - if !ok || currentKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - - return field.Int() < currentField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - - return field.Uint() < currentField.Uint() - - case reflect.Float32, reflect.Float64: - - return field.Float() < currentField.Float() - - case reflect.Struct: - - fieldType := field.Type() - - if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { - - t := currentField.Convert(timeType).Interface().(time.Time) - fieldTime := field.Convert(timeType).Interface().(time.Time) - - return fieldTime.Before(t) - } - - // Not Same underlying type i.e. struct and time - if fieldType != currentField.Type() { - return false - } - } - - // default reflect.String - return len(field.String()) < len(currentField.String()) -} - -// isLte is the validation function for validating if the current field's value is less than or equal to the param's value. -func isLte(fl FieldLevel) bool { - field := fl.Field() - param := fl.Param() - - switch field.Kind() { - - case reflect.String: - p := asInt(param) - - return int64(utf8.RuneCountInString(field.String())) <= p - - case reflect.Slice, reflect.Map, reflect.Array: - p := asInt(param) - - return int64(field.Len()) <= p - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asIntFromType(field.Type(), param) - - return field.Int() <= p - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p := asUint(param) - - return field.Uint() <= p - - case reflect.Float32, reflect.Float64: - p := asFloat(param) - - return field.Float() <= p - - case reflect.Struct: - - if field.Type().ConvertibleTo(timeType) { - - now := time.Now().UTC() - t := field.Convert(timeType).Interface().(time.Time) - - return t.Before(now) || t.Equal(now) - } - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isLt is the validation function for validating if the current field's value is less than the param's value. -func isLt(fl FieldLevel) bool { - field := fl.Field() - param := fl.Param() - - switch field.Kind() { - - case reflect.String: - p := asInt(param) - - return int64(utf8.RuneCountInString(field.String())) < p - - case reflect.Slice, reflect.Map, reflect.Array: - p := asInt(param) - - return int64(field.Len()) < p - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asIntFromType(field.Type(), param) - - return field.Int() < p - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p := asUint(param) - - return field.Uint() < p - - case reflect.Float32, reflect.Float64: - p := asFloat(param) - - return field.Float() < p - - case reflect.Struct: - - if field.Type().ConvertibleTo(timeType) { - - return field.Convert(timeType).Interface().(time.Time).Before(time.Now().UTC()) - } - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// hasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value. -func hasMaxOf(fl FieldLevel) bool { - return isLte(fl) -} - -// isTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address. -func isTCP4AddrResolvable(fl FieldLevel) bool { - if !isIP4Addr(fl) { - return false - } - - _, err := net.ResolveTCPAddr("tcp4", fl.Field().String()) - return err == nil -} - -// isTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address. -func isTCP6AddrResolvable(fl FieldLevel) bool { - if !isIP6Addr(fl) { - return false - } - - _, err := net.ResolveTCPAddr("tcp6", fl.Field().String()) - - return err == nil -} - -// isTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address. -func isTCPAddrResolvable(fl FieldLevel) bool { - if !isIP4Addr(fl) && !isIP6Addr(fl) { - return false - } - - _, err := net.ResolveTCPAddr("tcp", fl.Field().String()) - - return err == nil -} - -// isUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address. -func isUDP4AddrResolvable(fl FieldLevel) bool { - if !isIP4Addr(fl) { - return false - } - - _, err := net.ResolveUDPAddr("udp4", fl.Field().String()) - - return err == nil -} - -// isUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address. -func isUDP6AddrResolvable(fl FieldLevel) bool { - if !isIP6Addr(fl) { - return false - } - - _, err := net.ResolveUDPAddr("udp6", fl.Field().String()) - - return err == nil -} - -// isUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address. -func isUDPAddrResolvable(fl FieldLevel) bool { - if !isIP4Addr(fl) && !isIP6Addr(fl) { - return false - } - - _, err := net.ResolveUDPAddr("udp", fl.Field().String()) - - return err == nil -} - -// isIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address. -func isIP4AddrResolvable(fl FieldLevel) bool { - if !isIPv4(fl) { - return false - } - - _, err := net.ResolveIPAddr("ip4", fl.Field().String()) - - return err == nil -} - -// isIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address. -func isIP6AddrResolvable(fl FieldLevel) bool { - if !isIPv6(fl) { - return false - } - - _, err := net.ResolveIPAddr("ip6", fl.Field().String()) - - return err == nil -} - -// isIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address. -func isIPAddrResolvable(fl FieldLevel) bool { - if !isIP(fl) { - return false - } - - _, err := net.ResolveIPAddr("ip", fl.Field().String()) - - return err == nil -} - -// isUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address. -func isUnixAddrResolvable(fl FieldLevel) bool { - _, err := net.ResolveUnixAddr("unix", fl.Field().String()) - - return err == nil -} - -func isIP4Addr(fl FieldLevel) bool { - val := fl.Field().String() - - if idx := strings.LastIndex(val, ":"); idx != -1 { - val = val[0:idx] - } - - ip := net.ParseIP(val) - - return ip != nil && ip.To4() != nil -} - -func isIP6Addr(fl FieldLevel) bool { - val := fl.Field().String() - - if idx := strings.LastIndex(val, ":"); idx != -1 { - if idx != 0 && val[idx-1:idx] == "]" { - val = val[1 : idx-1] - } - } - - ip := net.ParseIP(val) - - return ip != nil && ip.To4() == nil -} - -func isHostnameRFC952(fl FieldLevel) bool { - return hostnameRegexRFC952.MatchString(fl.Field().String()) -} - -func isHostnameRFC1123(fl FieldLevel) bool { - return hostnameRegexRFC1123.MatchString(fl.Field().String()) -} - -func isFQDN(fl FieldLevel) bool { - val := fl.Field().String() - - if val == "" { - return false - } - - return fqdnRegexRFC1123.MatchString(val) -} - -// isDir is the validation function for validating if the current field's value is a valid directory. -func isDir(fl FieldLevel) bool { - field := fl.Field() - - if field.Kind() == reflect.String { - fileInfo, err := os.Stat(field.String()) - if err != nil { - return false - } - - return fileInfo.IsDir() - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isJSON is the validation function for validating if the current field's value is a valid json string. -func isJSON(fl FieldLevel) bool { - field := fl.Field() - - if field.Kind() == reflect.String { - val := field.String() - return json.Valid([]byte(val)) - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isJWT is the validation function for validating if the current field's value is a valid JWT string. -func isJWT(fl FieldLevel) bool { - return jWTRegex.MatchString(fl.Field().String()) -} - -// isHostnamePort validates a : combination for fields typically used for socket address. -func isHostnamePort(fl FieldLevel) bool { - val := fl.Field().String() - host, port, err := net.SplitHostPort(val) - if err != nil { - return false - } - // Port must be a iny <= 65535. - if portNum, err := strconv.ParseInt(port, 10, 32); err != nil || portNum > 65535 || portNum < 1 { - return false - } - - // If host is specified, it should match a DNS name - if host != "" { - return hostnameRegexRFC1123.MatchString(host) - } - return true -} - -// isLowercase is the validation function for validating if the current field's value is a lowercase string. -func isLowercase(fl FieldLevel) bool { - field := fl.Field() - - if field.Kind() == reflect.String { - if field.String() == "" { - return false - } - return field.String() == strings.ToLower(field.String()) - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isUppercase is the validation function for validating if the current field's value is an uppercase string. -func isUppercase(fl FieldLevel) bool { - field := fl.Field() - - if field.Kind() == reflect.String { - if field.String() == "" { - return false - } - return field.String() == strings.ToUpper(field.String()) - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isDatetime is the validation function for validating if the current field's value is a valid datetime string. -func isDatetime(fl FieldLevel) bool { - field := fl.Field() - param := fl.Param() - - if field.Kind() == reflect.String { - _, err := time.Parse(param, field.String()) - - return err == nil - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isTimeZone is the validation function for validating if the current field's value is a valid time zone string. -func isTimeZone(fl FieldLevel) bool { - field := fl.Field() - - if field.Kind() == reflect.String { - // empty value is converted to UTC by time.LoadLocation but disallow it as it is not a valid time zone name - if field.String() == "" { - return false - } - - // Local value is converted to the current system time zone by time.LoadLocation but disallow it as it is not a valid time zone name - if strings.ToLower(field.String()) == "local" { - return false - } - - _, err := time.LoadLocation(field.String()) - return err == nil - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-2 country code. -func isIso3166Alpha2(fl FieldLevel) bool { - val := fl.Field().String() - return iso3166_1_alpha2[val] -} - -// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 country code. -func isIso3166Alpha3(fl FieldLevel) bool { - val := fl.Field().String() - return iso3166_1_alpha3[val] -} - -// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric country code. -func isIso3166AlphaNumeric(fl FieldLevel) bool { - field := fl.Field() - - var code int - switch field.Kind() { - case reflect.String: - i, err := strconv.Atoi(field.String()) - if err != nil { - return false - } - code = i % 1000 - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - code = int(field.Int() % 1000) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - code = int(field.Uint() % 1000) - default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) - } - return iso3166_1_alpha_numeric[code] -} - -// isIso31662 is the validation function for validating if the current field's value is a valid iso3166-2 code. -func isIso31662(fl FieldLevel) bool { - val := fl.Field().String() - return iso3166_2[val] -} - -// isIso4217 is the validation function for validating if the current field's value is a valid iso4217 currency code. -func isIso4217(fl FieldLevel) bool { - val := fl.Field().String() - return iso4217[val] -} - -// isIso4217Numeric is the validation function for validating if the current field's value is a valid iso4217 numeric currency code. -func isIso4217Numeric(fl FieldLevel) bool { - field := fl.Field() - - var code int - switch field.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - code = int(field.Int()) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - code = int(field.Uint()) - default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) - } - return iso4217_numeric[code] -} - -// isBCP47LanguageTag is the validation function for validating if the current field's value is a valid BCP 47 language tag, as parsed by language.Parse -func isBCP47LanguageTag(fl FieldLevel) bool { - field := fl.Field() - - if field.Kind() == reflect.String { - _, err := language.Parse(field.String()) - return err == nil - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isIsoBicFormat is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362 -func isIsoBicFormat(fl FieldLevel) bool { - bicString := fl.Field().String() - - return bicRegex.MatchString(bicString) -} - -// isSemverFormat is the validation function for validating if the current field's value is a valid semver version, defined in Semantic Versioning 2.0.0 -func isSemverFormat(fl FieldLevel) bool { - semverString := fl.Field().String() - - return semverRegex.MatchString(semverString) -} - -// isDnsRFC1035LabelFormat is the validation function -// for validating if the current field's value is -// a valid dns RFC 1035 label, defined in RFC 1035. -func isDnsRFC1035LabelFormat(fl FieldLevel) bool { - val := fl.Field().String() - return dnsRegexRFC1035Label.MatchString(val) -} - -// isCreditCard is the validation function for validating if the current field's value is a valid credit card number -func isCreditCard(fl FieldLevel) bool { - val := fl.Field().String() - var creditCard bytes.Buffer - segments := strings.Split(val, " ") - for _, segment := range segments { - if len(segment) < 3 { - return false - } - creditCard.WriteString(segment) - } - - ccDigits := strings.Split(creditCard.String(), "") - size := len(ccDigits) - if size < 12 || size > 19 { - return false - } - - sum := 0 - for i, digit := range ccDigits { - value, err := strconv.Atoi(digit) - if err != nil { - return false - } - if size%2 == 0 && i%2 == 0 || size%2 == 1 && i%2 == 1 { - v := value * 2 - if v >= 10 { - sum += 1 + (v % 10) - } else { - sum += v - } - } else { - sum += value - } - } - return (sum % 10) == 0 -} diff --git a/vendor/github.com/go-playground/validator/v10/cache.go b/vendor/github.com/go-playground/validator/v10/cache.go deleted file mode 100644 index 7b84c91..0000000 --- a/vendor/github.com/go-playground/validator/v10/cache.go +++ /dev/null @@ -1,327 +0,0 @@ -package validator - -import ( - "fmt" - "reflect" - "strings" - "sync" - "sync/atomic" -) - -type tagType uint8 - -const ( - typeDefault tagType = iota - typeOmitEmpty - typeIsDefault - typeNoStructLevel - typeStructOnly - typeDive - typeOr - typeKeys - typeEndKeys -) - -const ( - invalidValidation = "Invalid validation tag on field '%s'" - undefinedValidation = "Undefined validation function '%s' on field '%s'" - keysTagNotDefined = "'" + endKeysTag + "' tag encountered without a corresponding '" + keysTag + "' tag" -) - -type structCache struct { - lock sync.Mutex - m atomic.Value // map[reflect.Type]*cStruct -} - -func (sc *structCache) Get(key reflect.Type) (c *cStruct, found bool) { - c, found = sc.m.Load().(map[reflect.Type]*cStruct)[key] - return -} - -func (sc *structCache) Set(key reflect.Type, value *cStruct) { - m := sc.m.Load().(map[reflect.Type]*cStruct) - nm := make(map[reflect.Type]*cStruct, len(m)+1) - for k, v := range m { - nm[k] = v - } - nm[key] = value - sc.m.Store(nm) -} - -type tagCache struct { - lock sync.Mutex - m atomic.Value // map[string]*cTag -} - -func (tc *tagCache) Get(key string) (c *cTag, found bool) { - c, found = tc.m.Load().(map[string]*cTag)[key] - return -} - -func (tc *tagCache) Set(key string, value *cTag) { - m := tc.m.Load().(map[string]*cTag) - nm := make(map[string]*cTag, len(m)+1) - for k, v := range m { - nm[k] = v - } - nm[key] = value - tc.m.Store(nm) -} - -type cStruct struct { - name string - fields []*cField - fn StructLevelFuncCtx -} - -type cField struct { - idx int - name string - altName string - namesEqual bool - cTags *cTag -} - -type cTag struct { - tag string - aliasTag string - actualAliasTag string - param string - keys *cTag // only populated when using tag's 'keys' and 'endkeys' for map key validation - next *cTag - fn FuncCtx - typeof tagType - hasTag bool - hasAlias bool - hasParam bool // true if parameter used eg. eq= where the equal sign has been set - isBlockEnd bool // indicates the current tag represents the last validation in the block - runValidationWhenNil bool -} - -func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct { - v.structCache.lock.Lock() - defer v.structCache.lock.Unlock() // leave as defer! because if inner panics, it will never get unlocked otherwise! - - typ := current.Type() - - // could have been multiple trying to access, but once first is done this ensures struct - // isn't parsed again. - cs, ok := v.structCache.Get(typ) - if ok { - return cs - } - - cs = &cStruct{name: sName, fields: make([]*cField, 0), fn: v.structLevelFuncs[typ]} - - numFields := current.NumField() - rules := v.rules[typ] - - var ctag *cTag - var fld reflect.StructField - var tag string - var customName string - - for i := 0; i < numFields; i++ { - - fld = typ.Field(i) - - if !fld.Anonymous && len(fld.PkgPath) > 0 { - continue - } - - if rtag, ok := rules[fld.Name]; ok { - tag = rtag - } else { - tag = fld.Tag.Get(v.tagName) - } - - if tag == skipValidationTag { - continue - } - - customName = fld.Name - - if v.hasTagNameFunc { - name := v.tagNameFunc(fld) - if len(name) > 0 { - customName = name - } - } - - // NOTE: cannot use shared tag cache, because tags may be equal, but things like alias may be different - // and so only struct level caching can be used instead of combined with Field tag caching - - if len(tag) > 0 { - ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, "", false) - } else { - // even if field doesn't have validations need cTag for traversing to potential inner/nested - // elements of the field. - ctag = new(cTag) - } - - cs.fields = append(cs.fields, &cField{ - idx: i, - name: fld.Name, - altName: customName, - cTags: ctag, - namesEqual: fld.Name == customName, - }) - } - v.structCache.Set(typ, cs) - return cs -} - -func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias string, hasAlias bool) (firstCtag *cTag, current *cTag) { - var t string - noAlias := len(alias) == 0 - tags := strings.Split(tag, tagSeparator) - - for i := 0; i < len(tags); i++ { - t = tags[i] - if noAlias { - alias = t - } - - // check map for alias and process new tags, otherwise process as usual - if tagsVal, found := v.aliases[t]; found { - if i == 0 { - firstCtag, current = v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) - } else { - next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) - current.next, current = next, curr - - } - continue - } - - var prevTag tagType - - if i == 0 { - current = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true, typeof: typeDefault} - firstCtag = current - } else { - prevTag = current.typeof - current.next = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true} - current = current.next - } - - switch t { - case diveTag: - current.typeof = typeDive - continue - - case keysTag: - current.typeof = typeKeys - - if i == 0 || prevTag != typeDive { - panic(fmt.Sprintf("'%s' tag must be immediately preceded by the '%s' tag", keysTag, diveTag)) - } - - current.typeof = typeKeys - - // need to pass along only keys tag - // need to increment i to skip over the keys tags - b := make([]byte, 0, 64) - - i++ - - for ; i < len(tags); i++ { - - b = append(b, tags[i]...) - b = append(b, ',') - - if tags[i] == endKeysTag { - break - } - } - - current.keys, _ = v.parseFieldTagsRecursive(string(b[:len(b)-1]), fieldName, "", false) - continue - - case endKeysTag: - current.typeof = typeEndKeys - - // if there are more in tags then there was no keysTag defined - // and an error should be thrown - if i != len(tags)-1 { - panic(keysTagNotDefined) - } - return - - case omitempty: - current.typeof = typeOmitEmpty - continue - - case structOnlyTag: - current.typeof = typeStructOnly - continue - - case noStructLevelTag: - current.typeof = typeNoStructLevel - continue - - default: - if t == isdefault { - current.typeof = typeIsDefault - } - // if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C" - orVals := strings.Split(t, orSeparator) - - for j := 0; j < len(orVals); j++ { - vals := strings.SplitN(orVals[j], tagKeySeparator, 2) - if noAlias { - alias = vals[0] - current.aliasTag = alias - } else { - current.actualAliasTag = t - } - - if j > 0 { - current.next = &cTag{aliasTag: alias, actualAliasTag: current.actualAliasTag, hasAlias: hasAlias, hasTag: true} - current = current.next - } - current.hasParam = len(vals) > 1 - - current.tag = vals[0] - if len(current.tag) == 0 { - panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, fieldName))) - } - - if wrapper, ok := v.validations[current.tag]; ok { - current.fn = wrapper.fn - current.runValidationWhenNil = wrapper.runValidatinOnNil - } else { - panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, current.tag, fieldName))) - } - - if len(orVals) > 1 { - current.typeof = typeOr - } - - if len(vals) > 1 { - current.param = strings.Replace(strings.Replace(vals[1], utf8HexComma, ",", -1), utf8Pipe, "|", -1) - } - } - current.isBlockEnd = true - } - } - return -} - -func (v *Validate) fetchCacheTag(tag string) *cTag { - // find cached tag - ctag, found := v.tagCache.Get(tag) - if !found { - v.tagCache.lock.Lock() - defer v.tagCache.lock.Unlock() - - // could have been multiple trying to access, but once first is done this ensures tag - // isn't parsed again. - ctag, found = v.tagCache.Get(tag) - if !found { - ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false) - v.tagCache.Set(tag, ctag) - } - } - return ctag -} diff --git a/vendor/github.com/go-playground/validator/v10/country_codes.go b/vendor/github.com/go-playground/validator/v10/country_codes.go deleted file mode 100644 index 0d9eda0..0000000 --- a/vendor/github.com/go-playground/validator/v10/country_codes.go +++ /dev/null @@ -1,1132 +0,0 @@ -package validator - -var iso3166_1_alpha2 = map[string]bool{ - // see: https://www.iso.org/iso-3166-country-codes.html - "AF": true, "AX": true, "AL": true, "DZ": true, "AS": true, - "AD": true, "AO": true, "AI": true, "AQ": true, "AG": true, - "AR": true, "AM": true, "AW": true, "AU": true, "AT": true, - "AZ": true, "BS": true, "BH": true, "BD": true, "BB": true, - "BY": true, "BE": true, "BZ": true, "BJ": true, "BM": true, - "BT": true, "BO": true, "BQ": true, "BA": true, "BW": true, - "BV": true, "BR": true, "IO": true, "BN": true, "BG": true, - "BF": true, "BI": true, "KH": true, "CM": true, "CA": true, - "CV": true, "KY": true, "CF": true, "TD": true, "CL": true, - "CN": true, "CX": true, "CC": true, "CO": true, "KM": true, - "CG": true, "CD": true, "CK": true, "CR": true, "CI": true, - "HR": true, "CU": true, "CW": true, "CY": true, "CZ": true, - "DK": true, "DJ": true, "DM": true, "DO": true, "EC": true, - "EG": true, "SV": true, "GQ": true, "ER": true, "EE": true, - "ET": true, "FK": true, "FO": true, "FJ": true, "FI": true, - "FR": true, "GF": true, "PF": true, "TF": true, "GA": true, - "GM": true, "GE": true, "DE": true, "GH": true, "GI": true, - "GR": true, "GL": true, "GD": true, "GP": true, "GU": true, - "GT": true, "GG": true, "GN": true, "GW": true, "GY": true, - "HT": true, "HM": true, "VA": true, "HN": true, "HK": true, - "HU": true, "IS": true, "IN": true, "ID": true, "IR": true, - "IQ": true, "IE": true, "IM": true, "IL": true, "IT": true, - "JM": true, "JP": true, "JE": true, "JO": true, "KZ": true, - "KE": true, "KI": true, "KP": true, "KR": true, "KW": true, - "KG": true, "LA": true, "LV": true, "LB": true, "LS": true, - "LR": true, "LY": true, "LI": true, "LT": true, "LU": true, - "MO": true, "MK": true, "MG": true, "MW": true, "MY": true, - "MV": true, "ML": true, "MT": true, "MH": true, "MQ": true, - "MR": true, "MU": true, "YT": true, "MX": true, "FM": true, - "MD": true, "MC": true, "MN": true, "ME": true, "MS": true, - "MA": true, "MZ": true, "MM": true, "NA": true, "NR": true, - "NP": true, "NL": true, "NC": true, "NZ": true, "NI": true, - "NE": true, "NG": true, "NU": true, "NF": true, "MP": true, - "NO": true, "OM": true, "PK": true, "PW": true, "PS": true, - "PA": true, "PG": true, "PY": true, "PE": true, "PH": true, - "PN": true, "PL": true, "PT": true, "PR": true, "QA": true, - "RE": true, "RO": true, "RU": true, "RW": true, "BL": true, - "SH": true, "KN": true, "LC": true, "MF": true, "PM": true, - "VC": true, "WS": true, "SM": true, "ST": true, "SA": true, - "SN": true, "RS": true, "SC": true, "SL": true, "SG": true, - "SX": true, "SK": true, "SI": true, "SB": true, "SO": true, - "ZA": true, "GS": true, "SS": true, "ES": true, "LK": true, - "SD": true, "SR": true, "SJ": true, "SZ": true, "SE": true, - "CH": true, "SY": true, "TW": true, "TJ": true, "TZ": true, - "TH": true, "TL": true, "TG": true, "TK": true, "TO": true, - "TT": true, "TN": true, "TR": true, "TM": true, "TC": true, - "TV": true, "UG": true, "UA": true, "AE": true, "GB": true, - "US": true, "UM": true, "UY": true, "UZ": true, "VU": true, - "VE": true, "VN": true, "VG": true, "VI": true, "WF": true, - "EH": true, "YE": true, "ZM": true, "ZW": true, -} - -var iso3166_1_alpha3 = map[string]bool{ - // see: https://www.iso.org/iso-3166-country-codes.html - "AFG": true, "ALB": true, "DZA": true, "ASM": true, "AND": true, - "AGO": true, "AIA": true, "ATA": true, "ATG": true, "ARG": true, - "ARM": true, "ABW": true, "AUS": true, "AUT": true, "AZE": true, - "BHS": true, "BHR": true, "BGD": true, "BRB": true, "BLR": true, - "BEL": true, "BLZ": true, "BEN": true, "BMU": true, "BTN": true, - "BOL": true, "BES": true, "BIH": true, "BWA": true, "BVT": true, - "BRA": true, "IOT": true, "BRN": true, "BGR": true, "BFA": true, - "BDI": true, "CPV": true, "KHM": true, "CMR": true, "CAN": true, - "CYM": true, "CAF": true, "TCD": true, "CHL": true, "CHN": true, - "CXR": true, "CCK": true, "COL": true, "COM": true, "COD": true, - "COG": true, "COK": true, "CRI": true, "HRV": true, "CUB": true, - "CUW": true, "CYP": true, "CZE": true, "CIV": true, "DNK": true, - "DJI": true, "DMA": true, "DOM": true, "ECU": true, "EGY": true, - "SLV": true, "GNQ": true, "ERI": true, "EST": true, "SWZ": true, - "ETH": true, "FLK": true, "FRO": true, "FJI": true, "FIN": true, - "FRA": true, "GUF": true, "PYF": true, "ATF": true, "GAB": true, - "GMB": true, "GEO": true, "DEU": true, "GHA": true, "GIB": true, - "GRC": true, "GRL": true, "GRD": true, "GLP": true, "GUM": true, - "GTM": true, "GGY": true, "GIN": true, "GNB": true, "GUY": true, - "HTI": true, "HMD": true, "VAT": true, "HND": true, "HKG": true, - "HUN": true, "ISL": true, "IND": true, "IDN": true, "IRN": true, - "IRQ": true, "IRL": true, "IMN": true, "ISR": true, "ITA": true, - "JAM": true, "JPN": true, "JEY": true, "JOR": true, "KAZ": true, - "KEN": true, "KIR": true, "PRK": true, "KOR": true, "KWT": true, - "KGZ": true, "LAO": true, "LVA": true, "LBN": true, "LSO": true, - "LBR": true, "LBY": true, "LIE": true, "LTU": true, "LUX": true, - "MAC": true, "MDG": true, "MWI": true, "MYS": true, "MDV": true, - "MLI": true, "MLT": true, "MHL": true, "MTQ": true, "MRT": true, - "MUS": true, "MYT": true, "MEX": true, "FSM": true, "MDA": true, - "MCO": true, "MNG": true, "MNE": true, "MSR": true, "MAR": true, - "MOZ": true, "MMR": true, "NAM": true, "NRU": true, "NPL": true, - "NLD": true, "NCL": true, "NZL": true, "NIC": true, "NER": true, - "NGA": true, "NIU": true, "NFK": true, "MKD": true, "MNP": true, - "NOR": true, "OMN": true, "PAK": true, "PLW": true, "PSE": true, - "PAN": true, "PNG": true, "PRY": true, "PER": true, "PHL": true, - "PCN": true, "POL": true, "PRT": true, "PRI": true, "QAT": true, - "ROU": true, "RUS": true, "RWA": true, "REU": true, "BLM": true, - "SHN": true, "KNA": true, "LCA": true, "MAF": true, "SPM": true, - "VCT": true, "WSM": true, "SMR": true, "STP": true, "SAU": true, - "SEN": true, "SRB": true, "SYC": true, "SLE": true, "SGP": true, - "SXM": true, "SVK": true, "SVN": true, "SLB": true, "SOM": true, - "ZAF": true, "SGS": true, "SSD": true, "ESP": true, "LKA": true, - "SDN": true, "SUR": true, "SJM": true, "SWE": true, "CHE": true, - "SYR": true, "TWN": true, "TJK": true, "TZA": true, "THA": true, - "TLS": true, "TGO": true, "TKL": true, "TON": true, "TTO": true, - "TUN": true, "TUR": true, "TKM": true, "TCA": true, "TUV": true, - "UGA": true, "UKR": true, "ARE": true, "GBR": true, "UMI": true, - "USA": true, "URY": true, "UZB": true, "VUT": true, "VEN": true, - "VNM": true, "VGB": true, "VIR": true, "WLF": true, "ESH": true, - "YEM": true, "ZMB": true, "ZWE": true, "ALA": true, -} -var iso3166_1_alpha_numeric = map[int]bool{ - // see: https://www.iso.org/iso-3166-country-codes.html - 4: true, 8: true, 12: true, 16: true, 20: true, - 24: true, 660: true, 10: true, 28: true, 32: true, - 51: true, 533: true, 36: true, 40: true, 31: true, - 44: true, 48: true, 50: true, 52: true, 112: true, - 56: true, 84: true, 204: true, 60: true, 64: true, - 68: true, 535: true, 70: true, 72: true, 74: true, - 76: true, 86: true, 96: true, 100: true, 854: true, - 108: true, 132: true, 116: true, 120: true, 124: true, - 136: true, 140: true, 148: true, 152: true, 156: true, - 162: true, 166: true, 170: true, 174: true, 180: true, - 178: true, 184: true, 188: true, 191: true, 192: true, - 531: true, 196: true, 203: true, 384: true, 208: true, - 262: true, 212: true, 214: true, 218: true, 818: true, - 222: true, 226: true, 232: true, 233: true, 748: true, - 231: true, 238: true, 234: true, 242: true, 246: true, - 250: true, 254: true, 258: true, 260: true, 266: true, - 270: true, 268: true, 276: true, 288: true, 292: true, - 300: true, 304: true, 308: true, 312: true, 316: true, - 320: true, 831: true, 324: true, 624: true, 328: true, - 332: true, 334: true, 336: true, 340: true, 344: true, - 348: true, 352: true, 356: true, 360: true, 364: true, - 368: true, 372: true, 833: true, 376: true, 380: true, - 388: true, 392: true, 832: true, 400: true, 398: true, - 404: true, 296: true, 408: true, 410: true, 414: true, - 417: true, 418: true, 428: true, 422: true, 426: true, - 430: true, 434: true, 438: true, 440: true, 442: true, - 446: true, 450: true, 454: true, 458: true, 462: true, - 466: true, 470: true, 584: true, 474: true, 478: true, - 480: true, 175: true, 484: true, 583: true, 498: true, - 492: true, 496: true, 499: true, 500: true, 504: true, - 508: true, 104: true, 516: true, 520: true, 524: true, - 528: true, 540: true, 554: true, 558: true, 562: true, - 566: true, 570: true, 574: true, 807: true, 580: true, - 578: true, 512: true, 586: true, 585: true, 275: true, - 591: true, 598: true, 600: true, 604: true, 608: true, - 612: true, 616: true, 620: true, 630: true, 634: true, - 642: true, 643: true, 646: true, 638: true, 652: true, - 654: true, 659: true, 662: true, 663: true, 666: true, - 670: true, 882: true, 674: true, 678: true, 682: true, - 686: true, 688: true, 690: true, 694: true, 702: true, - 534: true, 703: true, 705: true, 90: true, 706: true, - 710: true, 239: true, 728: true, 724: true, 144: true, - 729: true, 740: true, 744: true, 752: true, 756: true, - 760: true, 158: true, 762: true, 834: true, 764: true, - 626: true, 768: true, 772: true, 776: true, 780: true, - 788: true, 792: true, 795: true, 796: true, 798: true, - 800: true, 804: true, 784: true, 826: true, 581: true, - 840: true, 858: true, 860: true, 548: true, 862: true, - 704: true, 92: true, 850: true, 876: true, 732: true, - 887: true, 894: true, 716: true, 248: true, -} - -var iso3166_2 = map[string]bool{ - "AD-02" : true, "AD-03" : true, "AD-04" : true, "AD-05" : true, "AD-06" : true, - "AD-07" : true, "AD-08" : true, "AE-AJ" : true, "AE-AZ" : true, "AE-DU" : true, - "AE-FU" : true, "AE-RK" : true, "AE-SH" : true, "AE-UQ" : true, "AF-BAL" : true, - "AF-BAM" : true, "AF-BDG" : true, "AF-BDS" : true, "AF-BGL" : true, "AF-DAY" : true, - "AF-FRA" : true, "AF-FYB" : true, "AF-GHA" : true, "AF-GHO" : true, "AF-HEL" : true, - "AF-HER" : true, "AF-JOW" : true, "AF-KAB" : true, "AF-KAN" : true, "AF-KAP" : true, - "AF-KDZ" : true, "AF-KHO" : true, "AF-KNR" : true, "AF-LAG" : true, "AF-LOG" : true, - "AF-NAN" : true, "AF-NIM" : true, "AF-NUR" : true, "AF-PAN" : true, "AF-PAR" : true, - "AF-PIA" : true, "AF-PKA" : true, "AF-SAM" : true, "AF-SAR" : true, "AF-TAK" : true, - "AF-URU" : true, "AF-WAR" : true, "AF-ZAB" : true, "AG-03" : true, "AG-04" : true, - "AG-05" : true, "AG-06" : true, "AG-07" : true, "AG-08" : true, "AG-10" : true, - "AG-11" : true, "AL-01" : true, "AL-02" : true, "AL-03" : true, "AL-04" : true, - "AL-05" : true, "AL-06" : true, "AL-07" : true, "AL-08" : true, "AL-09" : true, - "AL-10" : true, "AL-11" : true, "AL-12" : true, "AL-BR" : true, "AL-BU" : true, - "AL-DI" : true, "AL-DL" : true, "AL-DR" : true, "AL-DV" : true, "AL-EL" : true, - "AL-ER" : true, "AL-FR" : true, "AL-GJ" : true, "AL-GR" : true, "AL-HA" : true, - "AL-KA" : true, "AL-KB" : true, "AL-KC" : true, "AL-KO" : true, "AL-KR" : true, - "AL-KU" : true, "AL-LB" : true, "AL-LE" : true, "AL-LU" : true, "AL-MK" : true, - "AL-MM" : true, "AL-MR" : true, "AL-MT" : true, "AL-PG" : true, "AL-PQ" : true, - "AL-PR" : true, "AL-PU" : true, "AL-SH" : true, "AL-SK" : true, "AL-SR" : true, - "AL-TE" : true, "AL-TP" : true, "AL-TR" : true, "AL-VL" : true, "AM-AG" : true, - "AM-AR" : true, "AM-AV" : true, "AM-ER" : true, "AM-GR" : true, "AM-KT" : true, - "AM-LO" : true, "AM-SH" : true, "AM-SU" : true, "AM-TV" : true, "AM-VD" : true, - "AO-BGO" : true, "AO-BGU" : true, "AO-BIE" : true, "AO-CAB" : true, "AO-CCU" : true, - "AO-CNN" : true, "AO-CNO" : true, "AO-CUS" : true, "AO-HUA" : true, "AO-HUI" : true, - "AO-LNO" : true, "AO-LSU" : true, "AO-LUA" : true, "AO-MAL" : true, "AO-MOX" : true, - "AO-NAM" : true, "AO-UIG" : true, "AO-ZAI" : true, "AR-A" : true, "AR-B" : true, - "AR-C" : true, "AR-D" : true, "AR-E" : true, "AR-G" : true, "AR-H" : true, - "AR-J" : true, "AR-K" : true, "AR-L" : true, "AR-M" : true, "AR-N" : true, - "AR-P" : true, "AR-Q" : true, "AR-R" : true, "AR-S" : true, "AR-T" : true, - "AR-U" : true, "AR-V" : true, "AR-W" : true, "AR-X" : true, "AR-Y" : true, - "AR-Z" : true, "AT-1" : true, "AT-2" : true, "AT-3" : true, "AT-4" : true, - "AT-5" : true, "AT-6" : true, "AT-7" : true, "AT-8" : true, "AT-9" : true, - "AU-ACT" : true, "AU-NSW" : true, "AU-NT" : true, "AU-QLD" : true, "AU-SA" : true, - "AU-TAS" : true, "AU-VIC" : true, "AU-WA" : true, "AZ-ABS" : true, "AZ-AGA" : true, - "AZ-AGC" : true, "AZ-AGM" : true, "AZ-AGS" : true, "AZ-AGU" : true, "AZ-AST" : true, - "AZ-BA" : true, "AZ-BAB" : true, "AZ-BAL" : true, "AZ-BAR" : true, "AZ-BEY" : true, - "AZ-BIL" : true, "AZ-CAB" : true, "AZ-CAL" : true, "AZ-CUL" : true, "AZ-DAS" : true, - "AZ-FUZ" : true, "AZ-GA" : true, "AZ-GAD" : true, "AZ-GOR" : true, "AZ-GOY" : true, - "AZ-GYG" : true, "AZ-HAC" : true, "AZ-IMI" : true, "AZ-ISM" : true, "AZ-KAL" : true, - "AZ-KAN" : true, "AZ-KUR" : true, "AZ-LA" : true, "AZ-LAC" : true, "AZ-LAN" : true, - "AZ-LER" : true, "AZ-MAS" : true, "AZ-MI" : true, "AZ-NA" : true, "AZ-NEF" : true, - "AZ-NV" : true, "AZ-NX" : true, "AZ-OGU" : true, "AZ-ORD" : true, "AZ-QAB" : true, - "AZ-QAX" : true, "AZ-QAZ" : true, "AZ-QBA" : true, "AZ-QBI" : true, "AZ-QOB" : true, - "AZ-QUS" : true, "AZ-SA" : true, "AZ-SAB" : true, "AZ-SAD" : true, "AZ-SAH" : true, - "AZ-SAK" : true, "AZ-SAL" : true, "AZ-SAR" : true, "AZ-SAT" : true, "AZ-SBN" : true, - "AZ-SIY" : true, "AZ-SKR" : true, "AZ-SM" : true, "AZ-SMI" : true, "AZ-SMX" : true, - "AZ-SR" : true, "AZ-SUS" : true, "AZ-TAR" : true, "AZ-TOV" : true, "AZ-UCA" : true, - "AZ-XA" : true, "AZ-XAC" : true, "AZ-XCI" : true, "AZ-XIZ" : true, "AZ-XVD" : true, - "AZ-YAR" : true, "AZ-YE" : true, "AZ-YEV" : true, "AZ-ZAN" : true, "AZ-ZAQ" : true, - "AZ-ZAR" : true, "BA-01" : true, "BA-02" : true, "BA-03" : true, "BA-04" : true, - "BA-05" : true, "BA-06" : true, "BA-07" : true, "BA-08" : true, "BA-09" : true, - "BA-10" : true, "BA-BIH" : true, "BA-BRC" : true, "BA-SRP" : true, "BB-01" : true, - "BB-02" : true, "BB-03" : true, "BB-04" : true, "BB-05" : true, "BB-06" : true, - "BB-07" : true, "BB-08" : true, "BB-09" : true, "BB-10" : true, "BB-11" : true, - "BD-01" : true, "BD-02" : true, "BD-03" : true, "BD-04" : true, "BD-05" : true, - "BD-06" : true, "BD-07" : true, "BD-08" : true, "BD-09" : true, "BD-10" : true, - "BD-11" : true, "BD-12" : true, "BD-13" : true, "BD-14" : true, "BD-15" : true, - "BD-16" : true, "BD-17" : true, "BD-18" : true, "BD-19" : true, "BD-20" : true, - "BD-21" : true, "BD-22" : true, "BD-23" : true, "BD-24" : true, "BD-25" : true, - "BD-26" : true, "BD-27" : true, "BD-28" : true, "BD-29" : true, "BD-30" : true, - "BD-31" : true, "BD-32" : true, "BD-33" : true, "BD-34" : true, "BD-35" : true, - "BD-36" : true, "BD-37" : true, "BD-38" : true, "BD-39" : true, "BD-40" : true, - "BD-41" : true, "BD-42" : true, "BD-43" : true, "BD-44" : true, "BD-45" : true, - "BD-46" : true, "BD-47" : true, "BD-48" : true, "BD-49" : true, "BD-50" : true, - "BD-51" : true, "BD-52" : true, "BD-53" : true, "BD-54" : true, "BD-55" : true, - "BD-56" : true, "BD-57" : true, "BD-58" : true, "BD-59" : true, "BD-60" : true, - "BD-61" : true, "BD-62" : true, "BD-63" : true, "BD-64" : true, "BD-A" : true, - "BD-B" : true, "BD-C" : true, "BD-D" : true, "BD-E" : true, "BD-F" : true, - "BD-G" : true, "BE-BRU" : true, "BE-VAN" : true, "BE-VBR" : true, "BE-VLG" : true, - "BE-VLI" : true, "BE-VOV" : true, "BE-VWV" : true, "BE-WAL" : true, "BE-WBR" : true, - "BE-WHT" : true, "BE-WLG" : true, "BE-WLX" : true, "BE-WNA" : true, "BF-01" : true, - "BF-02" : true, "BF-03" : true, "BF-04" : true, "BF-05" : true, "BF-06" : true, - "BF-07" : true, "BF-08" : true, "BF-09" : true, "BF-10" : true, "BF-11" : true, - "BF-12" : true, "BF-13" : true, "BF-BAL" : true, "BF-BAM" : true, "BF-BAN" : true, - "BF-BAZ" : true, "BF-BGR" : true, "BF-BLG" : true, "BF-BLK" : true, "BF-COM" : true, - "BF-GAN" : true, "BF-GNA" : true, "BF-GOU" : true, "BF-HOU" : true, "BF-IOB" : true, - "BF-KAD" : true, "BF-KEN" : true, "BF-KMD" : true, "BF-KMP" : true, "BF-KOP" : true, - "BF-KOS" : true, "BF-KOT" : true, "BF-KOW" : true, "BF-LER" : true, "BF-LOR" : true, - "BF-MOU" : true, "BF-NAM" : true, "BF-NAO" : true, "BF-NAY" : true, "BF-NOU" : true, - "BF-OUB" : true, "BF-OUD" : true, "BF-PAS" : true, "BF-PON" : true, "BF-SEN" : true, - "BF-SIS" : true, "BF-SMT" : true, "BF-SNG" : true, "BF-SOM" : true, "BF-SOR" : true, - "BF-TAP" : true, "BF-TUI" : true, "BF-YAG" : true, "BF-YAT" : true, "BF-ZIR" : true, - "BF-ZON" : true, "BF-ZOU" : true, "BG-01" : true, "BG-02" : true, "BG-03" : true, - "BG-04" : true, "BG-05" : true, "BG-06" : true, "BG-07" : true, "BG-08" : true, - "BG-09" : true, "BG-10" : true, "BG-11" : true, "BG-12" : true, "BG-13" : true, - "BG-14" : true, "BG-15" : true, "BG-16" : true, "BG-17" : true, "BG-18" : true, - "BG-19" : true, "BG-20" : true, "BG-21" : true, "BG-22" : true, "BG-23" : true, - "BG-24" : true, "BG-25" : true, "BG-26" : true, "BG-27" : true, "BG-28" : true, - "BH-13" : true, "BH-14" : true, "BH-15" : true, "BH-16" : true, "BH-17" : true, - "BI-BB" : true, "BI-BL" : true, "BI-BM" : true, "BI-BR" : true, "BI-CA" : true, - "BI-CI" : true, "BI-GI" : true, "BI-KI" : true, "BI-KR" : true, "BI-KY" : true, - "BI-MA" : true, "BI-MU" : true, "BI-MW" : true, "BI-NG" : true, "BI-RT" : true, - "BI-RY" : true, "BJ-AK" : true, "BJ-AL" : true, "BJ-AQ" : true, "BJ-BO" : true, - "BJ-CO" : true, "BJ-DO" : true, "BJ-KO" : true, "BJ-LI" : true, "BJ-MO" : true, - "BJ-OU" : true, "BJ-PL" : true, "BJ-ZO" : true, "BN-BE" : true, "BN-BM" : true, - "BN-TE" : true, "BN-TU" : true, "BO-B" : true, "BO-C" : true, "BO-H" : true, - "BO-L" : true, "BO-N" : true, "BO-O" : true, "BO-P" : true, "BO-S" : true, - "BO-T" : true, "BQ-BO" : true, "BQ-SA" : true, "BQ-SE" : true, "BR-AC" : true, - "BR-AL" : true, "BR-AM" : true, "BR-AP" : true, "BR-BA" : true, "BR-CE" : true, - "BR-DF" : true, "BR-ES" : true, "BR-FN" : true, "BR-GO" : true, "BR-MA" : true, - "BR-MG" : true, "BR-MS" : true, "BR-MT" : true, "BR-PA" : true, "BR-PB" : true, - "BR-PE" : true, "BR-PI" : true, "BR-PR" : true, "BR-RJ" : true, "BR-RN" : true, - "BR-RO" : true, "BR-RR" : true, "BR-RS" : true, "BR-SC" : true, "BR-SE" : true, - "BR-SP" : true, "BR-TO" : true, "BS-AK" : true, "BS-BI" : true, "BS-BP" : true, - "BS-BY" : true, "BS-CE" : true, "BS-CI" : true, "BS-CK" : true, "BS-CO" : true, - "BS-CS" : true, "BS-EG" : true, "BS-EX" : true, "BS-FP" : true, "BS-GC" : true, - "BS-HI" : true, "BS-HT" : true, "BS-IN" : true, "BS-LI" : true, "BS-MC" : true, - "BS-MG" : true, "BS-MI" : true, "BS-NE" : true, "BS-NO" : true, "BS-NS" : true, - "BS-RC" : true, "BS-RI" : true, "BS-SA" : true, "BS-SE" : true, "BS-SO" : true, - "BS-SS" : true, "BS-SW" : true, "BS-WG" : true, "BT-11" : true, "BT-12" : true, - "BT-13" : true, "BT-14" : true, "BT-15" : true, "BT-21" : true, "BT-22" : true, - "BT-23" : true, "BT-24" : true, "BT-31" : true, "BT-32" : true, "BT-33" : true, - "BT-34" : true, "BT-41" : true, "BT-42" : true, "BT-43" : true, "BT-44" : true, - "BT-45" : true, "BT-GA" : true, "BT-TY" : true, "BW-CE" : true, "BW-GH" : true, - "BW-KG" : true, "BW-KL" : true, "BW-KW" : true, "BW-NE" : true, "BW-NW" : true, - "BW-SE" : true, "BW-SO" : true, "BY-BR" : true, "BY-HM" : true, "BY-HO" : true, - "BY-HR" : true, "BY-MA" : true, "BY-MI" : true, "BY-VI" : true, "BZ-BZ" : true, - "BZ-CY" : true, "BZ-CZL" : true, "BZ-OW" : true, "BZ-SC" : true, "BZ-TOL" : true, - "CA-AB" : true, "CA-BC" : true, "CA-MB" : true, "CA-NB" : true, "CA-NL" : true, - "CA-NS" : true, "CA-NT" : true, "CA-NU" : true, "CA-ON" : true, "CA-PE" : true, - "CA-QC" : true, "CA-SK" : true, "CA-YT" : true, "CD-BC" : true, "CD-BN" : true, - "CD-EQ" : true, "CD-KA" : true, "CD-KE" : true, "CD-KN" : true, "CD-KW" : true, - "CD-MA" : true, "CD-NK" : true, "CD-OR" : true, "CD-SK" : true, "CF-AC" : true, - "CF-BB" : true, "CF-BGF" : true, "CF-BK" : true, "CF-HK" : true, "CF-HM" : true, - "CF-HS" : true, "CF-KB" : true, "CF-KG" : true, "CF-LB" : true, "CF-MB" : true, - "CF-MP" : true, "CF-NM" : true, "CF-OP" : true, "CF-SE" : true, "CF-UK" : true, - "CF-VK" : true, "CG-11" : true, "CG-12" : true, "CG-13" : true, "CG-14" : true, - "CG-15" : true, "CG-2" : true, "CG-5" : true, "CG-7" : true, "CG-8" : true, - "CG-9" : true, "CG-BZV" : true, "CH-AG" : true, "CH-AI" : true, "CH-AR" : true, - "CH-BE" : true, "CH-BL" : true, "CH-BS" : true, "CH-FR" : true, "CH-GE" : true, - "CH-GL" : true, "CH-GR" : true, "CH-JU" : true, "CH-LU" : true, "CH-NE" : true, - "CH-NW" : true, "CH-OW" : true, "CH-SG" : true, "CH-SH" : true, "CH-SO" : true, - "CH-SZ" : true, "CH-TG" : true, "CH-TI" : true, "CH-UR" : true, "CH-VD" : true, - "CH-VS" : true, "CH-ZG" : true, "CH-ZH" : true, "CI-01" : true, "CI-02" : true, - "CI-03" : true, "CI-04" : true, "CI-05" : true, "CI-06" : true, "CI-07" : true, - "CI-08" : true, "CI-09" : true, "CI-10" : true, "CI-11" : true, "CI-12" : true, - "CI-13" : true, "CI-14" : true, "CI-15" : true, "CI-16" : true, "CI-17" : true, - "CI-18" : true, "CI-19" : true, "CL-AI" : true, "CL-AN" : true, "CL-AP" : true, - "CL-AR" : true, "CL-AT" : true, "CL-BI" : true, "CL-CO" : true, "CL-LI" : true, - "CL-LL" : true, "CL-LR" : true, "CL-MA" : true, "CL-ML" : true, "CL-RM" : true, - "CL-TA" : true, "CL-VS" : true, "CM-AD" : true, "CM-CE" : true, "CM-EN" : true, - "CM-ES" : true, "CM-LT" : true, "CM-NO" : true, "CM-NW" : true, "CM-OU" : true, - "CM-SU" : true, "CM-SW" : true, "CN-11" : true, "CN-12" : true, "CN-13" : true, - "CN-14" : true, "CN-15" : true, "CN-21" : true, "CN-22" : true, "CN-23" : true, - "CN-31" : true, "CN-32" : true, "CN-33" : true, "CN-34" : true, "CN-35" : true, - "CN-36" : true, "CN-37" : true, "CN-41" : true, "CN-42" : true, "CN-43" : true, - "CN-44" : true, "CN-45" : true, "CN-46" : true, "CN-50" : true, "CN-51" : true, - "CN-52" : true, "CN-53" : true, "CN-54" : true, "CN-61" : true, "CN-62" : true, - "CN-63" : true, "CN-64" : true, "CN-65" : true, "CN-71" : true, "CN-91" : true, - "CN-92" : true, "CO-AMA" : true, "CO-ANT" : true, "CO-ARA" : true, "CO-ATL" : true, - "CO-BOL" : true, "CO-BOY" : true, "CO-CAL" : true, "CO-CAQ" : true, "CO-CAS" : true, - "CO-CAU" : true, "CO-CES" : true, "CO-CHO" : true, "CO-COR" : true, "CO-CUN" : true, - "CO-DC" : true, "CO-GUA" : true, "CO-GUV" : true, "CO-HUI" : true, "CO-LAG" : true, - "CO-MAG" : true, "CO-MET" : true, "CO-NAR" : true, "CO-NSA" : true, "CO-PUT" : true, - "CO-QUI" : true, "CO-RIS" : true, "CO-SAN" : true, "CO-SAP" : true, "CO-SUC" : true, - "CO-TOL" : true, "CO-VAC" : true, "CO-VAU" : true, "CO-VID" : true, "CR-A" : true, - "CR-C" : true, "CR-G" : true, "CR-H" : true, "CR-L" : true, "CR-P" : true, - "CR-SJ" : true, "CU-01" : true, "CU-02" : true, "CU-03" : true, "CU-04" : true, - "CU-05" : true, "CU-06" : true, "CU-07" : true, "CU-08" : true, "CU-09" : true, - "CU-10" : true, "CU-11" : true, "CU-12" : true, "CU-13" : true, "CU-14" : true, - "CU-99" : true, "CV-B" : true, "CV-BR" : true, "CV-BV" : true, "CV-CA" : true, - "CV-CF" : true, "CV-CR" : true, "CV-MA" : true, "CV-MO" : true, "CV-PA" : true, - "CV-PN" : true, "CV-PR" : true, "CV-RB" : true, "CV-RG" : true, "CV-RS" : true, - "CV-S" : true, "CV-SD" : true, "CV-SF" : true, "CV-SL" : true, "CV-SM" : true, - "CV-SO" : true, "CV-SS" : true, "CV-SV" : true, "CV-TA" : true, "CV-TS" : true, - "CY-01" : true, "CY-02" : true, "CY-03" : true, "CY-04" : true, "CY-05" : true, - "CY-06" : true, "CZ-10" : true, "CZ-101" : true, "CZ-102" : true, "CZ-103" : true, - "CZ-104" : true, "CZ-105" : true, "CZ-106" : true, "CZ-107" : true, "CZ-108" : true, - "CZ-109" : true, "CZ-110" : true, "CZ-111" : true, "CZ-112" : true, "CZ-113" : true, - "CZ-114" : true, "CZ-115" : true, "CZ-116" : true, "CZ-117" : true, "CZ-118" : true, - "CZ-119" : true, "CZ-120" : true, "CZ-121" : true, "CZ-122" : true, "CZ-20" : true, - "CZ-201" : true, "CZ-202" : true, "CZ-203" : true, "CZ-204" : true, "CZ-205" : true, - "CZ-206" : true, "CZ-207" : true, "CZ-208" : true, "CZ-209" : true, "CZ-20A" : true, - "CZ-20B" : true, "CZ-20C" : true, "CZ-31" : true, "CZ-311" : true, "CZ-312" : true, - "CZ-313" : true, "CZ-314" : true, "CZ-315" : true, "CZ-316" : true, "CZ-317" : true, - "CZ-32" : true, "CZ-321" : true, "CZ-322" : true, "CZ-323" : true, "CZ-324" : true, - "CZ-325" : true, "CZ-326" : true, "CZ-327" : true, "CZ-41" : true, "CZ-411" : true, - "CZ-412" : true, "CZ-413" : true, "CZ-42" : true, "CZ-421" : true, "CZ-422" : true, - "CZ-423" : true, "CZ-424" : true, "CZ-425" : true, "CZ-426" : true, "CZ-427" : true, - "CZ-51" : true, "CZ-511" : true, "CZ-512" : true, "CZ-513" : true, "CZ-514" : true, - "CZ-52" : true, "CZ-521" : true, "CZ-522" : true, "CZ-523" : true, "CZ-524" : true, - "CZ-525" : true, "CZ-53" : true, "CZ-531" : true, "CZ-532" : true, "CZ-533" : true, - "CZ-534" : true, "CZ-63" : true, "CZ-631" : true, "CZ-632" : true, "CZ-633" : true, - "CZ-634" : true, "CZ-635" : true, "CZ-64" : true, "CZ-641" : true, "CZ-642" : true, - "CZ-643" : true, "CZ-644" : true, "CZ-645" : true, "CZ-646" : true, "CZ-647" : true, - "CZ-71" : true, "CZ-711" : true, "CZ-712" : true, "CZ-713" : true, "CZ-714" : true, - "CZ-715" : true, "CZ-72" : true, "CZ-721" : true, "CZ-722" : true, "CZ-723" : true, - "CZ-724" : true, "CZ-80" : true, "CZ-801" : true, "CZ-802" : true, "CZ-803" : true, - "CZ-804" : true, "CZ-805" : true, "CZ-806" : true, "DE-BB" : true, "DE-BE" : true, - "DE-BW" : true, "DE-BY" : true, "DE-HB" : true, "DE-HE" : true, "DE-HH" : true, - "DE-MV" : true, "DE-NI" : true, "DE-NW" : true, "DE-RP" : true, "DE-SH" : true, - "DE-SL" : true, "DE-SN" : true, "DE-ST" : true, "DE-TH" : true, "DJ-AR" : true, - "DJ-AS" : true, "DJ-DI" : true, "DJ-DJ" : true, "DJ-OB" : true, "DJ-TA" : true, - "DK-81" : true, "DK-82" : true, "DK-83" : true, "DK-84" : true, "DK-85" : true, - "DM-01" : true, "DM-02" : true, "DM-03" : true, "DM-04" : true, "DM-05" : true, - "DM-06" : true, "DM-07" : true, "DM-08" : true, "DM-09" : true, "DM-10" : true, - "DO-01" : true, "DO-02" : true, "DO-03" : true, "DO-04" : true, "DO-05" : true, - "DO-06" : true, "DO-07" : true, "DO-08" : true, "DO-09" : true, "DO-10" : true, - "DO-11" : true, "DO-12" : true, "DO-13" : true, "DO-14" : true, "DO-15" : true, - "DO-16" : true, "DO-17" : true, "DO-18" : true, "DO-19" : true, "DO-20" : true, - "DO-21" : true, "DO-22" : true, "DO-23" : true, "DO-24" : true, "DO-25" : true, - "DO-26" : true, "DO-27" : true, "DO-28" : true, "DO-29" : true, "DO-30" : true, - "DZ-01" : true, "DZ-02" : true, "DZ-03" : true, "DZ-04" : true, "DZ-05" : true, - "DZ-06" : true, "DZ-07" : true, "DZ-08" : true, "DZ-09" : true, "DZ-10" : true, - "DZ-11" : true, "DZ-12" : true, "DZ-13" : true, "DZ-14" : true, "DZ-15" : true, - "DZ-16" : true, "DZ-17" : true, "DZ-18" : true, "DZ-19" : true, "DZ-20" : true, - "DZ-21" : true, "DZ-22" : true, "DZ-23" : true, "DZ-24" : true, "DZ-25" : true, - "DZ-26" : true, "DZ-27" : true, "DZ-28" : true, "DZ-29" : true, "DZ-30" : true, - "DZ-31" : true, "DZ-32" : true, "DZ-33" : true, "DZ-34" : true, "DZ-35" : true, - "DZ-36" : true, "DZ-37" : true, "DZ-38" : true, "DZ-39" : true, "DZ-40" : true, - "DZ-41" : true, "DZ-42" : true, "DZ-43" : true, "DZ-44" : true, "DZ-45" : true, - "DZ-46" : true, "DZ-47" : true, "DZ-48" : true, "EC-A" : true, "EC-B" : true, - "EC-C" : true, "EC-D" : true, "EC-E" : true, "EC-F" : true, "EC-G" : true, - "EC-H" : true, "EC-I" : true, "EC-L" : true, "EC-M" : true, "EC-N" : true, - "EC-O" : true, "EC-P" : true, "EC-R" : true, "EC-S" : true, "EC-SD" : true, - "EC-SE" : true, "EC-T" : true, "EC-U" : true, "EC-W" : true, "EC-X" : true, - "EC-Y" : true, "EC-Z" : true, "EE-37" : true, "EE-39" : true, "EE-44" : true, - "EE-49" : true, "EE-51" : true, "EE-57" : true, "EE-59" : true, "EE-65" : true, - "EE-67" : true, "EE-70" : true, "EE-74" : true, "EE-78" : true, "EE-82" : true, - "EE-84" : true, "EE-86" : true, "EG-ALX" : true, "EG-ASN" : true, "EG-AST" : true, - "EG-BA" : true, "EG-BH" : true, "EG-BNS" : true, "EG-C" : true, "EG-DK" : true, - "EG-DT" : true, "EG-FYM" : true, "EG-GH" : true, "EG-GZ" : true, "EG-HU" : true, - "EG-IS" : true, "EG-JS" : true, "EG-KB" : true, "EG-KFS" : true, "EG-KN" : true, - "EG-MN" : true, "EG-MNF" : true, "EG-MT" : true, "EG-PTS" : true, "EG-SHG" : true, - "EG-SHR" : true, "EG-SIN" : true, "EG-SU" : true, "EG-SUZ" : true, "EG-WAD" : true, - "ER-AN" : true, "ER-DK" : true, "ER-DU" : true, "ER-GB" : true, "ER-MA" : true, - "ER-SK" : true, "ES-A" : true, "ES-AB" : true, "ES-AL" : true, "ES-AN" : true, - "ES-AR" : true, "ES-AS" : true, "ES-AV" : true, "ES-B" : true, "ES-BA" : true, - "ES-BI" : true, "ES-BU" : true, "ES-C" : true, "ES-CA" : true, "ES-CB" : true, - "ES-CC" : true, "ES-CE" : true, "ES-CL" : true, "ES-CM" : true, "ES-CN" : true, - "ES-CO" : true, "ES-CR" : true, "ES-CS" : true, "ES-CT" : true, "ES-CU" : true, - "ES-EX" : true, "ES-GA" : true, "ES-GC" : true, "ES-GI" : true, "ES-GR" : true, - "ES-GU" : true, "ES-H" : true, "ES-HU" : true, "ES-IB" : true, "ES-J" : true, - "ES-L" : true, "ES-LE" : true, "ES-LO" : true, "ES-LU" : true, "ES-M" : true, - "ES-MA" : true, "ES-MC" : true, "ES-MD" : true, "ES-ML" : true, "ES-MU" : true, - "ES-NA" : true, "ES-NC" : true, "ES-O" : true, "ES-OR" : true, "ES-P" : true, - "ES-PM" : true, "ES-PO" : true, "ES-PV" : true, "ES-RI" : true, "ES-S" : true, - "ES-SA" : true, "ES-SE" : true, "ES-SG" : true, "ES-SO" : true, "ES-SS" : true, - "ES-T" : true, "ES-TE" : true, "ES-TF" : true, "ES-TO" : true, "ES-V" : true, - "ES-VA" : true, "ES-VC" : true, "ES-VI" : true, "ES-Z" : true, "ES-ZA" : true, - "ET-AA" : true, "ET-AF" : true, "ET-AM" : true, "ET-BE" : true, "ET-DD" : true, - "ET-GA" : true, "ET-HA" : true, "ET-OR" : true, "ET-SN" : true, "ET-SO" : true, - "ET-TI" : true, "FI-01" : true, "FI-02" : true, "FI-03" : true, "FI-04" : true, - "FI-05" : true, "FI-06" : true, "FI-07" : true, "FI-08" : true, "FI-09" : true, - "FI-10" : true, "FI-11" : true, "FI-12" : true, "FI-13" : true, "FI-14" : true, - "FI-15" : true, "FI-16" : true, "FI-17" : true, "FI-18" : true, "FI-19" : true, - "FJ-C" : true, "FJ-E" : true, "FJ-N" : true, "FJ-R" : true, "FJ-W" : true, - "FM-KSA" : true, "FM-PNI" : true, "FM-TRK" : true, "FM-YAP" : true, "FR-01" : true, - "FR-02" : true, "FR-03" : true, "FR-04" : true, "FR-05" : true, "FR-06" : true, - "FR-07" : true, "FR-08" : true, "FR-09" : true, "FR-10" : true, "FR-11" : true, - "FR-12" : true, "FR-13" : true, "FR-14" : true, "FR-15" : true, "FR-16" : true, - "FR-17" : true, "FR-18" : true, "FR-19" : true, "FR-21" : true, "FR-22" : true, - "FR-23" : true, "FR-24" : true, "FR-25" : true, "FR-26" : true, "FR-27" : true, - "FR-28" : true, "FR-29" : true, "FR-2A" : true, "FR-2B" : true, "FR-30" : true, - "FR-31" : true, "FR-32" : true, "FR-33" : true, "FR-34" : true, "FR-35" : true, - "FR-36" : true, "FR-37" : true, "FR-38" : true, "FR-39" : true, "FR-40" : true, - "FR-41" : true, "FR-42" : true, "FR-43" : true, "FR-44" : true, "FR-45" : true, - "FR-46" : true, "FR-47" : true, "FR-48" : true, "FR-49" : true, "FR-50" : true, - "FR-51" : true, "FR-52" : true, "FR-53" : true, "FR-54" : true, "FR-55" : true, - "FR-56" : true, "FR-57" : true, "FR-58" : true, "FR-59" : true, "FR-60" : true, - "FR-61" : true, "FR-62" : true, "FR-63" : true, "FR-64" : true, "FR-65" : true, - "FR-66" : true, "FR-67" : true, "FR-68" : true, "FR-69" : true, "FR-70" : true, - "FR-71" : true, "FR-72" : true, "FR-73" : true, "FR-74" : true, "FR-75" : true, - "FR-76" : true, "FR-77" : true, "FR-78" : true, "FR-79" : true, "FR-80" : true, - "FR-81" : true, "FR-82" : true, "FR-83" : true, "FR-84" : true, "FR-85" : true, - "FR-86" : true, "FR-87" : true, "FR-88" : true, "FR-89" : true, "FR-90" : true, - "FR-91" : true, "FR-92" : true, "FR-93" : true, "FR-94" : true, "FR-95" : true, - "FR-ARA" : true, "FR-BFC" : true, "FR-BL" : true, "FR-BRE" : true, "FR-COR" : true, - "FR-CP" : true, "FR-CVL" : true, "FR-GES" : true, "FR-GF" : true, "FR-GP" : true, - "FR-GUA" : true, "FR-HDF" : true, "FR-IDF" : true, "FR-LRE" : true, "FR-MAY" : true, - "FR-MF" : true, "FR-MQ" : true, "FR-NAQ" : true, "FR-NC" : true, "FR-NOR" : true, - "FR-OCC" : true, "FR-PAC" : true, "FR-PDL" : true, "FR-PF" : true, "FR-PM" : true, - "FR-RE" : true, "FR-TF" : true, "FR-WF" : true, "FR-YT" : true, "GA-1" : true, - "GA-2" : true, "GA-3" : true, "GA-4" : true, "GA-5" : true, "GA-6" : true, - "GA-7" : true, "GA-8" : true, "GA-9" : true, "GB-ABC" : true, "GB-ABD" : true, - "GB-ABE" : true, "GB-AGB" : true, "GB-AGY" : true, "GB-AND" : true, "GB-ANN" : true, - "GB-ANS" : true, "GB-BAS" : true, "GB-BBD" : true, "GB-BDF" : true, "GB-BDG" : true, - "GB-BEN" : true, "GB-BEX" : true, "GB-BFS" : true, "GB-BGE" : true, "GB-BGW" : true, - "GB-BIR" : true, "GB-BKM" : true, "GB-BMH" : true, "GB-BNE" : true, "GB-BNH" : true, - "GB-BNS" : true, "GB-BOL" : true, "GB-BPL" : true, "GB-BRC" : true, "GB-BRD" : true, - "GB-BRY" : true, "GB-BST" : true, "GB-BUR" : true, "GB-CAM" : true, "GB-CAY" : true, - "GB-CBF" : true, "GB-CCG" : true, "GB-CGN" : true, "GB-CHE" : true, "GB-CHW" : true, - "GB-CLD" : true, "GB-CLK" : true, "GB-CMA" : true, "GB-CMD" : true, "GB-CMN" : true, - "GB-CON" : true, "GB-COV" : true, "GB-CRF" : true, "GB-CRY" : true, "GB-CWY" : true, - "GB-DAL" : true, "GB-DBY" : true, "GB-DEN" : true, "GB-DER" : true, "GB-DEV" : true, - "GB-DGY" : true, "GB-DNC" : true, "GB-DND" : true, "GB-DOR" : true, "GB-DRS" : true, - "GB-DUD" : true, "GB-DUR" : true, "GB-EAL" : true, "GB-EAW" : true, "GB-EAY" : true, - "GB-EDH" : true, "GB-EDU" : true, "GB-ELN" : true, "GB-ELS" : true, "GB-ENF" : true, - "GB-ENG" : true, "GB-ERW" : true, "GB-ERY" : true, "GB-ESS" : true, "GB-ESX" : true, - "GB-FAL" : true, "GB-FIF" : true, "GB-FLN" : true, "GB-FMO" : true, "GB-GAT" : true, - "GB-GBN" : true, "GB-GLG" : true, "GB-GLS" : true, "GB-GRE" : true, "GB-GWN" : true, - "GB-HAL" : true, "GB-HAM" : true, "GB-HAV" : true, "GB-HCK" : true, "GB-HEF" : true, - "GB-HIL" : true, "GB-HLD" : true, "GB-HMF" : true, "GB-HNS" : true, "GB-HPL" : true, - "GB-HRT" : true, "GB-HRW" : true, "GB-HRY" : true, "GB-IOS" : true, "GB-IOW" : true, - "GB-ISL" : true, "GB-IVC" : true, "GB-KEC" : true, "GB-KEN" : true, "GB-KHL" : true, - "GB-KIR" : true, "GB-KTT" : true, "GB-KWL" : true, "GB-LAN" : true, "GB-LBC" : true, - "GB-LBH" : true, "GB-LCE" : true, "GB-LDS" : true, "GB-LEC" : true, "GB-LEW" : true, - "GB-LIN" : true, "GB-LIV" : true, "GB-LND" : true, "GB-LUT" : true, "GB-MAN" : true, - "GB-MDB" : true, "GB-MDW" : true, "GB-MEA" : true, "GB-MIK" : true, "GD-01" : true, - "GB-MLN" : true, "GB-MON" : true, "GB-MRT" : true, "GB-MRY" : true, "GB-MTY" : true, - "GB-MUL" : true, "GB-NAY" : true, "GB-NBL" : true, "GB-NEL" : true, "GB-NET" : true, - "GB-NFK" : true, "GB-NGM" : true, "GB-NIR" : true, "GB-NLK" : true, "GB-NLN" : true, - "GB-NMD" : true, "GB-NSM" : true, "GB-NTH" : true, "GB-NTL" : true, "GB-NTT" : true, - "GB-NTY" : true, "GB-NWM" : true, "GB-NWP" : true, "GB-NYK" : true, "GB-OLD" : true, - "GB-ORK" : true, "GB-OXF" : true, "GB-PEM" : true, "GB-PKN" : true, "GB-PLY" : true, - "GB-POL" : true, "GB-POR" : true, "GB-POW" : true, "GB-PTE" : true, "GB-RCC" : true, - "GB-RCH" : true, "GB-RCT" : true, "GB-RDB" : true, "GB-RDG" : true, "GB-RFW" : true, - "GB-RIC" : true, "GB-ROT" : true, "GB-RUT" : true, "GB-SAW" : true, "GB-SAY" : true, - "GB-SCB" : true, "GB-SCT" : true, "GB-SFK" : true, "GB-SFT" : true, "GB-SGC" : true, - "GB-SHF" : true, "GB-SHN" : true, "GB-SHR" : true, "GB-SKP" : true, "GB-SLF" : true, - "GB-SLG" : true, "GB-SLK" : true, "GB-SND" : true, "GB-SOL" : true, "GB-SOM" : true, - "GB-SOS" : true, "GB-SRY" : true, "GB-STE" : true, "GB-STG" : true, "GB-STH" : true, - "GB-STN" : true, "GB-STS" : true, "GB-STT" : true, "GB-STY" : true, "GB-SWA" : true, - "GB-SWD" : true, "GB-SWK" : true, "GB-TAM" : true, "GB-TFW" : true, "GB-THR" : true, - "GB-TOB" : true, "GB-TOF" : true, "GB-TRF" : true, "GB-TWH" : true, "GB-UKM" : true, - "GB-VGL" : true, "GB-WAR" : true, "GB-WBK" : true, "GB-WDU" : true, "GB-WFT" : true, - "GB-WGN" : true, "GB-WIL" : true, "GB-WKF" : true, "GB-WLL" : true, "GB-WLN" : true, - "GB-WLS" : true, "GB-WLV" : true, "GB-WND" : true, "GB-WNM" : true, "GB-WOK" : true, - "GB-WOR" : true, "GB-WRL" : true, "GB-WRT" : true, "GB-WRX" : true, "GB-WSM" : true, - "GB-WSX" : true, "GB-YOR" : true, "GB-ZET" : true, "GD-02" : true, "GD-03" : true, - "GD-04" : true, "GD-05" : true, "GD-06" : true, "GD-10" : true, "GE-AB" : true, - "GE-AJ" : true, "GE-GU" : true, "GE-IM" : true, "GE-KA" : true, "GE-KK" : true, - "GE-MM" : true, "GE-RL" : true, "GE-SJ" : true, "GE-SK" : true, "GE-SZ" : true, - "GE-TB" : true, "GH-AA" : true, "GH-AH" : true, "GH-BA" : true, "GH-CP" : true, - "GH-EP" : true, "GH-NP" : true, "GH-TV" : true, "GH-UE" : true, "GH-UW" : true, - "GH-WP" : true, "GL-KU" : true, "GL-QA" : true, "GL-QE" : true, "GL-SM" : true, - "GM-B" : true, "GM-L" : true, "GM-M" : true, "GM-N" : true, "GM-U" : true, - "GM-W" : true, "GN-B" : true, "GN-BE" : true, "GN-BF" : true, "GN-BK" : true, - "GN-C" : true, "GN-CO" : true, "GN-D" : true, "GN-DB" : true, "GN-DI" : true, - "GN-DL" : true, "GN-DU" : true, "GN-F" : true, "GN-FA" : true, "GN-FO" : true, - "GN-FR" : true, "GN-GA" : true, "GN-GU" : true, "GN-K" : true, "GN-KA" : true, - "GN-KB" : true, "GN-KD" : true, "GN-KE" : true, "GN-KN" : true, "GN-KO" : true, - "GN-KS" : true, "GN-L" : true, "GN-LA" : true, "GN-LE" : true, "GN-LO" : true, - "GN-M" : true, "GN-MC" : true, "GN-MD" : true, "GN-ML" : true, "GN-MM" : true, - "GN-N" : true, "GN-NZ" : true, "GN-PI" : true, "GN-SI" : true, "GN-TE" : true, - "GN-TO" : true, "GN-YO" : true, "GQ-AN" : true, "GQ-BN" : true, "GQ-BS" : true, - "GQ-C" : true, "GQ-CS" : true, "GQ-I" : true, "GQ-KN" : true, "GQ-LI" : true, - "GQ-WN" : true, "GR-01" : true, "GR-03" : true, "GR-04" : true, "GR-05" : true, - "GR-06" : true, "GR-07" : true, "GR-11" : true, "GR-12" : true, "GR-13" : true, - "GR-14" : true, "GR-15" : true, "GR-16" : true, "GR-17" : true, "GR-21" : true, - "GR-22" : true, "GR-23" : true, "GR-24" : true, "GR-31" : true, "GR-32" : true, - "GR-33" : true, "GR-34" : true, "GR-41" : true, "GR-42" : true, "GR-43" : true, - "GR-44" : true, "GR-51" : true, "GR-52" : true, "GR-53" : true, "GR-54" : true, - "GR-55" : true, "GR-56" : true, "GR-57" : true, "GR-58" : true, "GR-59" : true, - "GR-61" : true, "GR-62" : true, "GR-63" : true, "GR-64" : true, "GR-69" : true, - "GR-71" : true, "GR-72" : true, "GR-73" : true, "GR-81" : true, "GR-82" : true, - "GR-83" : true, "GR-84" : true, "GR-85" : true, "GR-91" : true, "GR-92" : true, - "GR-93" : true, "GR-94" : true, "GR-A" : true, "GR-A1" : true, "GR-B" : true, - "GR-C" : true, "GR-D" : true, "GR-E" : true, "GR-F" : true, "GR-G" : true, - "GR-H" : true, "GR-I" : true, "GR-J" : true, "GR-K" : true, "GR-L" : true, - "GR-M" : true, "GT-AV" : true, "GT-BV" : true, "GT-CM" : true, "GT-CQ" : true, - "GT-ES" : true, "GT-GU" : true, "GT-HU" : true, "GT-IZ" : true, "GT-JA" : true, - "GT-JU" : true, "GT-PE" : true, "GT-PR" : true, "GT-QC" : true, "GT-QZ" : true, - "GT-RE" : true, "GT-SA" : true, "GT-SM" : true, "GT-SO" : true, "GT-SR" : true, - "GT-SU" : true, "GT-TO" : true, "GT-ZA" : true, "GW-BA" : true, "GW-BL" : true, - "GW-BM" : true, "GW-BS" : true, "GW-CA" : true, "GW-GA" : true, "GW-L" : true, - "GW-N" : true, "GW-OI" : true, "GW-QU" : true, "GW-S" : true, "GW-TO" : true, - "GY-BA" : true, "GY-CU" : true, "GY-DE" : true, "GY-EB" : true, "GY-ES" : true, - "GY-MA" : true, "GY-PM" : true, "GY-PT" : true, "GY-UD" : true, "GY-UT" : true, - "HN-AT" : true, "HN-CH" : true, "HN-CL" : true, "HN-CM" : true, "HN-CP" : true, - "HN-CR" : true, "HN-EP" : true, "HN-FM" : true, "HN-GD" : true, "HN-IB" : true, - "HN-IN" : true, "HN-LE" : true, "HN-LP" : true, "HN-OC" : true, "HN-OL" : true, - "HN-SB" : true, "HN-VA" : true, "HN-YO" : true, "HR-01" : true, "HR-02" : true, - "HR-03" : true, "HR-04" : true, "HR-05" : true, "HR-06" : true, "HR-07" : true, - "HR-08" : true, "HR-09" : true, "HR-10" : true, "HR-11" : true, "HR-12" : true, - "HR-13" : true, "HR-14" : true, "HR-15" : true, "HR-16" : true, "HR-17" : true, - "HR-18" : true, "HR-19" : true, "HR-20" : true, "HR-21" : true, "HT-AR" : true, - "HT-CE" : true, "HT-GA" : true, "HT-ND" : true, "HT-NE" : true, "HT-NO" : true, - "HT-OU" : true, "HT-SD" : true, "HT-SE" : true, "HU-BA" : true, "HU-BC" : true, - "HU-BE" : true, "HU-BK" : true, "HU-BU" : true, "HU-BZ" : true, "HU-CS" : true, - "HU-DE" : true, "HU-DU" : true, "HU-EG" : true, "HU-ER" : true, "HU-FE" : true, - "HU-GS" : true, "HU-GY" : true, "HU-HB" : true, "HU-HE" : true, "HU-HV" : true, - "HU-JN" : true, "HU-KE" : true, "HU-KM" : true, "HU-KV" : true, "HU-MI" : true, - "HU-NK" : true, "HU-NO" : true, "HU-NY" : true, "HU-PE" : true, "HU-PS" : true, - "HU-SD" : true, "HU-SF" : true, "HU-SH" : true, "HU-SK" : true, "HU-SN" : true, - "HU-SO" : true, "HU-SS" : true, "HU-ST" : true, "HU-SZ" : true, "HU-TB" : true, - "HU-TO" : true, "HU-VA" : true, "HU-VE" : true, "HU-VM" : true, "HU-ZA" : true, - "HU-ZE" : true, "ID-AC" : true, "ID-BA" : true, "ID-BB" : true, "ID-BE" : true, - "ID-BT" : true, "ID-GO" : true, "ID-IJ" : true, "ID-JA" : true, "ID-JB" : true, - "ID-JI" : true, "ID-JK" : true, "ID-JT" : true, "ID-JW" : true, "ID-KA" : true, - "ID-KB" : true, "ID-KI" : true, "ID-KR" : true, "ID-KS" : true, "ID-KT" : true, - "ID-LA" : true, "ID-MA" : true, "ID-ML" : true, "ID-MU" : true, "ID-NB" : true, - "ID-NT" : true, "ID-NU" : true, "ID-PA" : true, "ID-PB" : true, "ID-RI" : true, - "ID-SA" : true, "ID-SB" : true, "ID-SG" : true, "ID-SL" : true, "ID-SM" : true, - "ID-SN" : true, "ID-SR" : true, "ID-SS" : true, "ID-ST" : true, "ID-SU" : true, - "ID-YO" : true, "IE-C" : true, "IE-CE" : true, "IE-CN" : true, "IE-CO" : true, - "IE-CW" : true, "IE-D" : true, "IE-DL" : true, "IE-G" : true, "IE-KE" : true, - "IE-KK" : true, "IE-KY" : true, "IE-L" : true, "IE-LD" : true, "IE-LH" : true, - "IE-LK" : true, "IE-LM" : true, "IE-LS" : true, "IE-M" : true, "IE-MH" : true, - "IE-MN" : true, "IE-MO" : true, "IE-OY" : true, "IE-RN" : true, "IE-SO" : true, - "IE-TA" : true, "IE-U" : true, "IE-WD" : true, "IE-WH" : true, "IE-WW" : true, - "IE-WX" : true, "IL-D" : true, "IL-HA" : true, "IL-JM" : true, "IL-M" : true, - "IL-TA" : true, "IL-Z" : true, "IN-AN" : true, "IN-AP" : true, "IN-AR" : true, - "IN-AS" : true, "IN-BR" : true, "IN-CH" : true, "IN-CT" : true, "IN-DD" : true, - "IN-DL" : true, "IN-DN" : true, "IN-GA" : true, "IN-GJ" : true, "IN-HP" : true, - "IN-HR" : true, "IN-JH" : true, "IN-JK" : true, "IN-KA" : true, "IN-KL" : true, - "IN-LD" : true, "IN-MH" : true, "IN-ML" : true, "IN-MN" : true, "IN-MP" : true, - "IN-MZ" : true, "IN-NL" : true, "IN-OR" : true, "IN-PB" : true, "IN-PY" : true, - "IN-RJ" : true, "IN-SK" : true, "IN-TN" : true, "IN-TR" : true, "IN-UP" : true, - "IN-UT" : true, "IN-WB" : true, "IQ-AN" : true, "IQ-AR" : true, "IQ-BA" : true, - "IQ-BB" : true, "IQ-BG" : true, "IQ-DA" : true, "IQ-DI" : true, "IQ-DQ" : true, - "IQ-KA" : true, "IQ-MA" : true, "IQ-MU" : true, "IQ-NA" : true, "IQ-NI" : true, - "IQ-QA" : true, "IQ-SD" : true, "IQ-SW" : true, "IQ-TS" : true, "IQ-WA" : true, - "IR-01" : true, "IR-02" : true, "IR-03" : true, "IR-04" : true, "IR-05" : true, - "IR-06" : true, "IR-07" : true, "IR-08" : true, "IR-10" : true, "IR-11" : true, - "IR-12" : true, "IR-13" : true, "IR-14" : true, "IR-15" : true, "IR-16" : true, - "IR-17" : true, "IR-18" : true, "IR-19" : true, "IR-20" : true, "IR-21" : true, - "IR-22" : true, "IR-23" : true, "IR-24" : true, "IR-25" : true, "IR-26" : true, - "IR-27" : true, "IR-28" : true, "IR-29" : true, "IR-30" : true, "IR-31" : true, - "IS-0" : true, "IS-1" : true, "IS-2" : true, "IS-3" : true, "IS-4" : true, - "IS-5" : true, "IS-6" : true, "IS-7" : true, "IS-8" : true, "IT-21" : true, - "IT-23" : true, "IT-25" : true, "IT-32" : true, "IT-34" : true, "IT-36" : true, - "IT-42" : true, "IT-45" : true, "IT-52" : true, "IT-55" : true, "IT-57" : true, - "IT-62" : true, "IT-65" : true, "IT-67" : true, "IT-72" : true, "IT-75" : true, - "IT-77" : true, "IT-78" : true, "IT-82" : true, "IT-88" : true, "IT-AG" : true, - "IT-AL" : true, "IT-AN" : true, "IT-AO" : true, "IT-AP" : true, "IT-AQ" : true, - "IT-AR" : true, "IT-AT" : true, "IT-AV" : true, "IT-BA" : true, "IT-BG" : true, - "IT-BI" : true, "IT-BL" : true, "IT-BN" : true, "IT-BO" : true, "IT-BR" : true, - "IT-BS" : true, "IT-BT" : true, "IT-BZ" : true, "IT-CA" : true, "IT-CB" : true, - "IT-CE" : true, "IT-CH" : true, "IT-CI" : true, "IT-CL" : true, "IT-CN" : true, - "IT-CO" : true, "IT-CR" : true, "IT-CS" : true, "IT-CT" : true, "IT-CZ" : true, - "IT-EN" : true, "IT-FC" : true, "IT-FE" : true, "IT-FG" : true, "IT-FI" : true, - "IT-FM" : true, "IT-FR" : true, "IT-GE" : true, "IT-GO" : true, "IT-GR" : true, - "IT-IM" : true, "IT-IS" : true, "IT-KR" : true, "IT-LC" : true, "IT-LE" : true, - "IT-LI" : true, "IT-LO" : true, "IT-LT" : true, "IT-LU" : true, "IT-MB" : true, - "IT-MC" : true, "IT-ME" : true, "IT-MI" : true, "IT-MN" : true, "IT-MO" : true, - "IT-MS" : true, "IT-MT" : true, "IT-NA" : true, "IT-NO" : true, "IT-NU" : true, - "IT-OG" : true, "IT-OR" : true, "IT-OT" : true, "IT-PA" : true, "IT-PC" : true, - "IT-PD" : true, "IT-PE" : true, "IT-PG" : true, "IT-PI" : true, "IT-PN" : true, - "IT-PO" : true, "IT-PR" : true, "IT-PT" : true, "IT-PU" : true, "IT-PV" : true, - "IT-PZ" : true, "IT-RA" : true, "IT-RC" : true, "IT-RE" : true, "IT-RG" : true, - "IT-RI" : true, "IT-RM" : true, "IT-RN" : true, "IT-RO" : true, "IT-SA" : true, - "IT-SI" : true, "IT-SO" : true, "IT-SP" : true, "IT-SR" : true, "IT-SS" : true, - "IT-SV" : true, "IT-TA" : true, "IT-TE" : true, "IT-TN" : true, "IT-TO" : true, - "IT-TP" : true, "IT-TR" : true, "IT-TS" : true, "IT-TV" : true, "IT-UD" : true, - "IT-VA" : true, "IT-VB" : true, "IT-VC" : true, "IT-VE" : true, "IT-VI" : true, - "IT-VR" : true, "IT-VS" : true, "IT-VT" : true, "IT-VV" : true, "JM-01" : true, - "JM-02" : true, "JM-03" : true, "JM-04" : true, "JM-05" : true, "JM-06" : true, - "JM-07" : true, "JM-08" : true, "JM-09" : true, "JM-10" : true, "JM-11" : true, - "JM-12" : true, "JM-13" : true, "JM-14" : true, "JO-AJ" : true, "JO-AM" : true, - "JO-AQ" : true, "JO-AT" : true, "JO-AZ" : true, "JO-BA" : true, "JO-IR" : true, - "JO-JA" : true, "JO-KA" : true, "JO-MA" : true, "JO-MD" : true, "JO-MN" : true, - "JP-01" : true, "JP-02" : true, "JP-03" : true, "JP-04" : true, "JP-05" : true, - "JP-06" : true, "JP-07" : true, "JP-08" : true, "JP-09" : true, "JP-10" : true, - "JP-11" : true, "JP-12" : true, "JP-13" : true, "JP-14" : true, "JP-15" : true, - "JP-16" : true, "JP-17" : true, "JP-18" : true, "JP-19" : true, "JP-20" : true, - "JP-21" : true, "JP-22" : true, "JP-23" : true, "JP-24" : true, "JP-25" : true, - "JP-26" : true, "JP-27" : true, "JP-28" : true, "JP-29" : true, "JP-30" : true, - "JP-31" : true, "JP-32" : true, "JP-33" : true, "JP-34" : true, "JP-35" : true, - "JP-36" : true, "JP-37" : true, "JP-38" : true, "JP-39" : true, "JP-40" : true, - "JP-41" : true, "JP-42" : true, "JP-43" : true, "JP-44" : true, "JP-45" : true, - "JP-46" : true, "JP-47" : true, "KE-110" : true, "KE-200" : true, "KE-300" : true, - "KE-400" : true, "KE-500" : true, "KE-700" : true, "KE-800" : true, "KG-B" : true, - "KG-C" : true, "KG-GB" : true, "KG-J" : true, "KG-N" : true, "KG-O" : true, - "KG-T" : true, "KG-Y" : true, "KH-1" : true, "KH-10" : true, "KH-11" : true, - "KH-12" : true, "KH-13" : true, "KH-14" : true, "KH-15" : true, "KH-16" : true, - "KH-17" : true, "KH-18" : true, "KH-19" : true, "KH-2" : true, "KH-20" : true, - "KH-21" : true, "KH-22" : true, "KH-23" : true, "KH-24" : true, "KH-3" : true, - "KH-4" : true, "KH-5" : true, "KH-6" : true, "KH-7" : true, "KH-8" : true, - "KH-9" : true, "KI-G" : true, "KI-L" : true, "KI-P" : true, "KM-A" : true, - "KM-G" : true, "KM-M" : true, "KN-01" : true, "KN-02" : true, "KN-03" : true, - "KN-04" : true, "KN-05" : true, "KN-06" : true, "KN-07" : true, "KN-08" : true, - "KN-09" : true, "KN-10" : true, "KN-11" : true, "KN-12" : true, "KN-13" : true, - "KN-15" : true, "KN-K" : true, "KN-N" : true, "KP-01" : true, "KP-02" : true, - "KP-03" : true, "KP-04" : true, "KP-05" : true, "KP-06" : true, "KP-07" : true, - "KP-08" : true, "KP-09" : true, "KP-10" : true, "KP-13" : true, "KR-11" : true, - "KR-26" : true, "KR-27" : true, "KR-28" : true, "KR-29" : true, "KR-30" : true, - "KR-31" : true, "KR-41" : true, "KR-42" : true, "KR-43" : true, "KR-44" : true, - "KR-45" : true, "KR-46" : true, "KR-47" : true, "KR-48" : true, "KR-49" : true, - "KW-AH" : true, "KW-FA" : true, "KW-HA" : true, "KW-JA" : true, "KW-KU" : true, - "KW-MU" : true, "KZ-AKM" : true, "KZ-AKT" : true, "KZ-ALA" : true, "KZ-ALM" : true, - "KZ-AST" : true, "KZ-ATY" : true, "KZ-KAR" : true, "KZ-KUS" : true, "KZ-KZY" : true, - "KZ-MAN" : true, "KZ-PAV" : true, "KZ-SEV" : true, "KZ-VOS" : true, "KZ-YUZ" : true, - "KZ-ZAP" : true, "KZ-ZHA" : true, "LA-AT" : true, "LA-BK" : true, "LA-BL" : true, - "LA-CH" : true, "LA-HO" : true, "LA-KH" : true, "LA-LM" : true, "LA-LP" : true, - "LA-OU" : true, "LA-PH" : true, "LA-SL" : true, "LA-SV" : true, "LA-VI" : true, - "LA-VT" : true, "LA-XA" : true, "LA-XE" : true, "LA-XI" : true, "LA-XS" : true, - "LB-AK" : true, "LB-AS" : true, "LB-BA" : true, "LB-BH" : true, "LB-BI" : true, - "LB-JA" : true, "LB-JL" : true, "LB-NA" : true, "LI-01" : true, "LI-02" : true, - "LI-03" : true, "LI-04" : true, "LI-05" : true, "LI-06" : true, "LI-07" : true, - "LI-08" : true, "LI-09" : true, "LI-10" : true, "LI-11" : true, "LK-1" : true, - "LK-11" : true, "LK-12" : true, "LK-13" : true, "LK-2" : true, "LK-21" : true, - "LK-22" : true, "LK-23" : true, "LK-3" : true, "LK-31" : true, "LK-32" : true, - "LK-33" : true, "LK-4" : true, "LK-41" : true, "LK-42" : true, "LK-43" : true, - "LK-44" : true, "LK-45" : true, "LK-5" : true, "LK-51" : true, "LK-52" : true, - "LK-53" : true, "LK-6" : true, "LK-61" : true, "LK-62" : true, "LK-7" : true, - "LK-71" : true, "LK-72" : true, "LK-8" : true, "LK-81" : true, "LK-82" : true, - "LK-9" : true, "LK-91" : true, "LK-92" : true, "LR-BG" : true, "LR-BM" : true, - "LR-CM" : true, "LR-GB" : true, "LR-GG" : true, "LR-GK" : true, "LR-LO" : true, - "LR-MG" : true, "LR-MO" : true, "LR-MY" : true, "LR-NI" : true, "LR-RI" : true, - "LR-SI" : true, "LS-A" : true, "LS-B" : true, "LS-C" : true, "LS-D" : true, - "LS-E" : true, "LS-F" : true, "LS-G" : true, "LS-H" : true, "LS-J" : true, - "LS-K" : true, "LT-AL" : true, "LT-KL" : true, "LT-KU" : true, "LT-MR" : true, - "LT-PN" : true, "LT-SA" : true, "LT-TA" : true, "LT-TE" : true, "LT-UT" : true, - "LT-VL" : true, "LU-D" : true, "LU-G" : true, "LU-L" : true, "LV-001" : true, - "LV-002" : true, "LV-003" : true, "LV-004" : true, "LV-005" : true, "LV-006" : true, - "LV-007" : true, "LV-008" : true, "LV-009" : true, "LV-010" : true, "LV-011" : true, - "LV-012" : true, "LV-013" : true, "LV-014" : true, "LV-015" : true, "LV-016" : true, - "LV-017" : true, "LV-018" : true, "LV-019" : true, "LV-020" : true, "LV-021" : true, - "LV-022" : true, "LV-023" : true, "LV-024" : true, "LV-025" : true, "LV-026" : true, - "LV-027" : true, "LV-028" : true, "LV-029" : true, "LV-030" : true, "LV-031" : true, - "LV-032" : true, "LV-033" : true, "LV-034" : true, "LV-035" : true, "LV-036" : true, - "LV-037" : true, "LV-038" : true, "LV-039" : true, "LV-040" : true, "LV-041" : true, - "LV-042" : true, "LV-043" : true, "LV-044" : true, "LV-045" : true, "LV-046" : true, - "LV-047" : true, "LV-048" : true, "LV-049" : true, "LV-050" : true, "LV-051" : true, - "LV-052" : true, "LV-053" : true, "LV-054" : true, "LV-055" : true, "LV-056" : true, - "LV-057" : true, "LV-058" : true, "LV-059" : true, "LV-060" : true, "LV-061" : true, - "LV-062" : true, "LV-063" : true, "LV-064" : true, "LV-065" : true, "LV-066" : true, - "LV-067" : true, "LV-068" : true, "LV-069" : true, "LV-070" : true, "LV-071" : true, - "LV-072" : true, "LV-073" : true, "LV-074" : true, "LV-075" : true, "LV-076" : true, - "LV-077" : true, "LV-078" : true, "LV-079" : true, "LV-080" : true, "LV-081" : true, - "LV-082" : true, "LV-083" : true, "LV-084" : true, "LV-085" : true, "LV-086" : true, - "LV-087" : true, "LV-088" : true, "LV-089" : true, "LV-090" : true, "LV-091" : true, - "LV-092" : true, "LV-093" : true, "LV-094" : true, "LV-095" : true, "LV-096" : true, - "LV-097" : true, "LV-098" : true, "LV-099" : true, "LV-100" : true, "LV-101" : true, - "LV-102" : true, "LV-103" : true, "LV-104" : true, "LV-105" : true, "LV-106" : true, - "LV-107" : true, "LV-108" : true, "LV-109" : true, "LV-110" : true, "LV-DGV" : true, - "LV-JEL" : true, "LV-JKB" : true, "LV-JUR" : true, "LV-LPX" : true, "LV-REZ" : true, - "LV-RIX" : true, "LV-VEN" : true, "LV-VMR" : true, "LY-BA" : true, "LY-BU" : true, - "LY-DR" : true, "LY-GT" : true, "LY-JA" : true, "LY-JB" : true, "LY-JG" : true, - "LY-JI" : true, "LY-JU" : true, "LY-KF" : true, "LY-MB" : true, "LY-MI" : true, - "LY-MJ" : true, "LY-MQ" : true, "LY-NL" : true, "LY-NQ" : true, "LY-SB" : true, - "LY-SR" : true, "LY-TB" : true, "LY-WA" : true, "LY-WD" : true, "LY-WS" : true, - "LY-ZA" : true, "MA-01" : true, "MA-02" : true, "MA-03" : true, "MA-04" : true, - "MA-05" : true, "MA-06" : true, "MA-07" : true, "MA-08" : true, "MA-09" : true, - "MA-10" : true, "MA-11" : true, "MA-12" : true, "MA-13" : true, "MA-14" : true, - "MA-15" : true, "MA-16" : true, "MA-AGD" : true, "MA-AOU" : true, "MA-ASZ" : true, - "MA-AZI" : true, "MA-BEM" : true, "MA-BER" : true, "MA-BES" : true, "MA-BOD" : true, - "MA-BOM" : true, "MA-CAS" : true, "MA-CHE" : true, "MA-CHI" : true, "MA-CHT" : true, - "MA-ERR" : true, "MA-ESI" : true, "MA-ESM" : true, "MA-FAH" : true, "MA-FES" : true, - "MA-FIG" : true, "MA-GUE" : true, "MA-HAJ" : true, "MA-HAO" : true, "MA-HOC" : true, - "MA-IFR" : true, "MA-INE" : true, "MA-JDI" : true, "MA-JRA" : true, "MA-KEN" : true, - "MA-KES" : true, "MA-KHE" : true, "MA-KHN" : true, "MA-KHO" : true, "MA-LAA" : true, - "MA-LAR" : true, "MA-MED" : true, "MA-MEK" : true, "MA-MMD" : true, "MA-MMN" : true, - "MA-MOH" : true, "MA-MOU" : true, "MA-NAD" : true, "MA-NOU" : true, "MA-OUA" : true, - "MA-OUD" : true, "MA-OUJ" : true, "MA-RAB" : true, "MA-SAF" : true, "MA-SAL" : true, - "MA-SEF" : true, "MA-SET" : true, "MA-SIK" : true, "MA-SKH" : true, "MA-SYB" : true, - "MA-TAI" : true, "MA-TAO" : true, "MA-TAR" : true, "MA-TAT" : true, "MA-TAZ" : true, - "MA-TET" : true, "MA-TIZ" : true, "MA-TNG" : true, "MA-TNT" : true, "MA-ZAG" : true, - "MC-CL" : true, "MC-CO" : true, "MC-FO" : true, "MC-GA" : true, "MC-JE" : true, - "MC-LA" : true, "MC-MA" : true, "MC-MC" : true, "MC-MG" : true, "MC-MO" : true, - "MC-MU" : true, "MC-PH" : true, "MC-SD" : true, "MC-SO" : true, "MC-SP" : true, - "MC-SR" : true, "MC-VR" : true, "MD-AN" : true, "MD-BA" : true, "MD-BD" : true, - "MD-BR" : true, "MD-BS" : true, "MD-CA" : true, "MD-CL" : true, "MD-CM" : true, - "MD-CR" : true, "MD-CS" : true, "MD-CT" : true, "MD-CU" : true, "MD-DO" : true, - "MD-DR" : true, "MD-DU" : true, "MD-ED" : true, "MD-FA" : true, "MD-FL" : true, - "MD-GA" : true, "MD-GL" : true, "MD-HI" : true, "MD-IA" : true, "MD-LE" : true, - "MD-NI" : true, "MD-OC" : true, "MD-OR" : true, "MD-RE" : true, "MD-RI" : true, - "MD-SD" : true, "MD-SI" : true, "MD-SN" : true, "MD-SO" : true, "MD-ST" : true, - "MD-SV" : true, "MD-TA" : true, "MD-TE" : true, "MD-UN" : true, "ME-01" : true, - "ME-02" : true, "ME-03" : true, "ME-04" : true, "ME-05" : true, "ME-06" : true, - "ME-07" : true, "ME-08" : true, "ME-09" : true, "ME-10" : true, "ME-11" : true, - "ME-12" : true, "ME-13" : true, "ME-14" : true, "ME-15" : true, "ME-16" : true, - "ME-17" : true, "ME-18" : true, "ME-19" : true, "ME-20" : true, "ME-21" : true, - "MG-A" : true, "MG-D" : true, "MG-F" : true, "MG-M" : true, "MG-T" : true, - "MG-U" : true, "MH-ALK" : true, "MH-ALL" : true, "MH-ARN" : true, "MH-AUR" : true, - "MH-EBO" : true, "MH-ENI" : true, "MH-JAB" : true, "MH-JAL" : true, "MH-KIL" : true, - "MH-KWA" : true, "MH-L" : true, "MH-LAE" : true, "MH-LIB" : true, "MH-LIK" : true, - "MH-MAJ" : true, "MH-MAL" : true, "MH-MEJ" : true, "MH-MIL" : true, "MH-NMK" : true, - "MH-NMU" : true, "MH-RON" : true, "MH-T" : true, "MH-UJA" : true, "MH-UTI" : true, - "MH-WTJ" : true, "MH-WTN" : true, "MK-01" : true, "MK-02" : true, "MK-03" : true, - "MK-04" : true, "MK-05" : true, "MK-06" : true, "MK-07" : true, "MK-08" : true, - "MK-09" : true, "MK-10" : true, "MK-11" : true, "MK-12" : true, "MK-13" : true, - "MK-14" : true, "MK-15" : true, "MK-16" : true, "MK-17" : true, "MK-18" : true, - "MK-19" : true, "MK-20" : true, "MK-21" : true, "MK-22" : true, "MK-23" : true, - "MK-24" : true, "MK-25" : true, "MK-26" : true, "MK-27" : true, "MK-28" : true, - "MK-29" : true, "MK-30" : true, "MK-31" : true, "MK-32" : true, "MK-33" : true, - "MK-34" : true, "MK-35" : true, "MK-36" : true, "MK-37" : true, "MK-38" : true, - "MK-39" : true, "MK-40" : true, "MK-41" : true, "MK-42" : true, "MK-43" : true, - "MK-44" : true, "MK-45" : true, "MK-46" : true, "MK-47" : true, "MK-48" : true, - "MK-49" : true, "MK-50" : true, "MK-51" : true, "MK-52" : true, "MK-53" : true, - "MK-54" : true, "MK-55" : true, "MK-56" : true, "MK-57" : true, "MK-58" : true, - "MK-59" : true, "MK-60" : true, "MK-61" : true, "MK-62" : true, "MK-63" : true, - "MK-64" : true, "MK-65" : true, "MK-66" : true, "MK-67" : true, "MK-68" : true, - "MK-69" : true, "MK-70" : true, "MK-71" : true, "MK-72" : true, "MK-73" : true, - "MK-74" : true, "MK-75" : true, "MK-76" : true, "MK-77" : true, "MK-78" : true, - "MK-79" : true, "MK-80" : true, "MK-81" : true, "MK-82" : true, "MK-83" : true, - "MK-84" : true, "ML-1" : true, "ML-2" : true, "ML-3" : true, "ML-4" : true, - "ML-5" : true, "ML-6" : true, "ML-7" : true, "ML-8" : true, "ML-BK0" : true, - "MM-01" : true, "MM-02" : true, "MM-03" : true, "MM-04" : true, "MM-05" : true, - "MM-06" : true, "MM-07" : true, "MM-11" : true, "MM-12" : true, "MM-13" : true, - "MM-14" : true, "MM-15" : true, "MM-16" : true, "MM-17" : true, "MN-035" : true, - "MN-037" : true, "MN-039" : true, "MN-041" : true, "MN-043" : true, "MN-046" : true, - "MN-047" : true, "MN-049" : true, "MN-051" : true, "MN-053" : true, "MN-055" : true, - "MN-057" : true, "MN-059" : true, "MN-061" : true, "MN-063" : true, "MN-064" : true, - "MN-065" : true, "MN-067" : true, "MN-069" : true, "MN-071" : true, "MN-073" : true, - "MN-1" : true, "MR-01" : true, "MR-02" : true, "MR-03" : true, "MR-04" : true, - "MR-05" : true, "MR-06" : true, "MR-07" : true, "MR-08" : true, "MR-09" : true, - "MR-10" : true, "MR-11" : true, "MR-12" : true, "MR-NKC" : true, "MT-01" : true, - "MT-02" : true, "MT-03" : true, "MT-04" : true, "MT-05" : true, "MT-06" : true, - "MT-07" : true, "MT-08" : true, "MT-09" : true, "MT-10" : true, "MT-11" : true, - "MT-12" : true, "MT-13" : true, "MT-14" : true, "MT-15" : true, "MT-16" : true, - "MT-17" : true, "MT-18" : true, "MT-19" : true, "MT-20" : true, "MT-21" : true, - "MT-22" : true, "MT-23" : true, "MT-24" : true, "MT-25" : true, "MT-26" : true, - "MT-27" : true, "MT-28" : true, "MT-29" : true, "MT-30" : true, "MT-31" : true, - "MT-32" : true, "MT-33" : true, "MT-34" : true, "MT-35" : true, "MT-36" : true, - "MT-37" : true, "MT-38" : true, "MT-39" : true, "MT-40" : true, "MT-41" : true, - "MT-42" : true, "MT-43" : true, "MT-44" : true, "MT-45" : true, "MT-46" : true, - "MT-47" : true, "MT-48" : true, "MT-49" : true, "MT-50" : true, "MT-51" : true, - "MT-52" : true, "MT-53" : true, "MT-54" : true, "MT-55" : true, "MT-56" : true, - "MT-57" : true, "MT-58" : true, "MT-59" : true, "MT-60" : true, "MT-61" : true, - "MT-62" : true, "MT-63" : true, "MT-64" : true, "MT-65" : true, "MT-66" : true, - "MT-67" : true, "MT-68" : true, "MU-AG" : true, "MU-BL" : true, "MU-BR" : true, - "MU-CC" : true, "MU-CU" : true, "MU-FL" : true, "MU-GP" : true, "MU-MO" : true, - "MU-PA" : true, "MU-PL" : true, "MU-PU" : true, "MU-PW" : true, "MU-QB" : true, - "MU-RO" : true, "MU-RP" : true, "MU-SA" : true, "MU-VP" : true, "MV-00" : true, - "MV-01" : true, "MV-02" : true, "MV-03" : true, "MV-04" : true, "MV-05" : true, - "MV-07" : true, "MV-08" : true, "MV-12" : true, "MV-13" : true, "MV-14" : true, - "MV-17" : true, "MV-20" : true, "MV-23" : true, "MV-24" : true, "MV-25" : true, - "MV-26" : true, "MV-27" : true, "MV-28" : true, "MV-29" : true, "MV-CE" : true, - "MV-MLE" : true, "MV-NC" : true, "MV-NO" : true, "MV-SC" : true, "MV-SU" : true, - "MV-UN" : true, "MV-US" : true, "MW-BA" : true, "MW-BL" : true, "MW-C" : true, - "MW-CK" : true, "MW-CR" : true, "MW-CT" : true, "MW-DE" : true, "MW-DO" : true, - "MW-KR" : true, "MW-KS" : true, "MW-LI" : true, "MW-LK" : true, "MW-MC" : true, - "MW-MG" : true, "MW-MH" : true, "MW-MU" : true, "MW-MW" : true, "MW-MZ" : true, - "MW-N" : true, "MW-NB" : true, "MW-NE" : true, "MW-NI" : true, "MW-NK" : true, - "MW-NS" : true, "MW-NU" : true, "MW-PH" : true, "MW-RU" : true, "MW-S" : true, - "MW-SA" : true, "MW-TH" : true, "MW-ZO" : true, "MX-AGU" : true, "MX-BCN" : true, - "MX-BCS" : true, "MX-CAM" : true, "MX-CHH" : true, "MX-CHP" : true, "MX-COA" : true, - "MX-COL" : true, "MX-DIF" : true, "MX-DUR" : true, "MX-GRO" : true, "MX-GUA" : true, - "MX-HID" : true, "MX-JAL" : true, "MX-MEX" : true, "MX-MIC" : true, "MX-MOR" : true, - "MX-NAY" : true, "MX-NLE" : true, "MX-OAX" : true, "MX-PUE" : true, "MX-QUE" : true, - "MX-ROO" : true, "MX-SIN" : true, "MX-SLP" : true, "MX-SON" : true, "MX-TAB" : true, - "MX-TAM" : true, "MX-TLA" : true, "MX-VER" : true, "MX-YUC" : true, "MX-ZAC" : true, - "MY-01" : true, "MY-02" : true, "MY-03" : true, "MY-04" : true, "MY-05" : true, - "MY-06" : true, "MY-07" : true, "MY-08" : true, "MY-09" : true, "MY-10" : true, - "MY-11" : true, "MY-12" : true, "MY-13" : true, "MY-14" : true, "MY-15" : true, - "MY-16" : true, "MZ-A" : true, "MZ-B" : true, "MZ-G" : true, "MZ-I" : true, - "MZ-L" : true, "MZ-MPM" : true, "MZ-N" : true, "MZ-P" : true, "MZ-Q" : true, - "MZ-S" : true, "MZ-T" : true, "NA-CA" : true, "NA-ER" : true, "NA-HA" : true, - "NA-KA" : true, "NA-KH" : true, "NA-KU" : true, "NA-OD" : true, "NA-OH" : true, - "NA-OK" : true, "NA-ON" : true, "NA-OS" : true, "NA-OT" : true, "NA-OW" : true, - "NE-1" : true, "NE-2" : true, "NE-3" : true, "NE-4" : true, "NE-5" : true, - "NE-6" : true, "NE-7" : true, "NE-8" : true, "NG-AB" : true, "NG-AD" : true, - "NG-AK" : true, "NG-AN" : true, "NG-BA" : true, "NG-BE" : true, "NG-BO" : true, - "NG-BY" : true, "NG-CR" : true, "NG-DE" : true, "NG-EB" : true, "NG-ED" : true, - "NG-EK" : true, "NG-EN" : true, "NG-FC" : true, "NG-GO" : true, "NG-IM" : true, - "NG-JI" : true, "NG-KD" : true, "NG-KE" : true, "NG-KN" : true, "NG-KO" : true, - "NG-KT" : true, "NG-KW" : true, "NG-LA" : true, "NG-NA" : true, "NG-NI" : true, - "NG-OG" : true, "NG-ON" : true, "NG-OS" : true, "NG-OY" : true, "NG-PL" : true, - "NG-RI" : true, "NG-SO" : true, "NG-TA" : true, "NG-YO" : true, "NG-ZA" : true, - "NI-AN" : true, "NI-AS" : true, "NI-BO" : true, "NI-CA" : true, "NI-CI" : true, - "NI-CO" : true, "NI-ES" : true, "NI-GR" : true, "NI-JI" : true, "NI-LE" : true, - "NI-MD" : true, "NI-MN" : true, "NI-MS" : true, "NI-MT" : true, "NI-NS" : true, - "NI-RI" : true, "NI-SJ" : true, "NL-AW" : true, "NL-BQ1" : true, "NL-BQ2" : true, - "NL-BQ3" : true, "NL-CW" : true, "NL-DR" : true, "NL-FL" : true, "NL-FR" : true, - "NL-GE" : true, "NL-GR" : true, "NL-LI" : true, "NL-NB" : true, "NL-NH" : true, - "NL-OV" : true, "NL-SX" : true, "NL-UT" : true, "NL-ZE" : true, "NL-ZH" : true, - "NO-01" : true, "NO-02" : true, "NO-03" : true, "NO-04" : true, "NO-05" : true, - "NO-06" : true, "NO-07" : true, "NO-08" : true, "NO-09" : true, "NO-10" : true, - "NO-11" : true, "NO-12" : true, "NO-14" : true, "NO-15" : true, "NO-16" : true, - "NO-17" : true, "NO-18" : true, "NO-19" : true, "NO-20" : true, "NO-21" : true, - "NO-22" : true, "NP-1" : true, "NP-2" : true, "NP-3" : true, "NP-4" : true, - "NP-5" : true, "NP-BA" : true, "NP-BH" : true, "NP-DH" : true, "NP-GA" : true, - "NP-JA" : true, "NP-KA" : true, "NP-KO" : true, "NP-LU" : true, "NP-MA" : true, - "NP-ME" : true, "NP-NA" : true, "NP-RA" : true, "NP-SA" : true, "NP-SE" : true, - "NR-01" : true, "NR-02" : true, "NR-03" : true, "NR-04" : true, "NR-05" : true, - "NR-06" : true, "NR-07" : true, "NR-08" : true, "NR-09" : true, "NR-10" : true, - "NR-11" : true, "NR-12" : true, "NR-13" : true, "NR-14" : true, "NZ-AUK" : true, - "NZ-BOP" : true, "NZ-CAN" : true, "NZ-CIT" : true, "NZ-GIS" : true, "NZ-HKB" : true, - "NZ-MBH" : true, "NZ-MWT" : true, "NZ-N" : true, "NZ-NSN" : true, "NZ-NTL" : true, - "NZ-OTA" : true, "NZ-S" : true, "NZ-STL" : true, "NZ-TAS" : true, "NZ-TKI" : true, - "NZ-WGN" : true, "NZ-WKO" : true, "NZ-WTC" : true, "OM-BA" : true, "OM-BU" : true, - "OM-DA" : true, "OM-MA" : true, "OM-MU" : true, "OM-SH" : true, "OM-WU" : true, - "OM-ZA" : true, "OM-ZU" : true, "PA-1" : true, "PA-2" : true, "PA-3" : true, - "PA-4" : true, "PA-5" : true, "PA-6" : true, "PA-7" : true, "PA-8" : true, - "PA-9" : true, "PA-EM" : true, "PA-KY" : true, "PA-NB" : true, "PE-AMA" : true, - "PE-ANC" : true, "PE-APU" : true, "PE-ARE" : true, "PE-AYA" : true, "PE-CAJ" : true, - "PE-CAL" : true, "PE-CUS" : true, "PE-HUC" : true, "PE-HUV" : true, "PE-ICA" : true, - "PE-JUN" : true, "PE-LAL" : true, "PE-LAM" : true, "PE-LIM" : true, "PE-LMA" : true, - "PE-LOR" : true, "PE-MDD" : true, "PE-MOQ" : true, "PE-PAS" : true, "PE-PIU" : true, - "PE-PUN" : true, "PE-SAM" : true, "PE-TAC" : true, "PE-TUM" : true, "PE-UCA" : true, - "PG-CPK" : true, "PG-CPM" : true, "PG-EBR" : true, "PG-EHG" : true, "PG-EPW" : true, - "PG-ESW" : true, "PG-GPK" : true, "PG-MBA" : true, "PG-MPL" : true, "PG-MPM" : true, - "PG-MRL" : true, "PG-NCD" : true, "PG-NIK" : true, "PG-NPP" : true, "PG-NSB" : true, - "PG-SAN" : true, "PG-SHM" : true, "PG-WBK" : true, "PG-WHM" : true, "PG-WPD" : true, - "PH-00" : true, "PH-01" : true, "PH-02" : true, "PH-03" : true, "PH-05" : true, - "PH-06" : true, "PH-07" : true, "PH-08" : true, "PH-09" : true, "PH-10" : true, - "PH-11" : true, "PH-12" : true, "PH-13" : true, "PH-14" : true, "PH-15" : true, - "PH-40" : true, "PH-41" : true, "PH-ABR" : true, "PH-AGN" : true, "PH-AGS" : true, - "PH-AKL" : true, "PH-ALB" : true, "PH-ANT" : true, "PH-APA" : true, "PH-AUR" : true, - "PH-BAN" : true, "PH-BAS" : true, "PH-BEN" : true, "PH-BIL" : true, "PH-BOH" : true, - "PH-BTG" : true, "PH-BTN" : true, "PH-BUK" : true, "PH-BUL" : true, "PH-CAG" : true, - "PH-CAM" : true, "PH-CAN" : true, "PH-CAP" : true, "PH-CAS" : true, "PH-CAT" : true, - "PH-CAV" : true, "PH-CEB" : true, "PH-COM" : true, "PH-DAO" : true, "PH-DAS" : true, - "PH-DAV" : true, "PH-DIN" : true, "PH-EAS" : true, "PH-GUI" : true, "PH-IFU" : true, - "PH-ILI" : true, "PH-ILN" : true, "PH-ILS" : true, "PH-ISA" : true, "PH-KAL" : true, - "PH-LAG" : true, "PH-LAN" : true, "PH-LAS" : true, "PH-LEY" : true, "PH-LUN" : true, - "PH-MAD" : true, "PH-MAG" : true, "PH-MAS" : true, "PH-MDC" : true, "PH-MDR" : true, - "PH-MOU" : true, "PH-MSC" : true, "PH-MSR" : true, "PH-NCO" : true, "PH-NEC" : true, - "PH-NER" : true, "PH-NSA" : true, "PH-NUE" : true, "PH-NUV" : true, "PH-PAM" : true, - "PH-PAN" : true, "PH-PLW" : true, "PH-QUE" : true, "PH-QUI" : true, "PH-RIZ" : true, - "PH-ROM" : true, "PH-SAR" : true, "PH-SCO" : true, "PH-SIG" : true, "PH-SLE" : true, - "PH-SLU" : true, "PH-SOR" : true, "PH-SUK" : true, "PH-SUN" : true, "PH-SUR" : true, - "PH-TAR" : true, "PH-TAW" : true, "PH-WSA" : true, "PH-ZAN" : true, "PH-ZAS" : true, - "PH-ZMB" : true, "PH-ZSI" : true, "PK-BA" : true, "PK-GB" : true, "PK-IS" : true, - "PK-JK" : true, "PK-KP" : true, "PK-PB" : true, "PK-SD" : true, "PK-TA" : true, - "PL-DS" : true, "PL-KP" : true, "PL-LB" : true, "PL-LD" : true, "PL-LU" : true, - "PL-MA" : true, "PL-MZ" : true, "PL-OP" : true, "PL-PD" : true, "PL-PK" : true, - "PL-PM" : true, "PL-SK" : true, "PL-SL" : true, "PL-WN" : true, "PL-WP" : true, - "PL-ZP" : true, "PS-BTH" : true, "PS-DEB" : true, "PS-GZA" : true, "PS-HBN" : true, - "PS-JEM" : true, "PS-JEN" : true, "PS-JRH" : true, "PS-KYS" : true, "PS-NBS" : true, - "PS-NGZ" : true, "PS-QQA" : true, "PS-RBH" : true, "PS-RFH" : true, "PS-SLT" : true, - "PS-TBS" : true, "PS-TKM" : true, "PT-01" : true, "PT-02" : true, "PT-03" : true, - "PT-04" : true, "PT-05" : true, "PT-06" : true, "PT-07" : true, "PT-08" : true, - "PT-09" : true, "PT-10" : true, "PT-11" : true, "PT-12" : true, "PT-13" : true, - "PT-14" : true, "PT-15" : true, "PT-16" : true, "PT-17" : true, "PT-18" : true, - "PT-20" : true, "PT-30" : true, "PW-002" : true, "PW-004" : true, "PW-010" : true, - "PW-050" : true, "PW-100" : true, "PW-150" : true, "PW-212" : true, "PW-214" : true, - "PW-218" : true, "PW-222" : true, "PW-224" : true, "PW-226" : true, "PW-227" : true, - "PW-228" : true, "PW-350" : true, "PW-370" : true, "PY-1" : true, "PY-10" : true, - "PY-11" : true, "PY-12" : true, "PY-13" : true, "PY-14" : true, "PY-15" : true, - "PY-16" : true, "PY-19" : true, "PY-2" : true, "PY-3" : true, "PY-4" : true, - "PY-5" : true, "PY-6" : true, "PY-7" : true, "PY-8" : true, "PY-9" : true, - "PY-ASU" : true, "QA-DA" : true, "QA-KH" : true, "QA-MS" : true, "QA-RA" : true, - "QA-US" : true, "QA-WA" : true, "QA-ZA" : true, "RO-AB" : true, "RO-AG" : true, - "RO-AR" : true, "RO-B" : true, "RO-BC" : true, "RO-BH" : true, "RO-BN" : true, - "RO-BR" : true, "RO-BT" : true, "RO-BV" : true, "RO-BZ" : true, "RO-CJ" : true, - "RO-CL" : true, "RO-CS" : true, "RO-CT" : true, "RO-CV" : true, "RO-DB" : true, - "RO-DJ" : true, "RO-GJ" : true, "RO-GL" : true, "RO-GR" : true, "RO-HD" : true, - "RO-HR" : true, "RO-IF" : true, "RO-IL" : true, "RO-IS" : true, "RO-MH" : true, - "RO-MM" : true, "RO-MS" : true, "RO-NT" : true, "RO-OT" : true, "RO-PH" : true, - "RO-SB" : true, "RO-SJ" : true, "RO-SM" : true, "RO-SV" : true, "RO-TL" : true, - "RO-TM" : true, "RO-TR" : true, "RO-VL" : true, "RO-VN" : true, "RO-VS" : true, - "RS-00" : true, "RS-01" : true, "RS-02" : true, "RS-03" : true, "RS-04" : true, - "RS-05" : true, "RS-06" : true, "RS-07" : true, "RS-08" : true, "RS-09" : true, - "RS-10" : true, "RS-11" : true, "RS-12" : true, "RS-13" : true, "RS-14" : true, - "RS-15" : true, "RS-16" : true, "RS-17" : true, "RS-18" : true, "RS-19" : true, - "RS-20" : true, "RS-21" : true, "RS-22" : true, "RS-23" : true, "RS-24" : true, - "RS-25" : true, "RS-26" : true, "RS-27" : true, "RS-28" : true, "RS-29" : true, - "RS-KM" : true, "RS-VO" : true, "RU-AD" : true, "RU-AL" : true, "RU-ALT" : true, - "RU-AMU" : true, "RU-ARK" : true, "RU-AST" : true, "RU-BA" : true, "RU-BEL" : true, - "RU-BRY" : true, "RU-BU" : true, "RU-CE" : true, "RU-CHE" : true, "RU-CHU" : true, - "RU-CU" : true, "RU-DA" : true, "RU-IN" : true, "RU-IRK" : true, "RU-IVA" : true, - "RU-KAM" : true, "RU-KB" : true, "RU-KC" : true, "RU-KDA" : true, "RU-KEM" : true, - "RU-KGD" : true, "RU-KGN" : true, "RU-KHA" : true, "RU-KHM" : true, "RU-KIR" : true, - "RU-KK" : true, "RU-KL" : true, "RU-KLU" : true, "RU-KO" : true, "RU-KOS" : true, - "RU-KR" : true, "RU-KRS" : true, "RU-KYA" : true, "RU-LEN" : true, "RU-LIP" : true, - "RU-MAG" : true, "RU-ME" : true, "RU-MO" : true, "RU-MOS" : true, "RU-MOW" : true, - "RU-MUR" : true, "RU-NEN" : true, "RU-NGR" : true, "RU-NIZ" : true, "RU-NVS" : true, - "RU-OMS" : true, "RU-ORE" : true, "RU-ORL" : true, "RU-PER" : true, "RU-PNZ" : true, - "RU-PRI" : true, "RU-PSK" : true, "RU-ROS" : true, "RU-RYA" : true, "RU-SA" : true, - "RU-SAK" : true, "RU-SAM" : true, "RU-SAR" : true, "RU-SE" : true, "RU-SMO" : true, - "RU-SPE" : true, "RU-STA" : true, "RU-SVE" : true, "RU-TA" : true, "RU-TAM" : true, - "RU-TOM" : true, "RU-TUL" : true, "RU-TVE" : true, "RU-TY" : true, "RU-TYU" : true, - "RU-UD" : true, "RU-ULY" : true, "RU-VGG" : true, "RU-VLA" : true, "RU-VLG" : true, - "RU-VOR" : true, "RU-YAN" : true, "RU-YAR" : true, "RU-YEV" : true, "RU-ZAB" : true, - "RW-01" : true, "RW-02" : true, "RW-03" : true, "RW-04" : true, "RW-05" : true, - "SA-01" : true, "SA-02" : true, "SA-03" : true, "SA-04" : true, "SA-05" : true, - "SA-06" : true, "SA-07" : true, "SA-08" : true, "SA-09" : true, "SA-10" : true, - "SA-11" : true, "SA-12" : true, "SA-14" : true, "SB-CE" : true, "SB-CH" : true, - "SB-CT" : true, "SB-GU" : true, "SB-IS" : true, "SB-MK" : true, "SB-ML" : true, - "SB-RB" : true, "SB-TE" : true, "SB-WE" : true, "SC-01" : true, "SC-02" : true, - "SC-03" : true, "SC-04" : true, "SC-05" : true, "SC-06" : true, "SC-07" : true, - "SC-08" : true, "SC-09" : true, "SC-10" : true, "SC-11" : true, "SC-12" : true, - "SC-13" : true, "SC-14" : true, "SC-15" : true, "SC-16" : true, "SC-17" : true, - "SC-18" : true, "SC-19" : true, "SC-20" : true, "SC-21" : true, "SC-22" : true, - "SC-23" : true, "SC-24" : true, "SC-25" : true, "SD-DC" : true, "SD-DE" : true, - "SD-DN" : true, "SD-DS" : true, "SD-DW" : true, "SD-GD" : true, "SD-GZ" : true, - "SD-KA" : true, "SD-KH" : true, "SD-KN" : true, "SD-KS" : true, "SD-NB" : true, - "SD-NO" : true, "SD-NR" : true, "SD-NW" : true, "SD-RS" : true, "SD-SI" : true, - "SE-AB" : true, "SE-AC" : true, "SE-BD" : true, "SE-C" : true, "SE-D" : true, - "SE-E" : true, "SE-F" : true, "SE-G" : true, "SE-H" : true, "SE-I" : true, - "SE-K" : true, "SE-M" : true, "SE-N" : true, "SE-O" : true, "SE-S" : true, - "SE-T" : true, "SE-U" : true, "SE-W" : true, "SE-X" : true, "SE-Y" : true, - "SE-Z" : true, "SG-01" : true, "SG-02" : true, "SG-03" : true, "SG-04" : true, - "SG-05" : true, "SH-AC" : true, "SH-HL" : true, "SH-TA" : true, "SI-001" : true, - "SI-002" : true, "SI-003" : true, "SI-004" : true, "SI-005" : true, "SI-006" : true, - "SI-007" : true, "SI-008" : true, "SI-009" : true, "SI-010" : true, "SI-011" : true, - "SI-012" : true, "SI-013" : true, "SI-014" : true, "SI-015" : true, "SI-016" : true, - "SI-017" : true, "SI-018" : true, "SI-019" : true, "SI-020" : true, "SI-021" : true, - "SI-022" : true, "SI-023" : true, "SI-024" : true, "SI-025" : true, "SI-026" : true, - "SI-027" : true, "SI-028" : true, "SI-029" : true, "SI-030" : true, "SI-031" : true, - "SI-032" : true, "SI-033" : true, "SI-034" : true, "SI-035" : true, "SI-036" : true, - "SI-037" : true, "SI-038" : true, "SI-039" : true, "SI-040" : true, "SI-041" : true, - "SI-042" : true, "SI-043" : true, "SI-044" : true, "SI-045" : true, "SI-046" : true, - "SI-047" : true, "SI-048" : true, "SI-049" : true, "SI-050" : true, "SI-051" : true, - "SI-052" : true, "SI-053" : true, "SI-054" : true, "SI-055" : true, "SI-056" : true, - "SI-057" : true, "SI-058" : true, "SI-059" : true, "SI-060" : true, "SI-061" : true, - "SI-062" : true, "SI-063" : true, "SI-064" : true, "SI-065" : true, "SI-066" : true, - "SI-067" : true, "SI-068" : true, "SI-069" : true, "SI-070" : true, "SI-071" : true, - "SI-072" : true, "SI-073" : true, "SI-074" : true, "SI-075" : true, "SI-076" : true, - "SI-077" : true, "SI-078" : true, "SI-079" : true, "SI-080" : true, "SI-081" : true, - "SI-082" : true, "SI-083" : true, "SI-084" : true, "SI-085" : true, "SI-086" : true, - "SI-087" : true, "SI-088" : true, "SI-089" : true, "SI-090" : true, "SI-091" : true, - "SI-092" : true, "SI-093" : true, "SI-094" : true, "SI-095" : true, "SI-096" : true, - "SI-097" : true, "SI-098" : true, "SI-099" : true, "SI-100" : true, "SI-101" : true, - "SI-102" : true, "SI-103" : true, "SI-104" : true, "SI-105" : true, "SI-106" : true, - "SI-107" : true, "SI-108" : true, "SI-109" : true, "SI-110" : true, "SI-111" : true, - "SI-112" : true, "SI-113" : true, "SI-114" : true, "SI-115" : true, "SI-116" : true, - "SI-117" : true, "SI-118" : true, "SI-119" : true, "SI-120" : true, "SI-121" : true, - "SI-122" : true, "SI-123" : true, "SI-124" : true, "SI-125" : true, "SI-126" : true, - "SI-127" : true, "SI-128" : true, "SI-129" : true, "SI-130" : true, "SI-131" : true, - "SI-132" : true, "SI-133" : true, "SI-134" : true, "SI-135" : true, "SI-136" : true, - "SI-137" : true, "SI-138" : true, "SI-139" : true, "SI-140" : true, "SI-141" : true, - "SI-142" : true, "SI-143" : true, "SI-144" : true, "SI-146" : true, "SI-147" : true, - "SI-148" : true, "SI-149" : true, "SI-150" : true, "SI-151" : true, "SI-152" : true, - "SI-153" : true, "SI-154" : true, "SI-155" : true, "SI-156" : true, "SI-157" : true, - "SI-158" : true, "SI-159" : true, "SI-160" : true, "SI-161" : true, "SI-162" : true, - "SI-163" : true, "SI-164" : true, "SI-165" : true, "SI-166" : true, "SI-167" : true, - "SI-168" : true, "SI-169" : true, "SI-170" : true, "SI-171" : true, "SI-172" : true, - "SI-173" : true, "SI-174" : true, "SI-175" : true, "SI-176" : true, "SI-177" : true, - "SI-178" : true, "SI-179" : true, "SI-180" : true, "SI-181" : true, "SI-182" : true, - "SI-183" : true, "SI-184" : true, "SI-185" : true, "SI-186" : true, "SI-187" : true, - "SI-188" : true, "SI-189" : true, "SI-190" : true, "SI-191" : true, "SI-192" : true, - "SI-193" : true, "SI-194" : true, "SI-195" : true, "SI-196" : true, "SI-197" : true, - "SI-198" : true, "SI-199" : true, "SI-200" : true, "SI-201" : true, "SI-202" : true, - "SI-203" : true, "SI-204" : true, "SI-205" : true, "SI-206" : true, "SI-207" : true, - "SI-208" : true, "SI-209" : true, "SI-210" : true, "SI-211" : true, "SK-BC" : true, - "SK-BL" : true, "SK-KI" : true, "SK-NI" : true, "SK-PV" : true, "SK-TA" : true, - "SK-TC" : true, "SK-ZI" : true, "SL-E" : true, "SL-N" : true, "SL-S" : true, - "SL-W" : true, "SM-01" : true, "SM-02" : true, "SM-03" : true, "SM-04" : true, - "SM-05" : true, "SM-06" : true, "SM-07" : true, "SM-08" : true, "SM-09" : true, - "SN-DB" : true, "SN-DK" : true, "SN-FK" : true, "SN-KA" : true, "SN-KD" : true, - "SN-KE" : true, "SN-KL" : true, "SN-LG" : true, "SN-MT" : true, "SN-SE" : true, - "SN-SL" : true, "SN-TC" : true, "SN-TH" : true, "SN-ZG" : true, "SO-AW" : true, - "SO-BK" : true, "SO-BN" : true, "SO-BR" : true, "SO-BY" : true, "SO-GA" : true, - "SO-GE" : true, "SO-HI" : true, "SO-JD" : true, "SO-JH" : true, "SO-MU" : true, - "SO-NU" : true, "SO-SA" : true, "SO-SD" : true, "SO-SH" : true, "SO-SO" : true, - "SO-TO" : true, "SO-WO" : true, "SR-BR" : true, "SR-CM" : true, "SR-CR" : true, - "SR-MA" : true, "SR-NI" : true, "SR-PM" : true, "SR-PR" : true, "SR-SA" : true, - "SR-SI" : true, "SR-WA" : true, "SS-BN" : true, "SS-BW" : true, "SS-EC" : true, - "SS-EE8" : true, "SS-EW" : true, "SS-JG" : true, "SS-LK" : true, "SS-NU" : true, - "SS-UY" : true, "SS-WR" : true, "ST-P" : true, "ST-S" : true, "SV-AH" : true, - "SV-CA" : true, "SV-CH" : true, "SV-CU" : true, "SV-LI" : true, "SV-MO" : true, - "SV-PA" : true, "SV-SA" : true, "SV-SM" : true, "SV-SO" : true, "SV-SS" : true, - "SV-SV" : true, "SV-UN" : true, "SV-US" : true, "SY-DI" : true, "SY-DR" : true, - "SY-DY" : true, "SY-HA" : true, "SY-HI" : true, "SY-HL" : true, "SY-HM" : true, - "SY-ID" : true, "SY-LA" : true, "SY-QU" : true, "SY-RA" : true, "SY-RD" : true, - "SY-SU" : true, "SY-TA" : true, "SZ-HH" : true, "SZ-LU" : true, "SZ-MA" : true, - "SZ-SH" : true, "TD-BA" : true, "TD-BG" : true, "TD-BO" : true, "TD-CB" : true, - "TD-EN" : true, "TD-GR" : true, "TD-HL" : true, "TD-KA" : true, "TD-LC" : true, - "TD-LO" : true, "TD-LR" : true, "TD-MA" : true, "TD-MC" : true, "TD-ME" : true, - "TD-MO" : true, "TD-ND" : true, "TD-OD" : true, "TD-SA" : true, "TD-SI" : true, - "TD-TA" : true, "TD-TI" : true, "TD-WF" : true, "TG-C" : true, "TG-K" : true, - "TG-M" : true, "TG-P" : true, "TG-S" : true, "TH-10" : true, "TH-11" : true, - "TH-12" : true, "TH-13" : true, "TH-14" : true, "TH-15" : true, "TH-16" : true, - "TH-17" : true, "TH-18" : true, "TH-19" : true, "TH-20" : true, "TH-21" : true, - "TH-22" : true, "TH-23" : true, "TH-24" : true, "TH-25" : true, "TH-26" : true, - "TH-27" : true, "TH-30" : true, "TH-31" : true, "TH-32" : true, "TH-33" : true, - "TH-34" : true, "TH-35" : true, "TH-36" : true, "TH-37" : true, "TH-39" : true, - "TH-40" : true, "TH-41" : true, "TH-42" : true, "TH-43" : true, "TH-44" : true, - "TH-45" : true, "TH-46" : true, "TH-47" : true, "TH-48" : true, "TH-49" : true, - "TH-50" : true, "TH-51" : true, "TH-52" : true, "TH-53" : true, "TH-54" : true, - "TH-55" : true, "TH-56" : true, "TH-57" : true, "TH-58" : true, "TH-60" : true, - "TH-61" : true, "TH-62" : true, "TH-63" : true, "TH-64" : true, "TH-65" : true, - "TH-66" : true, "TH-67" : true, "TH-70" : true, "TH-71" : true, "TH-72" : true, - "TH-73" : true, "TH-74" : true, "TH-75" : true, "TH-76" : true, "TH-77" : true, - "TH-80" : true, "TH-81" : true, "TH-82" : true, "TH-83" : true, "TH-84" : true, - "TH-85" : true, "TH-86" : true, "TH-90" : true, "TH-91" : true, "TH-92" : true, - "TH-93" : true, "TH-94" : true, "TH-95" : true, "TH-96" : true, "TH-S" : true, - "TJ-GB" : true, "TJ-KT" : true, "TJ-SU" : true, "TL-AL" : true, "TL-AN" : true, - "TL-BA" : true, "TL-BO" : true, "TL-CO" : true, "TL-DI" : true, "TL-ER" : true, - "TL-LA" : true, "TL-LI" : true, "TL-MF" : true, "TL-MT" : true, "TL-OE" : true, - "TL-VI" : true, "TM-A" : true, "TM-B" : true, "TM-D" : true, "TM-L" : true, - "TM-M" : true, "TM-S" : true, "TN-11" : true, "TN-12" : true, "TN-13" : true, - "TN-14" : true, "TN-21" : true, "TN-22" : true, "TN-23" : true, "TN-31" : true, - "TN-32" : true, "TN-33" : true, "TN-34" : true, "TN-41" : true, "TN-42" : true, - "TN-43" : true, "TN-51" : true, "TN-52" : true, "TN-53" : true, "TN-61" : true, - "TN-71" : true, "TN-72" : true, "TN-73" : true, "TN-81" : true, "TN-82" : true, - "TN-83" : true, "TO-01" : true, "TO-02" : true, "TO-03" : true, "TO-04" : true, - "TO-05" : true, "TR-01" : true, "TR-02" : true, "TR-03" : true, "TR-04" : true, - "TR-05" : true, "TR-06" : true, "TR-07" : true, "TR-08" : true, "TR-09" : true, - "TR-10" : true, "TR-11" : true, "TR-12" : true, "TR-13" : true, "TR-14" : true, - "TR-15" : true, "TR-16" : true, "TR-17" : true, "TR-18" : true, "TR-19" : true, - "TR-20" : true, "TR-21" : true, "TR-22" : true, "TR-23" : true, "TR-24" : true, - "TR-25" : true, "TR-26" : true, "TR-27" : true, "TR-28" : true, "TR-29" : true, - "TR-30" : true, "TR-31" : true, "TR-32" : true, "TR-33" : true, "TR-34" : true, - "TR-35" : true, "TR-36" : true, "TR-37" : true, "TR-38" : true, "TR-39" : true, - "TR-40" : true, "TR-41" : true, "TR-42" : true, "TR-43" : true, "TR-44" : true, - "TR-45" : true, "TR-46" : true, "TR-47" : true, "TR-48" : true, "TR-49" : true, - "TR-50" : true, "TR-51" : true, "TR-52" : true, "TR-53" : true, "TR-54" : true, - "TR-55" : true, "TR-56" : true, "TR-57" : true, "TR-58" : true, "TR-59" : true, - "TR-60" : true, "TR-61" : true, "TR-62" : true, "TR-63" : true, "TR-64" : true, - "TR-65" : true, "TR-66" : true, "TR-67" : true, "TR-68" : true, "TR-69" : true, - "TR-70" : true, "TR-71" : true, "TR-72" : true, "TR-73" : true, "TR-74" : true, - "TR-75" : true, "TR-76" : true, "TR-77" : true, "TR-78" : true, "TR-79" : true, - "TR-80" : true, "TR-81" : true, "TT-ARI" : true, "TT-CHA" : true, "TT-CTT" : true, - "TT-DMN" : true, "TT-ETO" : true, "TT-PED" : true, "TT-POS" : true, "TT-PRT" : true, - "TT-PTF" : true, "TT-RCM" : true, "TT-SFO" : true, "TT-SGE" : true, "TT-SIP" : true, - "TT-SJL" : true, "TT-TUP" : true, "TT-WTO" : true, "TV-FUN" : true, "TV-NIT" : true, - "TV-NKF" : true, "TV-NKL" : true, "TV-NMA" : true, "TV-NMG" : true, "TV-NUI" : true, - "TV-VAI" : true, "TW-CHA" : true, "TW-CYI" : true, "TW-CYQ" : true, "TW-HSQ" : true, - "TW-HSZ" : true, "TW-HUA" : true, "TW-ILA" : true, "TW-KEE" : true, "TW-KHH" : true, - "TW-KHQ" : true, "TW-MIA" : true, "TW-NAN" : true, "TW-PEN" : true, "TW-PIF" : true, - "TW-TAO" : true, "TW-TNN" : true, "TW-TNQ" : true, "TW-TPE" : true, "TW-TPQ" : true, - "TW-TTT" : true, "TW-TXG" : true, "TW-TXQ" : true, "TW-YUN" : true, "TZ-01" : true, - "TZ-02" : true, "TZ-03" : true, "TZ-04" : true, "TZ-05" : true, "TZ-06" : true, - "TZ-07" : true, "TZ-08" : true, "TZ-09" : true, "TZ-10" : true, "TZ-11" : true, - "TZ-12" : true, "TZ-13" : true, "TZ-14" : true, "TZ-15" : true, "TZ-16" : true, - "TZ-17" : true, "TZ-18" : true, "TZ-19" : true, "TZ-20" : true, "TZ-21" : true, - "TZ-22" : true, "TZ-23" : true, "TZ-24" : true, "TZ-25" : true, "TZ-26" : true, - "UA-05" : true, "UA-07" : true, "UA-09" : true, "UA-12" : true, "UA-14" : true, - "UA-18" : true, "UA-21" : true, "UA-23" : true, "UA-26" : true, "UA-30" : true, - "UA-32" : true, "UA-35" : true, "UA-40" : true, "UA-43" : true, "UA-46" : true, - "UA-48" : true, "UA-51" : true, "UA-53" : true, "UA-56" : true, "UA-59" : true, - "UA-61" : true, "UA-63" : true, "UA-65" : true, "UA-68" : true, "UA-71" : true, - "UA-74" : true, "UA-77" : true, "UG-101" : true, "UG-102" : true, "UG-103" : true, - "UG-104" : true, "UG-105" : true, "UG-106" : true, "UG-107" : true, "UG-108" : true, - "UG-109" : true, "UG-110" : true, "UG-111" : true, "UG-112" : true, "UG-113" : true, - "UG-114" : true, "UG-115" : true, "UG-116" : true, "UG-201" : true, "UG-202" : true, - "UG-203" : true, "UG-204" : true, "UG-205" : true, "UG-206" : true, "UG-207" : true, - "UG-208" : true, "UG-209" : true, "UG-210" : true, "UG-211" : true, "UG-212" : true, - "UG-213" : true, "UG-214" : true, "UG-215" : true, "UG-216" : true, "UG-217" : true, - "UG-218" : true, "UG-219" : true, "UG-220" : true, "UG-221" : true, "UG-222" : true, - "UG-223" : true, "UG-224" : true, "UG-301" : true, "UG-302" : true, "UG-303" : true, - "UG-304" : true, "UG-305" : true, "UG-306" : true, "UG-307" : true, "UG-308" : true, - "UG-309" : true, "UG-310" : true, "UG-311" : true, "UG-312" : true, "UG-313" : true, - "UG-314" : true, "UG-315" : true, "UG-316" : true, "UG-317" : true, "UG-318" : true, - "UG-319" : true, "UG-320" : true, "UG-321" : true, "UG-401" : true, "UG-402" : true, - "UG-403" : true, "UG-404" : true, "UG-405" : true, "UG-406" : true, "UG-407" : true, - "UG-408" : true, "UG-409" : true, "UG-410" : true, "UG-411" : true, "UG-412" : true, - "UG-413" : true, "UG-414" : true, "UG-415" : true, "UG-416" : true, "UG-417" : true, - "UG-418" : true, "UG-419" : true, "UG-C" : true, "UG-E" : true, "UG-N" : true, - "UG-W" : true, "UM-67" : true, "UM-71" : true, "UM-76" : true, "UM-79" : true, - "UM-81" : true, "UM-84" : true, "UM-86" : true, "UM-89" : true, "UM-95" : true, - "US-AK" : true, "US-AL" : true, "US-AR" : true, "US-AS" : true, "US-AZ" : true, - "US-CA" : true, "US-CO" : true, "US-CT" : true, "US-DC" : true, "US-DE" : true, - "US-FL" : true, "US-GA" : true, "US-GU" : true, "US-HI" : true, "US-IA" : true, - "US-ID" : true, "US-IL" : true, "US-IN" : true, "US-KS" : true, "US-KY" : true, - "US-LA" : true, "US-MA" : true, "US-MD" : true, "US-ME" : true, "US-MI" : true, - "US-MN" : true, "US-MO" : true, "US-MP" : true, "US-MS" : true, "US-MT" : true, - "US-NC" : true, "US-ND" : true, "US-NE" : true, "US-NH" : true, "US-NJ" : true, - "US-NM" : true, "US-NV" : true, "US-NY" : true, "US-OH" : true, "US-OK" : true, - "US-OR" : true, "US-PA" : true, "US-PR" : true, "US-RI" : true, "US-SC" : true, - "US-SD" : true, "US-TN" : true, "US-TX" : true, "US-UM" : true, "US-UT" : true, - "US-VA" : true, "US-VI" : true, "US-VT" : true, "US-WA" : true, "US-WI" : true, - "US-WV" : true, "US-WY" : true, "UY-AR" : true, "UY-CA" : true, "UY-CL" : true, - "UY-CO" : true, "UY-DU" : true, "UY-FD" : true, "UY-FS" : true, "UY-LA" : true, - "UY-MA" : true, "UY-MO" : true, "UY-PA" : true, "UY-RN" : true, "UY-RO" : true, - "UY-RV" : true, "UY-SA" : true, "UY-SJ" : true, "UY-SO" : true, "UY-TA" : true, - "UY-TT" : true, "UZ-AN" : true, "UZ-BU" : true, "UZ-FA" : true, "UZ-JI" : true, - "UZ-NG" : true, "UZ-NW" : true, "UZ-QA" : true, "UZ-QR" : true, "UZ-SA" : true, - "UZ-SI" : true, "UZ-SU" : true, "UZ-TK" : true, "UZ-TO" : true, "UZ-XO" : true, - "VC-01" : true, "VC-02" : true, "VC-03" : true, "VC-04" : true, "VC-05" : true, - "VC-06" : true, "VE-A" : true, "VE-B" : true, "VE-C" : true, "VE-D" : true, - "VE-E" : true, "VE-F" : true, "VE-G" : true, "VE-H" : true, "VE-I" : true, - "VE-J" : true, "VE-K" : true, "VE-L" : true, "VE-M" : true, "VE-N" : true, - "VE-O" : true, "VE-P" : true, "VE-R" : true, "VE-S" : true, "VE-T" : true, - "VE-U" : true, "VE-V" : true, "VE-W" : true, "VE-X" : true, "VE-Y" : true, - "VE-Z" : true, "VN-01" : true, "VN-02" : true, "VN-03" : true, "VN-04" : true, - "VN-05" : true, "VN-06" : true, "VN-07" : true, "VN-09" : true, "VN-13" : true, - "VN-14" : true, "VN-15" : true, "VN-18" : true, "VN-20" : true, "VN-21" : true, - "VN-22" : true, "VN-23" : true, "VN-24" : true, "VN-25" : true, "VN-26" : true, - "VN-27" : true, "VN-28" : true, "VN-29" : true, "VN-30" : true, "VN-31" : true, - "VN-32" : true, "VN-33" : true, "VN-34" : true, "VN-35" : true, "VN-36" : true, - "VN-37" : true, "VN-39" : true, "VN-40" : true, "VN-41" : true, "VN-43" : true, - "VN-44" : true, "VN-45" : true, "VN-46" : true, "VN-47" : true, "VN-49" : true, - "VN-50" : true, "VN-51" : true, "VN-52" : true, "VN-53" : true, "VN-54" : true, - "VN-55" : true, "VN-56" : true, "VN-57" : true, "VN-58" : true, "VN-59" : true, - "VN-61" : true, "VN-63" : true, "VN-66" : true, "VN-67" : true, "VN-68" : true, - "VN-69" : true, "VN-70" : true, "VN-71" : true, "VN-72" : true, "VN-73" : true, - "VN-CT" : true, "VN-DN" : true, "VN-HN" : true, "VN-HP" : true, "VN-SG" : true, - "VU-MAP" : true, "VU-PAM" : true, "VU-SAM" : true, "VU-SEE" : true, "VU-TAE" : true, - "VU-TOB" : true, "WS-AA" : true, "WS-AL" : true, "WS-AT" : true, "WS-FA" : true, - "WS-GE" : true, "WS-GI" : true, "WS-PA" : true, "WS-SA" : true, "WS-TU" : true, - "WS-VF" : true, "WS-VS" : true, "YE-AB" : true, "YE-AD" : true, "YE-AM" : true, - "YE-BA" : true, "YE-DA" : true, "YE-DH" : true, "YE-HD" : true, "YE-HJ" : true, - "YE-IB" : true, "YE-JA" : true, "YE-LA" : true, "YE-MA" : true, "YE-MR" : true, - "YE-MU" : true, "YE-MW" : true, "YE-RA" : true, "YE-SD" : true, "YE-SH" : true, - "YE-SN" : true, "YE-TA" : true, "ZA-EC" : true, "ZA-FS" : true, "ZA-GP" : true, - "ZA-LP" : true, "ZA-MP" : true, "ZA-NC" : true, "ZA-NW" : true, "ZA-WC" : true, - "ZA-ZN" : true, "ZM-01" : true, "ZM-02" : true, "ZM-03" : true, "ZM-04" : true, - "ZM-05" : true, "ZM-06" : true, "ZM-07" : true, "ZM-08" : true, "ZM-09" : true, - "ZW-BU" : true, "ZW-HA" : true, "ZW-MA" : true, "ZW-MC" : true, "ZW-ME" : true, - "ZW-MI" : true, "ZW-MN" : true, "ZW-MS" : true, "ZW-MV" : true, "ZW-MW" : true, -} diff --git a/vendor/github.com/go-playground/validator/v10/currency_codes.go b/vendor/github.com/go-playground/validator/v10/currency_codes.go deleted file mode 100644 index a5cd9b1..0000000 --- a/vendor/github.com/go-playground/validator/v10/currency_codes.go +++ /dev/null @@ -1,79 +0,0 @@ -package validator - -var iso4217 = map[string]bool{ - "AFN": true, "EUR": true, "ALL": true, "DZD": true, "USD": true, - "AOA": true, "XCD": true, "ARS": true, "AMD": true, "AWG": true, - "AUD": true, "AZN": true, "BSD": true, "BHD": true, "BDT": true, - "BBD": true, "BYN": true, "BZD": true, "XOF": true, "BMD": true, - "INR": true, "BTN": true, "BOB": true, "BOV": true, "BAM": true, - "BWP": true, "NOK": true, "BRL": true, "BND": true, "BGN": true, - "BIF": true, "CVE": true, "KHR": true, "XAF": true, "CAD": true, - "KYD": true, "CLP": true, "CLF": true, "CNY": true, "COP": true, - "COU": true, "KMF": true, "CDF": true, "NZD": true, "CRC": true, - "HRK": true, "CUP": true, "CUC": true, "ANG": true, "CZK": true, - "DKK": true, "DJF": true, "DOP": true, "EGP": true, "SVC": true, - "ERN": true, "SZL": true, "ETB": true, "FKP": true, "FJD": true, - "XPF": true, "GMD": true, "GEL": true, "GHS": true, "GIP": true, - "GTQ": true, "GBP": true, "GNF": true, "GYD": true, "HTG": true, - "HNL": true, "HKD": true, "HUF": true, "ISK": true, "IDR": true, - "XDR": true, "IRR": true, "IQD": true, "ILS": true, "JMD": true, - "JPY": true, "JOD": true, "KZT": true, "KES": true, "KPW": true, - "KRW": true, "KWD": true, "KGS": true, "LAK": true, "LBP": true, - "LSL": true, "ZAR": true, "LRD": true, "LYD": true, "CHF": true, - "MOP": true, "MKD": true, "MGA": true, "MWK": true, "MYR": true, - "MVR": true, "MRU": true, "MUR": true, "XUA": true, "MXN": true, - "MXV": true, "MDL": true, "MNT": true, "MAD": true, "MZN": true, - "MMK": true, "NAD": true, "NPR": true, "NIO": true, "NGN": true, - "OMR": true, "PKR": true, "PAB": true, "PGK": true, "PYG": true, - "PEN": true, "PHP": true, "PLN": true, "QAR": true, "RON": true, - "RUB": true, "RWF": true, "SHP": true, "WST": true, "STN": true, - "SAR": true, "RSD": true, "SCR": true, "SLL": true, "SGD": true, - "XSU": true, "SBD": true, "SOS": true, "SSP": true, "LKR": true, - "SDG": true, "SRD": true, "SEK": true, "CHE": true, "CHW": true, - "SYP": true, "TWD": true, "TJS": true, "TZS": true, "THB": true, - "TOP": true, "TTD": true, "TND": true, "TRY": true, "TMT": true, - "UGX": true, "UAH": true, "AED": true, "USN": true, "UYU": true, - "UYI": true, "UYW": true, "UZS": true, "VUV": true, "VES": true, - "VND": true, "YER": true, "ZMW": true, "ZWL": true, "XBA": true, - "XBB": true, "XBC": true, "XBD": true, "XTS": true, "XXX": true, - "XAU": true, "XPD": true, "XPT": true, "XAG": true, -} - -var iso4217_numeric = map[int]bool{ - 8: true, 12: true, 32: true, 36: true, 44: true, - 48: true, 50: true, 51: true, 52: true, 60: true, - 64: true, 68: true, 72: true, 84: true, 90: true, - 96: true, 104: true, 108: true, 116: true, 124: true, - 132: true, 136: true, 144: true, 152: true, 156: true, - 170: true, 174: true, 188: true, 191: true, 192: true, - 203: true, 208: true, 214: true, 222: true, 230: true, - 232: true, 238: true, 242: true, 262: true, 270: true, - 292: true, 320: true, 324: true, 328: true, 332: true, - 340: true, 344: true, 348: true, 352: true, 356: true, - 360: true, 364: true, 368: true, 376: true, 388: true, - 392: true, 398: true, 400: true, 404: true, 408: true, - 410: true, 414: true, 417: true, 418: true, 422: true, - 426: true, 430: true, 434: true, 446: true, 454: true, - 458: true, 462: true, 480: true, 484: true, 496: true, - 498: true, 504: true, 512: true, 516: true, 524: true, - 532: true, 533: true, 548: true, 554: true, 558: true, - 566: true, 578: true, 586: true, 590: true, 598: true, - 600: true, 604: true, 608: true, 634: true, 643: true, - 646: true, 654: true, 682: true, 690: true, 694: true, - 702: true, 704: true, 706: true, 710: true, 728: true, - 748: true, 752: true, 756: true, 760: true, 764: true, - 776: true, 780: true, 784: true, 788: true, 800: true, - 807: true, 818: true, 826: true, 834: true, 840: true, - 858: true, 860: true, 882: true, 886: true, 901: true, - 927: true, 928: true, 929: true, 930: true, 931: true, - 932: true, 933: true, 934: true, 936: true, 938: true, - 940: true, 941: true, 943: true, 944: true, 946: true, - 947: true, 948: true, 949: true, 950: true, 951: true, - 952: true, 953: true, 955: true, 956: true, 957: true, - 958: true, 959: true, 960: true, 961: true, 962: true, - 963: true, 964: true, 965: true, 967: true, 968: true, - 969: true, 970: true, 971: true, 972: true, 973: true, - 975: true, 976: true, 977: true, 978: true, 979: true, - 980: true, 981: true, 984: true, 985: true, 986: true, - 990: true, 994: true, 997: true, 999: true, -} diff --git a/vendor/github.com/go-playground/validator/v10/doc.go b/vendor/github.com/go-playground/validator/v10/doc.go deleted file mode 100644 index 7341c67..0000000 --- a/vendor/github.com/go-playground/validator/v10/doc.go +++ /dev/null @@ -1,1401 +0,0 @@ -/* -Package validator implements value validations for structs and individual fields -based on tags. - -It can also handle Cross-Field and Cross-Struct validation for nested structs -and has the ability to dive into arrays and maps of any type. - -see more examples https://github.com/go-playground/validator/tree/master/_examples - -Singleton - -Validator is designed to be thread-safe and used as a singleton instance. -It caches information about your struct and validations, -in essence only parsing your validation tags once per struct type. -Using multiple instances neglects the benefit of caching. -The not thread-safe functions are explicitly marked as such in the documentation. - -Validation Functions Return Type error - -Doing things this way is actually the way the standard library does, see the -file.Open method here: - - https://golang.org/pkg/os/#Open. - -The authors return type "error" to avoid the issue discussed in the following, -where err is always != nil: - - http://stackoverflow.com/a/29138676/3158232 - https://github.com/go-playground/validator/issues/134 - -Validator only InvalidValidationError for bad validation input, nil or -ValidationErrors as type error; so, in your code all you need to do is check -if the error returned is not nil, and if it's not check if error is -InvalidValidationError ( if necessary, most of the time it isn't ) type cast -it to type ValidationErrors like so err.(validator.ValidationErrors). - -Custom Validation Functions - -Custom Validation functions can be added. Example: - - // Structure - func customFunc(fl validator.FieldLevel) bool { - - if fl.Field().String() == "invalid" { - return false - } - - return true - } - - validate.RegisterValidation("custom tag name", customFunc) - // NOTES: using the same tag name as an existing function - // will overwrite the existing one - -Cross-Field Validation - -Cross-Field Validation can be done via the following tags: - - eqfield - - nefield - - gtfield - - gtefield - - ltfield - - ltefield - - eqcsfield - - necsfield - - gtcsfield - - gtecsfield - - ltcsfield - - ltecsfield - -If, however, some custom cross-field validation is required, it can be done -using a custom validation. - -Why not just have cross-fields validation tags (i.e. only eqcsfield and not -eqfield)? - -The reason is efficiency. If you want to check a field within the same struct -"eqfield" only has to find the field on the same struct (1 level). But, if we -used "eqcsfield" it could be multiple levels down. Example: - - type Inner struct { - StartDate time.Time - } - - type Outer struct { - InnerStructField *Inner - CreatedAt time.Time `validate:"ltecsfield=InnerStructField.StartDate"` - } - - now := time.Now() - - inner := &Inner{ - StartDate: now, - } - - outer := &Outer{ - InnerStructField: inner, - CreatedAt: now, - } - - errs := validate.Struct(outer) - - // NOTE: when calling validate.Struct(val) topStruct will be the top level struct passed - // into the function - // when calling validate.VarWithValue(val, field, tag) val will be - // whatever you pass, struct, field... - // when calling validate.Field(field, tag) val will be nil - -Multiple Validators - -Multiple validators on a field will process in the order defined. Example: - - type Test struct { - Field `validate:"max=10,min=1"` - } - - // max will be checked then min - -Bad Validator definitions are not handled by the library. Example: - - type Test struct { - Field `validate:"min=10,max=0"` - } - - // this definition of min max will never succeed - -Using Validator Tags - -Baked In Cross-Field validation only compares fields on the same struct. -If Cross-Field + Cross-Struct validation is needed you should implement your -own custom validator. - -Comma (",") is the default separator of validation tags. If you wish to -have a comma included within the parameter (i.e. excludesall=,) you will need to -use the UTF-8 hex representation 0x2C, which is replaced in the code as a comma, -so the above will become excludesall=0x2C. - - type Test struct { - Field `validate:"excludesall=,"` // BAD! Do not include a comma. - Field `validate:"excludesall=0x2C"` // GOOD! Use the UTF-8 hex representation. - } - -Pipe ("|") is the 'or' validation tags deparator. If you wish to -have a pipe included within the parameter i.e. excludesall=| you will need to -use the UTF-8 hex representation 0x7C, which is replaced in the code as a pipe, -so the above will become excludesall=0x7C - - type Test struct { - Field `validate:"excludesall=|"` // BAD! Do not include a a pipe! - Field `validate:"excludesall=0x7C"` // GOOD! Use the UTF-8 hex representation. - } - - -Baked In Validators and Tags - -Here is a list of the current built in validators: - - -Skip Field - -Tells the validation to skip this struct field; this is particularly -handy in ignoring embedded structs from being validated. (Usage: -) - Usage: - - - -Or Operator - -This is the 'or' operator allowing multiple validators to be used and -accepted. (Usage: rgb|rgba) <-- this would allow either rgb or rgba -colors to be accepted. This can also be combined with 'and' for example -( Usage: omitempty,rgb|rgba) - - Usage: | - -StructOnly - -When a field that is a nested struct is encountered, and contains this flag -any validation on the nested struct will be run, but none of the nested -struct fields will be validated. This is useful if inside of your program -you know the struct will be valid, but need to verify it has been assigned. -NOTE: only "required" and "omitempty" can be used on a struct itself. - - Usage: structonly - -NoStructLevel - -Same as structonly tag except that any struct level validations will not run. - - Usage: nostructlevel - -Omit Empty - -Allows conditional validation, for example if a field is not set with -a value (Determined by the "required" validator) then other validation -such as min or max won't run, but if a value is set validation will run. - - Usage: omitempty - -Dive - -This tells the validator to dive into a slice, array or map and validate that -level of the slice, array or map with the validation tags that follow. -Multidimensional nesting is also supported, each level you wish to dive will -require another dive tag. dive has some sub-tags, 'keys' & 'endkeys', please see -the Keys & EndKeys section just below. - - Usage: dive - -Example #1 - - [][]string with validation tag "gt=0,dive,len=1,dive,required" - // gt=0 will be applied to [] - // len=1 will be applied to []string - // required will be applied to string - -Example #2 - - [][]string with validation tag "gt=0,dive,dive,required" - // gt=0 will be applied to [] - // []string will be spared validation - // required will be applied to string - -Keys & EndKeys - -These are to be used together directly after the dive tag and tells the validator -that anything between 'keys' and 'endkeys' applies to the keys of a map and not the -values; think of it like the 'dive' tag, but for map keys instead of values. -Multidimensional nesting is also supported, each level you wish to validate will -require another 'keys' and 'endkeys' tag. These tags are only valid for maps. - - Usage: dive,keys,othertagvalidation(s),endkeys,valuevalidationtags - -Example #1 - - map[string]string with validation tag "gt=0,dive,keys,eg=1|eq=2,endkeys,required" - // gt=0 will be applied to the map itself - // eg=1|eq=2 will be applied to the map keys - // required will be applied to map values - -Example #2 - - map[[2]string]string with validation tag "gt=0,dive,keys,dive,eq=1|eq=2,endkeys,required" - // gt=0 will be applied to the map itself - // eg=1|eq=2 will be applied to each array element in the the map keys - // required will be applied to map values - -Required - -This validates that the value is not the data types default zero value. -For numbers ensures value is not zero. For strings ensures value is -not "". For slices, maps, pointers, interfaces, channels and functions -ensures the value is not nil. - - Usage: required - -Required If - -The field under validation must be present and not empty only if all -the other specified fields are equal to the value following the specified -field. For strings ensures value is not "". For slices, maps, pointers, -interfaces, channels and functions ensures the value is not nil. - - Usage: required_if - -Examples: - - // require the field if the Field1 is equal to the parameter given: - Usage: required_if=Field1 foobar - - // require the field if the Field1 and Field2 is equal to the value respectively: - Usage: required_if=Field1 foo Field2 bar - -Required Unless - -The field under validation must be present and not empty unless all -the other specified fields are equal to the value following the specified -field. For strings ensures value is not "". For slices, maps, pointers, -interfaces, channels and functions ensures the value is not nil. - - Usage: required_unless - -Examples: - - // require the field unless the Field1 is equal to the parameter given: - Usage: required_unless=Field1 foobar - - // require the field unless the Field1 and Field2 is equal to the value respectively: - Usage: required_unless=Field1 foo Field2 bar - -Required With - -The field under validation must be present and not empty only if any -of the other specified fields are present. For strings ensures value is -not "". For slices, maps, pointers, interfaces, channels and functions -ensures the value is not nil. - - Usage: required_with - -Examples: - - // require the field if the Field1 is present: - Usage: required_with=Field1 - - // require the field if the Field1 or Field2 is present: - Usage: required_with=Field1 Field2 - -Required With All - -The field under validation must be present and not empty only if all -of the other specified fields are present. For strings ensures value is -not "". For slices, maps, pointers, interfaces, channels and functions -ensures the value is not nil. - - Usage: required_with_all - -Example: - - // require the field if the Field1 and Field2 is present: - Usage: required_with_all=Field1 Field2 - -Required Without - -The field under validation must be present and not empty only when any -of the other specified fields are not present. For strings ensures value is -not "". For slices, maps, pointers, interfaces, channels and functions -ensures the value is not nil. - - Usage: required_without - -Examples: - - // require the field if the Field1 is not present: - Usage: required_without=Field1 - - // require the field if the Field1 or Field2 is not present: - Usage: required_without=Field1 Field2 - -Required Without All - -The field under validation must be present and not empty only when all -of the other specified fields are not present. For strings ensures value is -not "". For slices, maps, pointers, interfaces, channels and functions -ensures the value is not nil. - - Usage: required_without_all - -Example: - - // require the field if the Field1 and Field2 is not present: - Usage: required_without_all=Field1 Field2 - -Excluded If - -The field under validation must not be present or not empty only if all -the other specified fields are equal to the value following the specified -field. For strings ensures value is not "". For slices, maps, pointers, -interfaces, channels and functions ensures the value is not nil. - - Usage: excluded_if - -Examples: - - // exclude the field if the Field1 is equal to the parameter given: - Usage: excluded_if=Field1 foobar - - // exclude the field if the Field1 and Field2 is equal to the value respectively: - Usage: excluded_if=Field1 foo Field2 bar - -Excluded Unless - -The field under validation must not be present or empty unless all -the other specified fields are equal to the value following the specified -field. For strings ensures value is not "". For slices, maps, pointers, -interfaces, channels and functions ensures the value is not nil. - - Usage: excluded_unless - -Examples: - - // exclude the field unless the Field1 is equal to the parameter given: - Usage: excluded_unless=Field1 foobar - - // exclude the field unless the Field1 and Field2 is equal to the value respectively: - Usage: excluded_unless=Field1 foo Field2 bar - -Is Default - -This validates that the value is the default value and is almost the -opposite of required. - - Usage: isdefault - -Length - -For numbers, length will ensure that the value is -equal to the parameter given. For strings, it checks that -the string length is exactly that number of characters. For slices, -arrays, and maps, validates the number of items. - -Example #1 - - Usage: len=10 - -Example #2 (time.Duration) - -For time.Duration, len will ensure that the value is equal to the duration given -in the parameter. - - Usage: len=1h30m - -Maximum - -For numbers, max will ensure that the value is -less than or equal to the parameter given. For strings, it checks -that the string length is at most that number of characters. For -slices, arrays, and maps, validates the number of items. - -Example #1 - - Usage: max=10 - -Example #2 (time.Duration) - -For time.Duration, max will ensure that the value is less than or equal to the -duration given in the parameter. - - Usage: max=1h30m - -Minimum - -For numbers, min will ensure that the value is -greater or equal to the parameter given. For strings, it checks that -the string length is at least that number of characters. For slices, -arrays, and maps, validates the number of items. - -Example #1 - - Usage: min=10 - -Example #2 (time.Duration) - -For time.Duration, min will ensure that the value is greater than or equal to -the duration given in the parameter. - - Usage: min=1h30m - -Equals - -For strings & numbers, eq will ensure that the value is -equal to the parameter given. For slices, arrays, and maps, -validates the number of items. - -Example #1 - - Usage: eq=10 - -Example #2 (time.Duration) - -For time.Duration, eq will ensure that the value is equal to the duration given -in the parameter. - - Usage: eq=1h30m - -Not Equal - -For strings & numbers, ne will ensure that the value is not -equal to the parameter given. For slices, arrays, and maps, -validates the number of items. - -Example #1 - - Usage: ne=10 - -Example #2 (time.Duration) - -For time.Duration, ne will ensure that the value is not equal to the duration -given in the parameter. - - Usage: ne=1h30m - -One Of - -For strings, ints, and uints, oneof will ensure that the value -is one of the values in the parameter. The parameter should be -a list of values separated by whitespace. Values may be -strings or numbers. To match strings with spaces in them, include -the target string between single quotes. - - Usage: oneof=red green - oneof='red green' 'blue yellow' - oneof=5 7 9 - -Greater Than - -For numbers, this will ensure that the value is greater than the -parameter given. For strings, it checks that the string length -is greater than that number of characters. For slices, arrays -and maps it validates the number of items. - -Example #1 - - Usage: gt=10 - -Example #2 (time.Time) - -For time.Time ensures the time value is greater than time.Now.UTC(). - - Usage: gt - -Example #3 (time.Duration) - -For time.Duration, gt will ensure that the value is greater than the duration -given in the parameter. - - Usage: gt=1h30m - -Greater Than or Equal - -Same as 'min' above. Kept both to make terminology with 'len' easier. - -Example #1 - - Usage: gte=10 - -Example #2 (time.Time) - -For time.Time ensures the time value is greater than or equal to time.Now.UTC(). - - Usage: gte - -Example #3 (time.Duration) - -For time.Duration, gte will ensure that the value is greater than or equal to -the duration given in the parameter. - - Usage: gte=1h30m - -Less Than - -For numbers, this will ensure that the value is less than the parameter given. -For strings, it checks that the string length is less than that number of -characters. For slices, arrays, and maps it validates the number of items. - -Example #1 - - Usage: lt=10 - -Example #2 (time.Time) - -For time.Time ensures the time value is less than time.Now.UTC(). - - Usage: lt - -Example #3 (time.Duration) - -For time.Duration, lt will ensure that the value is less than the duration given -in the parameter. - - Usage: lt=1h30m - -Less Than or Equal - -Same as 'max' above. Kept both to make terminology with 'len' easier. - -Example #1 - - Usage: lte=10 - -Example #2 (time.Time) - -For time.Time ensures the time value is less than or equal to time.Now.UTC(). - - Usage: lte - -Example #3 (time.Duration) - -For time.Duration, lte will ensure that the value is less than or equal to the -duration given in the parameter. - - Usage: lte=1h30m - -Field Equals Another Field - -This will validate the field value against another fields value either within -a struct or passed in field. - -Example #1: - - // Validation on Password field using: - Usage: eqfield=ConfirmPassword - -Example #2: - - // Validating by field: - validate.VarWithValue(password, confirmpassword, "eqfield") - -Field Equals Another Field (relative) - -This does the same as eqfield except that it validates the field provided relative -to the top level struct. - - Usage: eqcsfield=InnerStructField.Field) - -Field Does Not Equal Another Field - -This will validate the field value against another fields value either within -a struct or passed in field. - -Examples: - - // Confirm two colors are not the same: - // - // Validation on Color field: - Usage: nefield=Color2 - - // Validating by field: - validate.VarWithValue(color1, color2, "nefield") - -Field Does Not Equal Another Field (relative) - -This does the same as nefield except that it validates the field provided -relative to the top level struct. - - Usage: necsfield=InnerStructField.Field - -Field Greater Than Another Field - -Only valid for Numbers, time.Duration and time.Time types, this will validate -the field value against another fields value either within a struct or passed in -field. usage examples are for validation of a Start and End date: - -Example #1: - - // Validation on End field using: - validate.Struct Usage(gtfield=Start) - -Example #2: - - // Validating by field: - validate.VarWithValue(start, end, "gtfield") - -Field Greater Than Another Relative Field - -This does the same as gtfield except that it validates the field provided -relative to the top level struct. - - Usage: gtcsfield=InnerStructField.Field - -Field Greater Than or Equal To Another Field - -Only valid for Numbers, time.Duration and time.Time types, this will validate -the field value against another fields value either within a struct or passed in -field. usage examples are for validation of a Start and End date: - -Example #1: - - // Validation on End field using: - validate.Struct Usage(gtefield=Start) - -Example #2: - - // Validating by field: - validate.VarWithValue(start, end, "gtefield") - -Field Greater Than or Equal To Another Relative Field - -This does the same as gtefield except that it validates the field provided relative -to the top level struct. - - Usage: gtecsfield=InnerStructField.Field - -Less Than Another Field - -Only valid for Numbers, time.Duration and time.Time types, this will validate -the field value against another fields value either within a struct or passed in -field. usage examples are for validation of a Start and End date: - -Example #1: - - // Validation on End field using: - validate.Struct Usage(ltfield=Start) - -Example #2: - - // Validating by field: - validate.VarWithValue(start, end, "ltfield") - -Less Than Another Relative Field - -This does the same as ltfield except that it validates the field provided relative -to the top level struct. - - Usage: ltcsfield=InnerStructField.Field - -Less Than or Equal To Another Field - -Only valid for Numbers, time.Duration and time.Time types, this will validate -the field value against another fields value either within a struct or passed in -field. usage examples are for validation of a Start and End date: - -Example #1: - - // Validation on End field using: - validate.Struct Usage(ltefield=Start) - -Example #2: - - // Validating by field: - validate.VarWithValue(start, end, "ltefield") - -Less Than or Equal To Another Relative Field - -This does the same as ltefield except that it validates the field provided relative -to the top level struct. - - Usage: ltecsfield=InnerStructField.Field - -Field Contains Another Field - -This does the same as contains except for struct fields. It should only be used -with string types. See the behavior of reflect.Value.String() for behavior on -other types. - - Usage: containsfield=InnerStructField.Field - -Field Excludes Another Field - -This does the same as excludes except for struct fields. It should only be used -with string types. See the behavior of reflect.Value.String() for behavior on -other types. - - Usage: excludesfield=InnerStructField.Field - -Unique - -For arrays & slices, unique will ensure that there are no duplicates. -For maps, unique will ensure that there are no duplicate values. -For slices of struct, unique will ensure that there are no duplicate values -in a field of the struct specified via a parameter. - - // For arrays, slices, and maps: - Usage: unique - - // For slices of struct: - Usage: unique=field - -Alpha Only - -This validates that a string value contains ASCII alpha characters only - - Usage: alpha - -Alphanumeric - -This validates that a string value contains ASCII alphanumeric characters only - - Usage: alphanum - -Alpha Unicode - -This validates that a string value contains unicode alpha characters only - - Usage: alphaunicode - -Alphanumeric Unicode - -This validates that a string value contains unicode alphanumeric characters only - - Usage: alphanumunicode - -Boolean - -This validates that a string value can successfully be parsed into a boolean with strconv.ParseBool - - Usage: boolean - -Number - -This validates that a string value contains number values only. -For integers or float it returns true. - - Usage: number - -Numeric - -This validates that a string value contains a basic numeric value. -basic excludes exponents etc... -for integers or float it returns true. - - Usage: numeric - -Hexadecimal String - -This validates that a string value contains a valid hexadecimal. - - Usage: hexadecimal - -Hexcolor String - -This validates that a string value contains a valid hex color including -hashtag (#) - - Usage: hexcolor - -Lowercase String - -This validates that a string value contains only lowercase characters. An empty string is not a valid lowercase string. - - Usage: lowercase - -Uppercase String - -This validates that a string value contains only uppercase characters. An empty string is not a valid uppercase string. - - Usage: uppercase - -RGB String - -This validates that a string value contains a valid rgb color - - Usage: rgb - -RGBA String - -This validates that a string value contains a valid rgba color - - Usage: rgba - -HSL String - -This validates that a string value contains a valid hsl color - - Usage: hsl - -HSLA String - -This validates that a string value contains a valid hsla color - - Usage: hsla - -E.164 Phone Number String - -This validates that a string value contains a valid E.164 Phone number -https://en.wikipedia.org/wiki/E.164 (ex. +1123456789) - - Usage: e164 - -E-mail String - -This validates that a string value contains a valid email -This may not conform to all possibilities of any rfc standard, but neither -does any email provider accept all possibilities. - - Usage: email - -JSON String - -This validates that a string value is valid JSON - - Usage: json - -JWT String - -This validates that a string value is a valid JWT - - Usage: jwt - -File path - -This validates that a string value contains a valid file path and that -the file exists on the machine. -This is done using os.Stat, which is a platform independent function. - - Usage: file - -URL String - -This validates that a string value contains a valid url -This will accept any url the golang request uri accepts but must contain -a schema for example http:// or rtmp:// - - Usage: url - -URI String - -This validates that a string value contains a valid uri -This will accept any uri the golang request uri accepts - - Usage: uri - -Urn RFC 2141 String - -This validataes that a string value contains a valid URN -according to the RFC 2141 spec. - - Usage: urn_rfc2141 - -Base64 String - -This validates that a string value contains a valid base64 value. -Although an empty string is valid base64 this will report an empty string -as an error, if you wish to accept an empty string as valid you can use -this with the omitempty tag. - - Usage: base64 - -Base64URL String - -This validates that a string value contains a valid base64 URL safe value -according the the RFC4648 spec. -Although an empty string is a valid base64 URL safe value, this will report -an empty string as an error, if you wish to accept an empty string as valid -you can use this with the omitempty tag. - - Usage: base64url - -Bitcoin Address - -This validates that a string value contains a valid bitcoin address. -The format of the string is checked to ensure it matches one of the three formats -P2PKH, P2SH and performs checksum validation. - - Usage: btc_addr - -Bitcoin Bech32 Address (segwit) - -This validates that a string value contains a valid bitcoin Bech32 address as defined -by bip-0173 (https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) -Special thanks to Pieter Wuille for providng reference implementations. - - Usage: btc_addr_bech32 - -Ethereum Address - -This validates that a string value contains a valid ethereum address. -The format of the string is checked to ensure it matches the standard Ethereum address format. - - Usage: eth_addr - -Contains - -This validates that a string value contains the substring value. - - Usage: contains=@ - -Contains Any - -This validates that a string value contains any Unicode code points -in the substring value. - - Usage: containsany=!@#? - -Contains Rune - -This validates that a string value contains the supplied rune value. - - Usage: containsrune=@ - -Excludes - -This validates that a string value does not contain the substring value. - - Usage: excludes=@ - -Excludes All - -This validates that a string value does not contain any Unicode code -points in the substring value. - - Usage: excludesall=!@#? - -Excludes Rune - -This validates that a string value does not contain the supplied rune value. - - Usage: excludesrune=@ - -Starts With - -This validates that a string value starts with the supplied string value - - Usage: startswith=hello - -Ends With - -This validates that a string value ends with the supplied string value - - Usage: endswith=goodbye - -Does Not Start With - -This validates that a string value does not start with the supplied string value - - Usage: startsnotwith=hello - -Does Not End With - -This validates that a string value does not end with the supplied string value - - Usage: endsnotwith=goodbye - -International Standard Book Number - -This validates that a string value contains a valid isbn10 or isbn13 value. - - Usage: isbn - -International Standard Book Number 10 - -This validates that a string value contains a valid isbn10 value. - - Usage: isbn10 - -International Standard Book Number 13 - -This validates that a string value contains a valid isbn13 value. - - Usage: isbn13 - -Universally Unique Identifier UUID - -This validates that a string value contains a valid UUID. Uppercase UUID values will not pass - use `uuid_rfc4122` instead. - - Usage: uuid - -Universally Unique Identifier UUID v3 - -This validates that a string value contains a valid version 3 UUID. Uppercase UUID values will not pass - use `uuid3_rfc4122` instead. - - Usage: uuid3 - -Universally Unique Identifier UUID v4 - -This validates that a string value contains a valid version 4 UUID. Uppercase UUID values will not pass - use `uuid4_rfc4122` instead. - - Usage: uuid4 - -Universally Unique Identifier UUID v5 - -This validates that a string value contains a valid version 5 UUID. Uppercase UUID values will not pass - use `uuid5_rfc4122` instead. - - Usage: uuid5 - -Universally Unique Lexicographically Sortable Identifier ULID - -This validates that a string value contains a valid ULID value. - - Usage: ulid - -ASCII - -This validates that a string value contains only ASCII characters. -NOTE: if the string is blank, this validates as true. - - Usage: ascii - -Printable ASCII - -This validates that a string value contains only printable ASCII characters. -NOTE: if the string is blank, this validates as true. - - Usage: printascii - -Multi-Byte Characters - -This validates that a string value contains one or more multibyte characters. -NOTE: if the string is blank, this validates as true. - - Usage: multibyte - -Data URL - -This validates that a string value contains a valid DataURI. -NOTE: this will also validate that the data portion is valid base64 - - Usage: datauri - -Latitude - -This validates that a string value contains a valid latitude. - - Usage: latitude - -Longitude - -This validates that a string value contains a valid longitude. - - Usage: longitude - -Social Security Number SSN - -This validates that a string value contains a valid U.S. Social Security Number. - - Usage: ssn - -Internet Protocol Address IP - -This validates that a string value contains a valid IP Address. - - Usage: ip - -Internet Protocol Address IPv4 - -This validates that a string value contains a valid v4 IP Address. - - Usage: ipv4 - -Internet Protocol Address IPv6 - -This validates that a string value contains a valid v6 IP Address. - - Usage: ipv6 - -Classless Inter-Domain Routing CIDR - -This validates that a string value contains a valid CIDR Address. - - Usage: cidr - -Classless Inter-Domain Routing CIDRv4 - -This validates that a string value contains a valid v4 CIDR Address. - - Usage: cidrv4 - -Classless Inter-Domain Routing CIDRv6 - -This validates that a string value contains a valid v6 CIDR Address. - - Usage: cidrv6 - -Transmission Control Protocol Address TCP - -This validates that a string value contains a valid resolvable TCP Address. - - Usage: tcp_addr - -Transmission Control Protocol Address TCPv4 - -This validates that a string value contains a valid resolvable v4 TCP Address. - - Usage: tcp4_addr - -Transmission Control Protocol Address TCPv6 - -This validates that a string value contains a valid resolvable v6 TCP Address. - - Usage: tcp6_addr - -User Datagram Protocol Address UDP - -This validates that a string value contains a valid resolvable UDP Address. - - Usage: udp_addr - -User Datagram Protocol Address UDPv4 - -This validates that a string value contains a valid resolvable v4 UDP Address. - - Usage: udp4_addr - -User Datagram Protocol Address UDPv6 - -This validates that a string value contains a valid resolvable v6 UDP Address. - - Usage: udp6_addr - -Internet Protocol Address IP - -This validates that a string value contains a valid resolvable IP Address. - - Usage: ip_addr - -Internet Protocol Address IPv4 - -This validates that a string value contains a valid resolvable v4 IP Address. - - Usage: ip4_addr - -Internet Protocol Address IPv6 - -This validates that a string value contains a valid resolvable v6 IP Address. - - Usage: ip6_addr - -Unix domain socket end point Address - -This validates that a string value contains a valid Unix Address. - - Usage: unix_addr - -Media Access Control Address MAC - -This validates that a string value contains a valid MAC Address. - - Usage: mac - -Note: See Go's ParseMAC for accepted formats and types: - - http://golang.org/src/net/mac.go?s=866:918#L29 - -Hostname RFC 952 - -This validates that a string value is a valid Hostname according to RFC 952 https://tools.ietf.org/html/rfc952 - - Usage: hostname - -Hostname RFC 1123 - -This validates that a string value is a valid Hostname according to RFC 1123 https://tools.ietf.org/html/rfc1123 - - Usage: hostname_rfc1123 or if you want to continue to use 'hostname' in your tags, create an alias. - -Full Qualified Domain Name (FQDN) - -This validates that a string value contains a valid FQDN. - - Usage: fqdn - -HTML Tags - -This validates that a string value appears to be an HTML element tag -including those described at https://developer.mozilla.org/en-US/docs/Web/HTML/Element - - Usage: html - -HTML Encoded - -This validates that a string value is a proper character reference in decimal -or hexadecimal format - - Usage: html_encoded - -URL Encoded - -This validates that a string value is percent-encoded (URL encoded) according -to https://tools.ietf.org/html/rfc3986#section-2.1 - - Usage: url_encoded - -Directory - -This validates that a string value contains a valid directory and that -it exists on the machine. -This is done using os.Stat, which is a platform independent function. - - Usage: dir - -HostPort - -This validates that a string value contains a valid DNS hostname and port that -can be used to valiate fields typically passed to sockets and connections. - - Usage: hostname_port - -Datetime - -This validates that a string value is a valid datetime based on the supplied datetime format. -Supplied format must match the official Go time format layout as documented in https://golang.org/pkg/time/ - - Usage: datetime=2006-01-02 - -Iso3166-1 alpha-2 - -This validates that a string value is a valid country code based on iso3166-1 alpha-2 standard. -see: https://www.iso.org/iso-3166-country-codes.html - - Usage: iso3166_1_alpha2 - -Iso3166-1 alpha-3 - -This validates that a string value is a valid country code based on iso3166-1 alpha-3 standard. -see: https://www.iso.org/iso-3166-country-codes.html - - Usage: iso3166_1_alpha3 - -Iso3166-1 alpha-numeric - -This validates that a string value is a valid country code based on iso3166-1 alpha-numeric standard. -see: https://www.iso.org/iso-3166-country-codes.html - - Usage: iso3166_1_alpha3 - -BCP 47 Language Tag - -This validates that a string value is a valid BCP 47 language tag, as parsed by language.Parse. -More information on https://pkg.go.dev/golang.org/x/text/language - - Usage: bcp47_language_tag - -BIC (SWIFT code) - -This validates that a string value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362. -More information on https://www.iso.org/standard/60390.html - - Usage: bic - -RFC 1035 label - -This validates that a string value is a valid dns RFC 1035 label, defined in RFC 1035. -More information on https://datatracker.ietf.org/doc/html/rfc1035 - - Usage: dns_rfc1035_label - -TimeZone - -This validates that a string value is a valid time zone based on the time zone database present on the system. -Although empty value and Local value are allowed by time.LoadLocation golang function, they are not allowed by this validator. -More information on https://golang.org/pkg/time/#LoadLocation - - Usage: timezone - -Semantic Version - -This validates that a string value is a valid semver version, defined in Semantic Versioning 2.0.0. -More information on https://semver.org/ - - Usage: semver - -Credit Card - -This validates that a string value contains a valid credit card number using Luhn algoritm. - - Usage: credit_card - -Alias Validators and Tags - -NOTE: When returning an error, the tag returned in "FieldError" will be -the alias tag unless the dive tag is part of the alias. Everything after the -dive tag is not reported as the alias tag. Also, the "ActualTag" in the before -case will be the actual tag within the alias that failed. - -Here is a list of the current built in alias tags: - - "iscolor" - alias is "hexcolor|rgb|rgba|hsl|hsla" (Usage: iscolor) - "country_code" - alias is "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric" (Usage: country_code) - -Validator notes: - - regex - a regex validator won't be added because commas and = signs can be part - of a regex which conflict with the validation definitions. Although - workarounds can be made, they take away from using pure regex's. - Furthermore it's quick and dirty but the regex's become harder to - maintain and are not reusable, so it's as much a programming philosophy - as anything. - - In place of this new validator functions should be created; a regex can - be used within the validator function and even be precompiled for better - efficiency within regexes.go. - - And the best reason, you can submit a pull request and we can keep on - adding to the validation library of this package! - -Non standard validators - -A collection of validation rules that are frequently needed but are more -complex than the ones found in the baked in validators. -A non standard validator must be registered manually like you would -with your own custom validation functions. - -Example of registration and use: - - type Test struct { - TestField string `validate:"yourtag"` - } - - t := &Test{ - TestField: "Test" - } - - validate := validator.New() - validate.RegisterValidation("yourtag", validators.NotBlank) - -Here is a list of the current non standard validators: - - NotBlank - This validates that the value is not blank or with length zero. - For strings ensures they do not contain only spaces. For channels, maps, slices and arrays - ensures they don't have zero length. For others, a non empty value is required. - - Usage: notblank - -Panics - -This package panics when bad input is provided, this is by design, bad code like -that should not make it to production. - - type Test struct { - TestField string `validate:"nonexistantfunction=1"` - } - - t := &Test{ - TestField: "Test" - } - - validate.Struct(t) // this will panic -*/ -package validator diff --git a/vendor/github.com/go-playground/validator/v10/errors.go b/vendor/github.com/go-playground/validator/v10/errors.go deleted file mode 100644 index 9a1b1ab..0000000 --- a/vendor/github.com/go-playground/validator/v10/errors.go +++ /dev/null @@ -1,275 +0,0 @@ -package validator - -import ( - "bytes" - "fmt" - "reflect" - "strings" - - ut "github.com/go-playground/universal-translator" -) - -const ( - fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag" -) - -// ValidationErrorsTranslations is the translation return type -type ValidationErrorsTranslations map[string]string - -// InvalidValidationError describes an invalid argument passed to -// `Struct`, `StructExcept`, StructPartial` or `Field` -type InvalidValidationError struct { - Type reflect.Type -} - -// Error returns InvalidValidationError message -func (e *InvalidValidationError) Error() string { - - if e.Type == nil { - return "validator: (nil)" - } - - return "validator: (nil " + e.Type.String() + ")" -} - -// ValidationErrors is an array of FieldError's -// for use in custom error messages post validation. -type ValidationErrors []FieldError - -// Error is intended for use in development + debugging and not intended to be a production error message. -// It allows ValidationErrors to subscribe to the Error interface. -// All information to create an error message specific to your application is contained within -// the FieldError found within the ValidationErrors array -func (ve ValidationErrors) Error() string { - - buff := bytes.NewBufferString("") - - var fe *fieldError - - for i := 0; i < len(ve); i++ { - - fe = ve[i].(*fieldError) - buff.WriteString(fe.Error()) - buff.WriteString("\n") - } - - return strings.TrimSpace(buff.String()) -} - -// Translate translates all of the ValidationErrors -func (ve ValidationErrors) Translate(ut ut.Translator) ValidationErrorsTranslations { - - trans := make(ValidationErrorsTranslations) - - var fe *fieldError - - for i := 0; i < len(ve); i++ { - fe = ve[i].(*fieldError) - - // // in case an Anonymous struct was used, ensure that the key - // // would be 'Username' instead of ".Username" - // if len(fe.ns) > 0 && fe.ns[:1] == "." { - // trans[fe.ns[1:]] = fe.Translate(ut) - // continue - // } - - trans[fe.ns] = fe.Translate(ut) - } - - return trans -} - -// FieldError contains all functions to get error details -type FieldError interface { - - // Tag returns the validation tag that failed. if the - // validation was an alias, this will return the - // alias name and not the underlying tag that failed. - // - // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla" - // will return "iscolor" - Tag() string - - // ActualTag returns the validation tag that failed, even if an - // alias the actual tag within the alias will be returned. - // If an 'or' validation fails the entire or will be returned. - // - // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla" - // will return "hexcolor|rgb|rgba|hsl|hsla" - ActualTag() string - - // Namespace returns the namespace for the field error, with the tag - // name taking precedence over the field's actual name. - // - // eg. JSON name "User.fname" - // - // See StructNamespace() for a version that returns actual names. - // - // NOTE: this field can be blank when validating a single primitive field - // using validate.Field(...) as there is no way to extract it's name - Namespace() string - - // StructNamespace returns the namespace for the field error, with the field's - // actual name. - // - // eq. "User.FirstName" see Namespace for comparison - // - // NOTE: this field can be blank when validating a single primitive field - // using validate.Field(...) as there is no way to extract its name - StructNamespace() string - - // Field returns the fields name with the tag name taking precedence over the - // field's actual name. - // - // eq. JSON name "fname" - // see StructField for comparison - Field() string - - // StructField returns the field's actual name from the struct, when able to determine. - // - // eq. "FirstName" - // see Field for comparison - StructField() string - - // Value returns the actual field's value in case needed for creating the error - // message - Value() interface{} - - // Param returns the param value, in string form for comparison; this will also - // help with generating an error message - Param() string - - // Kind returns the Field's reflect Kind - // - // eg. time.Time's kind is a struct - Kind() reflect.Kind - - // Type returns the Field's reflect Type - // - // eg. time.Time's type is time.Time - Type() reflect.Type - - // Translate returns the FieldError's translated error - // from the provided 'ut.Translator' and registered 'TranslationFunc' - // - // NOTE: if no registered translator can be found it returns the same as - // calling fe.Error() - Translate(ut ut.Translator) string - - // Error returns the FieldError's message - Error() string -} - -// compile time interface checks -var _ FieldError = new(fieldError) -var _ error = new(fieldError) - -// fieldError contains a single field's validation error along -// with other properties that may be needed for error message creation -// it complies with the FieldError interface -type fieldError struct { - v *Validate - tag string - actualTag string - ns string - structNs string - fieldLen uint8 - structfieldLen uint8 - value interface{} - param string - kind reflect.Kind - typ reflect.Type -} - -// Tag returns the validation tag that failed. -func (fe *fieldError) Tag() string { - return fe.tag -} - -// ActualTag returns the validation tag that failed, even if an -// alias the actual tag within the alias will be returned. -func (fe *fieldError) ActualTag() string { - return fe.actualTag -} - -// Namespace returns the namespace for the field error, with the tag -// name taking precedence over the field's actual name. -func (fe *fieldError) Namespace() string { - return fe.ns -} - -// StructNamespace returns the namespace for the field error, with the field's -// actual name. -func (fe *fieldError) StructNamespace() string { - return fe.structNs -} - -// Field returns the field's name with the tag name taking precedence over the -// field's actual name. -func (fe *fieldError) Field() string { - - return fe.ns[len(fe.ns)-int(fe.fieldLen):] - // // return fe.field - // fld := fe.ns[len(fe.ns)-int(fe.fieldLen):] - - // log.Println("FLD:", fld) - - // if len(fld) > 0 && fld[:1] == "." { - // return fld[1:] - // } - - // return fld -} - -// StructField returns the field's actual name from the struct, when able to determine. -func (fe *fieldError) StructField() string { - // return fe.structField - return fe.structNs[len(fe.structNs)-int(fe.structfieldLen):] -} - -// Value returns the actual field's value in case needed for creating the error -// message -func (fe *fieldError) Value() interface{} { - return fe.value -} - -// Param returns the param value, in string form for comparison; this will -// also help with generating an error message -func (fe *fieldError) Param() string { - return fe.param -} - -// Kind returns the Field's reflect Kind -func (fe *fieldError) Kind() reflect.Kind { - return fe.kind -} - -// Type returns the Field's reflect Type -func (fe *fieldError) Type() reflect.Type { - return fe.typ -} - -// Error returns the fieldError's error message -func (fe *fieldError) Error() string { - return fmt.Sprintf(fieldErrMsg, fe.ns, fe.Field(), fe.tag) -} - -// Translate returns the FieldError's translated error -// from the provided 'ut.Translator' and registered 'TranslationFunc' -// -// NOTE: if no registered translation can be found, it returns the original -// untranslated error message. -func (fe *fieldError) Translate(ut ut.Translator) string { - - m, ok := fe.v.transTagFunc[ut] - if !ok { - return fe.Error() - } - - fn, ok := m[fe.tag] - if !ok { - return fe.Error() - } - - return fn(ut, fe) -} diff --git a/vendor/github.com/go-playground/validator/v10/field_level.go b/vendor/github.com/go-playground/validator/v10/field_level.go deleted file mode 100644 index ef35826..0000000 --- a/vendor/github.com/go-playground/validator/v10/field_level.go +++ /dev/null @@ -1,120 +0,0 @@ -package validator - -import "reflect" - -// FieldLevel contains all the information and helper functions -// to validate a field -type FieldLevel interface { - - // Top returns the top level struct, if any - Top() reflect.Value - - // Parent returns the current fields parent struct, if any or - // the comparison value if called 'VarWithValue' - Parent() reflect.Value - - // Field returns current field for validation - Field() reflect.Value - - // FieldName returns the field's name with the tag - // name taking precedence over the fields actual name. - FieldName() string - - // StructFieldName returns the struct field's name - StructFieldName() string - - // Param returns param for validation against current field - Param() string - - // GetTag returns the current validations tag name - GetTag() string - - // ExtractType gets the actual underlying type of field value. - // It will dive into pointers, customTypes and return you the - // underlying value and it's kind. - ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) - - // GetStructFieldOK traverses the parent struct to retrieve a specific field denoted by the provided namespace - // in the param and returns the field, field kind and whether is was successful in retrieving - // the field at all. - // - // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field - // could not be retrieved because it didn't exist. - // - // Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable. - GetStructFieldOK() (reflect.Value, reflect.Kind, bool) - - // GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for - // the field and namespace allowing more extensibility for validators. - // - // Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable. - GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) - - // GetStructFieldOK2 traverses the parent struct to retrieve a specific field denoted by the provided namespace - // in the param and returns the field, field kind, if it's a nullable type and whether is was successful in retrieving - // the field at all. - // - // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field - // could not be retrieved because it didn't exist. - GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) - - // GetStructFieldOKAdvanced2 is the same as GetStructFieldOK except that it accepts the parent struct to start looking for - // the field and namespace allowing more extensibility for validators. - GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) -} - -var _ FieldLevel = new(validate) - -// Field returns current field for validation -func (v *validate) Field() reflect.Value { - return v.flField -} - -// FieldName returns the field's name with the tag -// name taking precedence over the fields actual name. -func (v *validate) FieldName() string { - return v.cf.altName -} - -// GetTag returns the current validations tag name -func (v *validate) GetTag() string { - return v.ct.tag -} - -// StructFieldName returns the struct field's name -func (v *validate) StructFieldName() string { - return v.cf.name -} - -// Param returns param for validation against current field -func (v *validate) Param() string { - return v.ct.param -} - -// GetStructFieldOK returns Param returns param for validation against current field -// -// Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable. -func (v *validate) GetStructFieldOK() (reflect.Value, reflect.Kind, bool) { - current, kind, _, found := v.getStructFieldOKInternal(v.slflParent, v.ct.param) - return current, kind, found -} - -// GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for -// the field and namespace allowing more extensibility for validators. -// -// Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable. -func (v *validate) GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) { - current, kind, _, found := v.GetStructFieldOKAdvanced2(val, namespace) - return current, kind, found -} - -// GetStructFieldOK2 returns Param returns param for validation against current field -func (v *validate) GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) { - return v.getStructFieldOKInternal(v.slflParent, v.ct.param) -} - -// GetStructFieldOKAdvanced2 is the same as GetStructFieldOK except that it accepts the parent struct to start looking for -// the field and namespace allowing more extensibility for validators. -func (v *validate) GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) { - return v.getStructFieldOKInternal(val, namespace) -} diff --git a/vendor/github.com/go-playground/validator/v10/logo.png b/vendor/github.com/go-playground/validator/v10/logo.png deleted file mode 100644 index 355000f..0000000 Binary files a/vendor/github.com/go-playground/validator/v10/logo.png and /dev/null differ diff --git a/vendor/github.com/go-playground/validator/v10/postcode_regexes.go b/vendor/github.com/go-playground/validator/v10/postcode_regexes.go deleted file mode 100644 index e7e7b68..0000000 --- a/vendor/github.com/go-playground/validator/v10/postcode_regexes.go +++ /dev/null @@ -1,173 +0,0 @@ -package validator - -import "regexp" - -var postCodePatternDict = map[string]string{ - "GB": `^GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\d{1,4}$`, - "JE": `^JE\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, - "GG": `^GY\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, - "IM": `^IM\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, - "US": `^\d{5}([ \-]\d{4})?$`, - "CA": `^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJ-NPRSTV-Z][ ]?\d[ABCEGHJ-NPRSTV-Z]\d$`, - "DE": `^\d{5}$`, - "JP": `^\d{3}-\d{4}$`, - "FR": `^\d{2}[ ]?\d{3}$`, - "AU": `^\d{4}$`, - "IT": `^\d{5}$`, - "CH": `^\d{4}$`, - "AT": `^\d{4}$`, - "ES": `^\d{5}$`, - "NL": `^\d{4}[ ]?[A-Z]{2}$`, - "BE": `^\d{4}$`, - "DK": `^\d{4}$`, - "SE": `^\d{3}[ ]?\d{2}$`, - "NO": `^\d{4}$`, - "BR": `^\d{5}[\-]?\d{3}$`, - "PT": `^\d{4}([\-]\d{3})?$`, - "FI": `^\d{5}$`, - "AX": `^22\d{3}$`, - "KR": `^\d{3}[\-]\d{3}$`, - "CN": `^\d{6}$`, - "TW": `^\d{3}(\d{2})?$`, - "SG": `^\d{6}$`, - "DZ": `^\d{5}$`, - "AD": `^AD\d{3}$`, - "AR": `^([A-HJ-NP-Z])?\d{4}([A-Z]{3})?$`, - "AM": `^(37)?\d{4}$`, - "AZ": `^\d{4}$`, - "BH": `^((1[0-2]|[2-9])\d{2})?$`, - "BD": `^\d{4}$`, - "BB": `^(BB\d{5})?$`, - "BY": `^\d{6}$`, - "BM": `^[A-Z]{2}[ ]?[A-Z0-9]{2}$`, - "BA": `^\d{5}$`, - "IO": `^BBND 1ZZ$`, - "BN": `^[A-Z]{2}[ ]?\d{4}$`, - "BG": `^\d{4}$`, - "KH": `^\d{5}$`, - "CV": `^\d{4}$`, - "CL": `^\d{7}$`, - "CR": `^\d{4,5}|\d{3}-\d{4}$`, - "HR": `^\d{5}$`, - "CY": `^\d{4}$`, - "CZ": `^\d{3}[ ]?\d{2}$`, - "DO": `^\d{5}$`, - "EC": `^([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?$`, - "EG": `^\d{5}$`, - "EE": `^\d{5}$`, - "FO": `^\d{3}$`, - "GE": `^\d{4}$`, - "GR": `^\d{3}[ ]?\d{2}$`, - "GL": `^39\d{2}$`, - "GT": `^\d{5}$`, - "HT": `^\d{4}$`, - "HN": `^(?:\d{5})?$`, - "HU": `^\d{4}$`, - "IS": `^\d{3}$`, - "IN": `^\d{6}$`, - "ID": `^\d{5}$`, - "IL": `^\d{5}$`, - "JO": `^\d{5}$`, - "KZ": `^\d{6}$`, - "KE": `^\d{5}$`, - "KW": `^\d{5}$`, - "LA": `^\d{5}$`, - "LV": `^\d{4}$`, - "LB": `^(\d{4}([ ]?\d{4})?)?$`, - "LI": `^(948[5-9])|(949[0-7])$`, - "LT": `^\d{5}$`, - "LU": `^\d{4}$`, - "MK": `^\d{4}$`, - "MY": `^\d{5}$`, - "MV": `^\d{5}$`, - "MT": `^[A-Z]{3}[ ]?\d{2,4}$`, - "MU": `^(\d{3}[A-Z]{2}\d{3})?$`, - "MX": `^\d{5}$`, - "MD": `^\d{4}$`, - "MC": `^980\d{2}$`, - "MA": `^\d{5}$`, - "NP": `^\d{5}$`, - "NZ": `^\d{4}$`, - "NI": `^((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?$`, - "NG": `^(\d{6})?$`, - "OM": `^(PC )?\d{3}$`, - "PK": `^\d{5}$`, - "PY": `^\d{4}$`, - "PH": `^\d{4}$`, - "PL": `^\d{2}-\d{3}$`, - "PR": `^00[679]\d{2}([ \-]\d{4})?$`, - "RO": `^\d{6}$`, - "RU": `^\d{6}$`, - "SM": `^4789\d$`, - "SA": `^\d{5}$`, - "SN": `^\d{5}$`, - "SK": `^\d{3}[ ]?\d{2}$`, - "SI": `^\d{4}$`, - "ZA": `^\d{4}$`, - "LK": `^\d{5}$`, - "TJ": `^\d{6}$`, - "TH": `^\d{5}$`, - "TN": `^\d{4}$`, - "TR": `^\d{5}$`, - "TM": `^\d{6}$`, - "UA": `^\d{5}$`, - "UY": `^\d{5}$`, - "UZ": `^\d{6}$`, - "VA": `^00120$`, - "VE": `^\d{4}$`, - "ZM": `^\d{5}$`, - "AS": `^96799$`, - "CC": `^6799$`, - "CK": `^\d{4}$`, - "RS": `^\d{6}$`, - "ME": `^8\d{4}$`, - "CS": `^\d{5}$`, - "YU": `^\d{5}$`, - "CX": `^6798$`, - "ET": `^\d{4}$`, - "FK": `^FIQQ 1ZZ$`, - "NF": `^2899$`, - "FM": `^(9694[1-4])([ \-]\d{4})?$`, - "GF": `^9[78]3\d{2}$`, - "GN": `^\d{3}$`, - "GP": `^9[78][01]\d{2}$`, - "GS": `^SIQQ 1ZZ$`, - "GU": `^969[123]\d([ \-]\d{4})?$`, - "GW": `^\d{4}$`, - "HM": `^\d{4}$`, - "IQ": `^\d{5}$`, - "KG": `^\d{6}$`, - "LR": `^\d{4}$`, - "LS": `^\d{3}$`, - "MG": `^\d{3}$`, - "MH": `^969[67]\d([ \-]\d{4})?$`, - "MN": `^\d{6}$`, - "MP": `^9695[012]([ \-]\d{4})?$`, - "MQ": `^9[78]2\d{2}$`, - "NC": `^988\d{2}$`, - "NE": `^\d{4}$`, - "VI": `^008(([0-4]\d)|(5[01]))([ \-]\d{4})?$`, - "VN": `^[0-9]{1,6}$`, - "PF": `^987\d{2}$`, - "PG": `^\d{3}$`, - "PM": `^9[78]5\d{2}$`, - "PN": `^PCRN 1ZZ$`, - "PW": `^96940$`, - "RE": `^9[78]4\d{2}$`, - "SH": `^(ASCN|STHL) 1ZZ$`, - "SJ": `^\d{4}$`, - "SO": `^\d{5}$`, - "SZ": `^[HLMS]\d{3}$`, - "TC": `^TKCA 1ZZ$`, - "WF": `^986\d{2}$`, - "XK": `^\d{5}$`, - "YT": `^976\d{2}$`, -} - -var postCodeRegexDict = map[string]*regexp.Regexp{} - -func init() { - for countryCode, pattern := range postCodePatternDict { - postCodeRegexDict[countryCode] = regexp.MustCompile(pattern) - } -} diff --git a/vendor/github.com/go-playground/validator/v10/regexes.go b/vendor/github.com/go-playground/validator/v10/regexes.go deleted file mode 100644 index 9c1c634..0000000 --- a/vendor/github.com/go-playground/validator/v10/regexes.go +++ /dev/null @@ -1,131 +0,0 @@ -package validator - -import "regexp" - -const ( - alphaRegexString = "^[a-zA-Z]+$" - alphaNumericRegexString = "^[a-zA-Z0-9]+$" - alphaUnicodeRegexString = "^[\\p{L}]+$" - alphaUnicodeNumericRegexString = "^[\\p{L}\\p{N}]+$" - numericRegexString = "^[-+]?[0-9]+(?:\\.[0-9]+)?$" - numberRegexString = "^[0-9]+$" - hexadecimalRegexString = "^(0[xX])?[0-9a-fA-F]+$" - hexColorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$" - rgbRegexString = "^rgb\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*\\)$" - rgbaRegexString = "^rgba\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$" - hslRegexString = "^hsl\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*\\)$" - hslaRegexString = "^hsla\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$" - emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" - e164RegexString = "^\\+[1-9]?[0-9]{7,14}$" - base64RegexString = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$" - base64URLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2}==|[A-Za-z0-9-_]{3}=|[A-Za-z0-9-_]{4})$" - iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$" - iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$" - uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$" - uUID4RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" - uUID5RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" - uUIDRegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$" - uUID3RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-3[0-9a-fA-F]{3}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" - uUID4RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - uUID5RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-5[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - uUIDRFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" - uLIDRegexString = "^[A-HJKMNP-TV-Z0-9]{26}$" - md4RegexString = "^[0-9a-f]{32}$" - md5RegexString = "^[0-9a-f]{32}$" - sha256RegexString = "^[0-9a-f]{64}$" - sha384RegexString = "^[0-9a-f]{96}$" - sha512RegexString = "^[0-9a-f]{128}$" - ripemd128RegexString = "^[0-9a-f]{32}$" - ripemd160RegexString = "^[0-9a-f]{40}$" - tiger128RegexString = "^[0-9a-f]{32}$" - tiger160RegexString = "^[0-9a-f]{40}$" - tiger192RegexString = "^[0-9a-f]{48}$" - aSCIIRegexString = "^[\x00-\x7F]*$" - printableASCIIRegexString = "^[\x20-\x7E]*$" - multibyteRegexString = "[^\x00-\x7F]" - dataURIRegexString = `^data:((?:\w+\/(?:([^;]|;[^;]).)+)?)` - latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$" - longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$" - sSNRegexString = `^[0-9]{3}[ -]?(0[1-9]|[1-9][0-9])[ -]?([1-9][0-9]{3}|[0-9][1-9][0-9]{2}|[0-9]{2}[1-9][0-9]|[0-9]{3}[1-9])$` - hostnameRegexStringRFC952 = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$` // https://tools.ietf.org/html/rfc952 - hostnameRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62}){1}(\.[a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})*?$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123 - fqdnRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})(\.[a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})*?(\.[a-zA-Z]{1}[a-zA-Z0-9]{0,62})\.?$` // same as hostnameRegexStringRFC1123 but must contain a non numerical TLD (possibly ending with '.') - btcAddressRegexString = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$` // bitcoin address - btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32 - btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32 - ethAddressRegexString = `^0x[0-9a-fA-F]{40}$` - ethAddressUpperRegexString = `^0x[0-9A-F]{40}$` - ethAddressLowerRegexString = `^0x[0-9a-f]{40}$` - uRLEncodedRegexString = `^(?:[^%]|%[0-9A-Fa-f]{2})*$` - hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(>)|(<)|(")|(&)+[;]?` - hTMLRegexString = `<[/]?([a-zA-Z]+).*?>` - jWTRegexString = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$" - splitParamsRegexString = `'[^']*'|\S+` - bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$` - semverRegexString = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` // numbered capture groups https://semver.org/ - dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9]){0,62}$" -) - -var ( - alphaRegex = regexp.MustCompile(alphaRegexString) - alphaNumericRegex = regexp.MustCompile(alphaNumericRegexString) - alphaUnicodeRegex = regexp.MustCompile(alphaUnicodeRegexString) - alphaUnicodeNumericRegex = regexp.MustCompile(alphaUnicodeNumericRegexString) - numericRegex = regexp.MustCompile(numericRegexString) - numberRegex = regexp.MustCompile(numberRegexString) - hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString) - hexColorRegex = regexp.MustCompile(hexColorRegexString) - rgbRegex = regexp.MustCompile(rgbRegexString) - rgbaRegex = regexp.MustCompile(rgbaRegexString) - hslRegex = regexp.MustCompile(hslRegexString) - hslaRegex = regexp.MustCompile(hslaRegexString) - e164Regex = regexp.MustCompile(e164RegexString) - emailRegex = regexp.MustCompile(emailRegexString) - base64Regex = regexp.MustCompile(base64RegexString) - base64URLRegex = regexp.MustCompile(base64URLRegexString) - iSBN10Regex = regexp.MustCompile(iSBN10RegexString) - iSBN13Regex = regexp.MustCompile(iSBN13RegexString) - uUID3Regex = regexp.MustCompile(uUID3RegexString) - uUID4Regex = regexp.MustCompile(uUID4RegexString) - uUID5Regex = regexp.MustCompile(uUID5RegexString) - uUIDRegex = regexp.MustCompile(uUIDRegexString) - uUID3RFC4122Regex = regexp.MustCompile(uUID3RFC4122RegexString) - uUID4RFC4122Regex = regexp.MustCompile(uUID4RFC4122RegexString) - uUID5RFC4122Regex = regexp.MustCompile(uUID5RFC4122RegexString) - uUIDRFC4122Regex = regexp.MustCompile(uUIDRFC4122RegexString) - uLIDRegex = regexp.MustCompile(uLIDRegexString) - md4Regex = regexp.MustCompile(md4RegexString) - md5Regex = regexp.MustCompile(md5RegexString) - sha256Regex = regexp.MustCompile(sha256RegexString) - sha384Regex = regexp.MustCompile(sha384RegexString) - sha512Regex = regexp.MustCompile(sha512RegexString) - ripemd128Regex = regexp.MustCompile(ripemd128RegexString) - ripemd160Regex = regexp.MustCompile(ripemd160RegexString) - tiger128Regex = regexp.MustCompile(tiger128RegexString) - tiger160Regex = regexp.MustCompile(tiger160RegexString) - tiger192Regex = regexp.MustCompile(tiger192RegexString) - aSCIIRegex = regexp.MustCompile(aSCIIRegexString) - printableASCIIRegex = regexp.MustCompile(printableASCIIRegexString) - multibyteRegex = regexp.MustCompile(multibyteRegexString) - dataURIRegex = regexp.MustCompile(dataURIRegexString) - latitudeRegex = regexp.MustCompile(latitudeRegexString) - longitudeRegex = regexp.MustCompile(longitudeRegexString) - sSNRegex = regexp.MustCompile(sSNRegexString) - hostnameRegexRFC952 = regexp.MustCompile(hostnameRegexStringRFC952) - hostnameRegexRFC1123 = regexp.MustCompile(hostnameRegexStringRFC1123) - fqdnRegexRFC1123 = regexp.MustCompile(fqdnRegexStringRFC1123) - btcAddressRegex = regexp.MustCompile(btcAddressRegexString) - btcUpperAddressRegexBech32 = regexp.MustCompile(btcAddressUpperRegexStringBech32) - btcLowerAddressRegexBech32 = regexp.MustCompile(btcAddressLowerRegexStringBech32) - ethAddressRegex = regexp.MustCompile(ethAddressRegexString) - ethAddressRegexUpper = regexp.MustCompile(ethAddressUpperRegexString) - ethAddressRegexLower = regexp.MustCompile(ethAddressLowerRegexString) - uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString) - hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString) - hTMLRegex = regexp.MustCompile(hTMLRegexString) - jWTRegex = regexp.MustCompile(jWTRegexString) - splitParamsRegex = regexp.MustCompile(splitParamsRegexString) - bicRegex = regexp.MustCompile(bicRegexString) - semverRegex = regexp.MustCompile(semverRegexString) - dnsRegexRFC1035Label = regexp.MustCompile(dnsRegexStringRFC1035Label) -) diff --git a/vendor/github.com/go-playground/validator/v10/struct_level.go b/vendor/github.com/go-playground/validator/v10/struct_level.go deleted file mode 100644 index c0d89cf..0000000 --- a/vendor/github.com/go-playground/validator/v10/struct_level.go +++ /dev/null @@ -1,175 +0,0 @@ -package validator - -import ( - "context" - "reflect" -) - -// StructLevelFunc accepts all values needed for struct level validation -type StructLevelFunc func(sl StructLevel) - -// StructLevelFuncCtx accepts all values needed for struct level validation -// but also allows passing of contextual validation information via context.Context. -type StructLevelFuncCtx func(ctx context.Context, sl StructLevel) - -// wrapStructLevelFunc wraps normal StructLevelFunc makes it compatible with StructLevelFuncCtx -func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx { - return func(ctx context.Context, sl StructLevel) { - fn(sl) - } -} - -// StructLevel contains all the information and helper functions -// to validate a struct -type StructLevel interface { - - // Validator returns the main validation object, in case one wants to call validations internally. - // this is so you don't have to use anonymous functions to get access to the validate - // instance. - Validator() *Validate - - // Top returns the top level struct, if any - Top() reflect.Value - - // Parent returns the current fields parent struct, if any - Parent() reflect.Value - - // Current returns the current struct. - Current() reflect.Value - - // ExtractType gets the actual underlying type of field value. - // It will dive into pointers, customTypes and return you the - // underlying value and its kind. - ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) - - // ReportError reports an error just by passing the field and tag information - // - // NOTES: - // - // fieldName and altName get appended to the existing namespace that - // validator is on. e.g. pass 'FirstName' or 'Names[0]' depending - // on the nesting - // - // tag can be an existing validation tag or just something you make up - // and process on the flip side it's up to you. - ReportError(field interface{}, fieldName, structFieldName string, tag, param string) - - // ReportValidationErrors reports an error just by passing ValidationErrors - // - // NOTES: - // - // relativeNamespace and relativeActualNamespace get appended to the - // existing namespace that validator is on. - // e.g. pass 'User.FirstName' or 'Users[0].FirstName' depending - // on the nesting. most of the time they will be blank, unless you validate - // at a level lower the the current field depth - ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors) -} - -var _ StructLevel = new(validate) - -// Top returns the top level struct -// -// NOTE: this can be the same as the current struct being validated -// if not is a nested struct. -// -// this is only called when within Struct and Field Level validation and -// should not be relied upon for an acurate value otherwise. -func (v *validate) Top() reflect.Value { - return v.top -} - -// Parent returns the current structs parent -// -// NOTE: this can be the same as the current struct being validated -// if not is a nested struct. -// -// this is only called when within Struct and Field Level validation and -// should not be relied upon for an acurate value otherwise. -func (v *validate) Parent() reflect.Value { - return v.slflParent -} - -// Current returns the current struct. -func (v *validate) Current() reflect.Value { - return v.slCurrent -} - -// Validator returns the main validation object, in case one want to call validations internally. -func (v *validate) Validator() *Validate { - return v.v -} - -// ExtractType gets the actual underlying type of field value. -func (v *validate) ExtractType(field reflect.Value) (reflect.Value, reflect.Kind, bool) { - return v.extractTypeInternal(field, false) -} - -// ReportError reports an error just by passing the field and tag information -func (v *validate) ReportError(field interface{}, fieldName, structFieldName, tag, param string) { - - fv, kind, _ := v.extractTypeInternal(reflect.ValueOf(field), false) - - if len(structFieldName) == 0 { - structFieldName = fieldName - } - - v.str1 = string(append(v.ns, fieldName...)) - - if v.v.hasTagNameFunc || fieldName != structFieldName { - v.str2 = string(append(v.actualNs, structFieldName...)) - } else { - v.str2 = v.str1 - } - - if kind == reflect.Invalid { - - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: tag, - actualTag: tag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(fieldName)), - structfieldLen: uint8(len(structFieldName)), - param: param, - kind: kind, - }, - ) - return - } - - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: tag, - actualTag: tag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(fieldName)), - structfieldLen: uint8(len(structFieldName)), - value: fv.Interface(), - param: param, - kind: kind, - typ: fv.Type(), - }, - ) -} - -// ReportValidationErrors reports ValidationErrors obtained from running validations within the Struct Level validation. -// -// NOTE: this function prepends the current namespace to the relative ones. -func (v *validate) ReportValidationErrors(relativeNamespace, relativeStructNamespace string, errs ValidationErrors) { - - var err *fieldError - - for i := 0; i < len(errs); i++ { - - err = errs[i].(*fieldError) - err.ns = string(append(append(v.ns, relativeNamespace...), err.ns...)) - err.structNs = string(append(append(v.actualNs, relativeStructNamespace...), err.structNs...)) - - v.errs = append(v.errs, err) - } -} diff --git a/vendor/github.com/go-playground/validator/v10/translations.go b/vendor/github.com/go-playground/validator/v10/translations.go deleted file mode 100644 index 4d9d75c..0000000 --- a/vendor/github.com/go-playground/validator/v10/translations.go +++ /dev/null @@ -1,11 +0,0 @@ -package validator - -import ut "github.com/go-playground/universal-translator" - -// TranslationFunc is the function type used to register or override -// custom translations -type TranslationFunc func(ut ut.Translator, fe FieldError) string - -// RegisterTranslationsFunc allows for registering of translations -// for a 'ut.Translator' for use within the 'TranslationFunc' -type RegisterTranslationsFunc func(ut ut.Translator) error diff --git a/vendor/github.com/go-playground/validator/v10/util.go b/vendor/github.com/go-playground/validator/v10/util.go deleted file mode 100644 index 36da855..0000000 --- a/vendor/github.com/go-playground/validator/v10/util.go +++ /dev/null @@ -1,288 +0,0 @@ -package validator - -import ( - "reflect" - "strconv" - "strings" - "time" -) - -// extractTypeInternal gets the actual underlying type of field value. -// It will dive into pointers, customTypes and return you the -// underlying value and it's kind. -func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) { - -BEGIN: - switch current.Kind() { - case reflect.Ptr: - - nullable = true - - if current.IsNil() { - return current, reflect.Ptr, nullable - } - - current = current.Elem() - goto BEGIN - - case reflect.Interface: - - nullable = true - - if current.IsNil() { - return current, reflect.Interface, nullable - } - - current = current.Elem() - goto BEGIN - - case reflect.Invalid: - return current, reflect.Invalid, nullable - - default: - - if v.v.hasCustomFuncs { - - if fn, ok := v.v.customFuncs[current.Type()]; ok { - current = reflect.ValueOf(fn(current)) - goto BEGIN - } - } - - return current, current.Kind(), nullable - } -} - -// getStructFieldOKInternal traverses a struct to retrieve a specific field denoted by the provided namespace and -// returns the field, field kind and whether is was successful in retrieving the field at all. -// -// NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field -// could not be retrieved because it didn't exist. -func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, nullable bool, found bool) { - -BEGIN: - current, kind, nullable = v.ExtractType(val) - if kind == reflect.Invalid { - return - } - - if namespace == "" { - found = true - return - } - - switch kind { - - case reflect.Ptr, reflect.Interface: - return - - case reflect.Struct: - - typ := current.Type() - fld := namespace - var ns string - - if !typ.ConvertibleTo(timeType) { - - idx := strings.Index(namespace, namespaceSeparator) - - if idx != -1 { - fld = namespace[:idx] - ns = namespace[idx+1:] - } else { - ns = "" - } - - bracketIdx := strings.Index(fld, leftBracket) - if bracketIdx != -1 { - fld = fld[:bracketIdx] - - ns = namespace[bracketIdx:] - } - - val = current.FieldByName(fld) - namespace = ns - goto BEGIN - } - - case reflect.Array, reflect.Slice: - idx := strings.Index(namespace, leftBracket) - idx2 := strings.Index(namespace, rightBracket) - - arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2]) - - if arrIdx >= current.Len() { - return - } - - startIdx := idx2 + 1 - - if startIdx < len(namespace) { - if namespace[startIdx:startIdx+1] == namespaceSeparator { - startIdx++ - } - } - - val = current.Index(arrIdx) - namespace = namespace[startIdx:] - goto BEGIN - - case reflect.Map: - idx := strings.Index(namespace, leftBracket) + 1 - idx2 := strings.Index(namespace, rightBracket) - - endIdx := idx2 - - if endIdx+1 < len(namespace) { - if namespace[endIdx+1:endIdx+2] == namespaceSeparator { - endIdx++ - } - } - - key := namespace[idx:idx2] - - switch current.Type().Key().Kind() { - case reflect.Int: - i, _ := strconv.Atoi(key) - val = current.MapIndex(reflect.ValueOf(i)) - namespace = namespace[endIdx+1:] - - case reflect.Int8: - i, _ := strconv.ParseInt(key, 10, 8) - val = current.MapIndex(reflect.ValueOf(int8(i))) - namespace = namespace[endIdx+1:] - - case reflect.Int16: - i, _ := strconv.ParseInt(key, 10, 16) - val = current.MapIndex(reflect.ValueOf(int16(i))) - namespace = namespace[endIdx+1:] - - case reflect.Int32: - i, _ := strconv.ParseInt(key, 10, 32) - val = current.MapIndex(reflect.ValueOf(int32(i))) - namespace = namespace[endIdx+1:] - - case reflect.Int64: - i, _ := strconv.ParseInt(key, 10, 64) - val = current.MapIndex(reflect.ValueOf(i)) - namespace = namespace[endIdx+1:] - - case reflect.Uint: - i, _ := strconv.ParseUint(key, 10, 0) - val = current.MapIndex(reflect.ValueOf(uint(i))) - namespace = namespace[endIdx+1:] - - case reflect.Uint8: - i, _ := strconv.ParseUint(key, 10, 8) - val = current.MapIndex(reflect.ValueOf(uint8(i))) - namespace = namespace[endIdx+1:] - - case reflect.Uint16: - i, _ := strconv.ParseUint(key, 10, 16) - val = current.MapIndex(reflect.ValueOf(uint16(i))) - namespace = namespace[endIdx+1:] - - case reflect.Uint32: - i, _ := strconv.ParseUint(key, 10, 32) - val = current.MapIndex(reflect.ValueOf(uint32(i))) - namespace = namespace[endIdx+1:] - - case reflect.Uint64: - i, _ := strconv.ParseUint(key, 10, 64) - val = current.MapIndex(reflect.ValueOf(i)) - namespace = namespace[endIdx+1:] - - case reflect.Float32: - f, _ := strconv.ParseFloat(key, 32) - val = current.MapIndex(reflect.ValueOf(float32(f))) - namespace = namespace[endIdx+1:] - - case reflect.Float64: - f, _ := strconv.ParseFloat(key, 64) - val = current.MapIndex(reflect.ValueOf(f)) - namespace = namespace[endIdx+1:] - - case reflect.Bool: - b, _ := strconv.ParseBool(key) - val = current.MapIndex(reflect.ValueOf(b)) - namespace = namespace[endIdx+1:] - - // reflect.Type = string - default: - val = current.MapIndex(reflect.ValueOf(key)) - namespace = namespace[endIdx+1:] - } - - goto BEGIN - } - - // if got here there was more namespace, cannot go any deeper - panic("Invalid field namespace") -} - -// asInt returns the parameter as a int64 -// or panics if it can't convert -func asInt(param string) int64 { - i, err := strconv.ParseInt(param, 0, 64) - panicIf(err) - - return i -} - -// asIntFromTimeDuration parses param as time.Duration and returns it as int64 -// or panics on error. -func asIntFromTimeDuration(param string) int64 { - d, err := time.ParseDuration(param) - if err != nil { - // attempt parsing as an an integer assuming nanosecond precision - return asInt(param) - } - return int64(d) -} - -// asIntFromType calls the proper function to parse param as int64, -// given a field's Type t. -func asIntFromType(t reflect.Type, param string) int64 { - switch t { - case timeDurationType: - return asIntFromTimeDuration(param) - default: - return asInt(param) - } -} - -// asUint returns the parameter as a uint64 -// or panics if it can't convert -func asUint(param string) uint64 { - - i, err := strconv.ParseUint(param, 0, 64) - panicIf(err) - - return i -} - -// asFloat returns the parameter as a float64 -// or panics if it can't convert -func asFloat(param string) float64 { - - i, err := strconv.ParseFloat(param, 64) - panicIf(err) - - return i -} - -// asBool returns the parameter as a bool -// or panics if it can't convert -func asBool(param string) bool { - - i, err := strconv.ParseBool(param) - panicIf(err) - - return i -} - -func panicIf(err error) { - if err != nil { - panic(err.Error()) - } -} diff --git a/vendor/github.com/go-playground/validator/v10/validator.go b/vendor/github.com/go-playground/validator/v10/validator.go deleted file mode 100644 index 80da095..0000000 --- a/vendor/github.com/go-playground/validator/v10/validator.go +++ /dev/null @@ -1,486 +0,0 @@ -package validator - -import ( - "context" - "fmt" - "reflect" - "strconv" -) - -// per validate construct -type validate struct { - v *Validate - top reflect.Value - ns []byte - actualNs []byte - errs ValidationErrors - includeExclude map[string]struct{} // reset only if StructPartial or StructExcept are called, no need otherwise - ffn FilterFunc - slflParent reflect.Value // StructLevel & FieldLevel - slCurrent reflect.Value // StructLevel & FieldLevel - flField reflect.Value // StructLevel & FieldLevel - cf *cField // StructLevel & FieldLevel - ct *cTag // StructLevel & FieldLevel - misc []byte // misc reusable - str1 string // misc reusable - str2 string // misc reusable - fldIsPointer bool // StructLevel & FieldLevel - isPartial bool - hasExcludes bool -} - -// parent and current will be the same the first run of validateStruct -func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, structNs []byte, ct *cTag) { - - cs, ok := v.v.structCache.Get(typ) - if !ok { - cs = v.v.extractStructCache(current, typ.Name()) - } - - if len(ns) == 0 && len(cs.name) != 0 { - - ns = append(ns, cs.name...) - ns = append(ns, '.') - - structNs = append(structNs, cs.name...) - structNs = append(structNs, '.') - } - - // ct is nil on top level struct, and structs as fields that have no tag info - // so if nil or if not nil and the structonly tag isn't present - if ct == nil || ct.typeof != typeStructOnly { - - var f *cField - - for i := 0; i < len(cs.fields); i++ { - - f = cs.fields[i] - - if v.isPartial { - - if v.ffn != nil { - // used with StructFiltered - if v.ffn(append(structNs, f.name...)) { - continue - } - - } else { - // used with StructPartial & StructExcept - _, ok = v.includeExclude[string(append(structNs, f.name...))] - - if (ok && v.hasExcludes) || (!ok && !v.hasExcludes) { - continue - } - } - } - - v.traverseField(ctx, current, current.Field(f.idx), ns, structNs, f, f.cTags) - } - } - - // check if any struct level validations, after all field validations already checked. - // first iteration will have no info about nostructlevel tag, and is checked prior to - // calling the next iteration of validateStruct called from traverseField. - if cs.fn != nil { - - v.slflParent = parent - v.slCurrent = current - v.ns = ns - v.actualNs = structNs - - cs.fn(ctx, v) - } -} - -// traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options -func (v *validate) traverseField(ctx context.Context, parent reflect.Value, current reflect.Value, ns []byte, structNs []byte, cf *cField, ct *cTag) { - var typ reflect.Type - var kind reflect.Kind - - current, kind, v.fldIsPointer = v.extractTypeInternal(current, false) - - switch kind { - case reflect.Ptr, reflect.Interface, reflect.Invalid: - - if ct == nil { - return - } - - if ct.typeof == typeOmitEmpty || ct.typeof == typeIsDefault { - return - } - - if ct.hasTag { - if kind == reflect.Invalid { - v.str1 = string(append(ns, cf.altName...)) - if v.v.hasTagNameFunc { - v.str2 = string(append(structNs, cf.name...)) - } else { - v.str2 = v.str1 - } - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: ct.aliasTag, - actualTag: ct.tag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(cf.altName)), - structfieldLen: uint8(len(cf.name)), - param: ct.param, - kind: kind, - }, - ) - return - } - - v.str1 = string(append(ns, cf.altName...)) - if v.v.hasTagNameFunc { - v.str2 = string(append(structNs, cf.name...)) - } else { - v.str2 = v.str1 - } - if !ct.runValidationWhenNil { - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: ct.aliasTag, - actualTag: ct.tag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(cf.altName)), - structfieldLen: uint8(len(cf.name)), - value: current.Interface(), - param: ct.param, - kind: kind, - typ: current.Type(), - }, - ) - return - } - } - - case reflect.Struct: - - typ = current.Type() - - if !typ.ConvertibleTo(timeType) { - - if ct != nil { - - if ct.typeof == typeStructOnly { - goto CONTINUE - } else if ct.typeof == typeIsDefault { - // set Field Level fields - v.slflParent = parent - v.flField = current - v.cf = cf - v.ct = ct - - if !ct.fn(ctx, v) { - v.str1 = string(append(ns, cf.altName...)) - - if v.v.hasTagNameFunc { - v.str2 = string(append(structNs, cf.name...)) - } else { - v.str2 = v.str1 - } - - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: ct.aliasTag, - actualTag: ct.tag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(cf.altName)), - structfieldLen: uint8(len(cf.name)), - value: current.Interface(), - param: ct.param, - kind: kind, - typ: typ, - }, - ) - return - } - } - - ct = ct.next - } - - if ct != nil && ct.typeof == typeNoStructLevel { - return - } - - CONTINUE: - // if len == 0 then validating using 'Var' or 'VarWithValue' - // Var - doesn't make much sense to do it that way, should call 'Struct', but no harm... - // VarWithField - this allows for validating against each field within the struct against a specific value - // pretty handy in certain situations - if len(cf.name) > 0 { - ns = append(append(ns, cf.altName...), '.') - structNs = append(append(structNs, cf.name...), '.') - } - - v.validateStruct(ctx, parent, current, typ, ns, structNs, ct) - return - } - } - - if ct == nil || !ct.hasTag { - return - } - - typ = current.Type() - -OUTER: - for { - if ct == nil { - return - } - - switch ct.typeof { - - case typeOmitEmpty: - - // set Field Level fields - v.slflParent = parent - v.flField = current - v.cf = cf - v.ct = ct - - if !hasValue(v) { - return - } - - ct = ct.next - continue - - case typeEndKeys: - return - - case typeDive: - - ct = ct.next - - // traverse slice or map here - // or panic ;) - switch kind { - case reflect.Slice, reflect.Array: - - var i64 int64 - reusableCF := &cField{} - - for i := 0; i < current.Len(); i++ { - - i64 = int64(i) - - v.misc = append(v.misc[0:0], cf.name...) - v.misc = append(v.misc, '[') - v.misc = strconv.AppendInt(v.misc, i64, 10) - v.misc = append(v.misc, ']') - - reusableCF.name = string(v.misc) - - if cf.namesEqual { - reusableCF.altName = reusableCF.name - } else { - - v.misc = append(v.misc[0:0], cf.altName...) - v.misc = append(v.misc, '[') - v.misc = strconv.AppendInt(v.misc, i64, 10) - v.misc = append(v.misc, ']') - - reusableCF.altName = string(v.misc) - } - v.traverseField(ctx, parent, current.Index(i), ns, structNs, reusableCF, ct) - } - - case reflect.Map: - - var pv string - reusableCF := &cField{} - - for _, key := range current.MapKeys() { - - pv = fmt.Sprintf("%v", key.Interface()) - - v.misc = append(v.misc[0:0], cf.name...) - v.misc = append(v.misc, '[') - v.misc = append(v.misc, pv...) - v.misc = append(v.misc, ']') - - reusableCF.name = string(v.misc) - - if cf.namesEqual { - reusableCF.altName = reusableCF.name - } else { - v.misc = append(v.misc[0:0], cf.altName...) - v.misc = append(v.misc, '[') - v.misc = append(v.misc, pv...) - v.misc = append(v.misc, ']') - - reusableCF.altName = string(v.misc) - } - - if ct != nil && ct.typeof == typeKeys && ct.keys != nil { - v.traverseField(ctx, parent, key, ns, structNs, reusableCF, ct.keys) - // can be nil when just keys being validated - if ct.next != nil { - v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct.next) - } - } else { - v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct) - } - } - - default: - // throw error, if not a slice or map then should not have gotten here - // bad dive tag - panic("dive error! can't dive on a non slice or map") - } - - return - - case typeOr: - - v.misc = v.misc[0:0] - - for { - - // set Field Level fields - v.slflParent = parent - v.flField = current - v.cf = cf - v.ct = ct - - if ct.fn(ctx, v) { - if ct.isBlockEnd { - ct = ct.next - continue OUTER - } - - // drain rest of the 'or' values, then continue or leave - for { - - ct = ct.next - - if ct == nil { - return - } - - if ct.typeof != typeOr { - continue OUTER - } - - if ct.isBlockEnd { - ct = ct.next - continue OUTER - } - } - } - - v.misc = append(v.misc, '|') - v.misc = append(v.misc, ct.tag...) - - if ct.hasParam { - v.misc = append(v.misc, '=') - v.misc = append(v.misc, ct.param...) - } - - if ct.isBlockEnd || ct.next == nil { - // if we get here, no valid 'or' value and no more tags - v.str1 = string(append(ns, cf.altName...)) - - if v.v.hasTagNameFunc { - v.str2 = string(append(structNs, cf.name...)) - } else { - v.str2 = v.str1 - } - - if ct.hasAlias { - - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: ct.aliasTag, - actualTag: ct.actualAliasTag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(cf.altName)), - structfieldLen: uint8(len(cf.name)), - value: current.Interface(), - param: ct.param, - kind: kind, - typ: typ, - }, - ) - - } else { - - tVal := string(v.misc)[1:] - - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: tVal, - actualTag: tVal, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(cf.altName)), - structfieldLen: uint8(len(cf.name)), - value: current.Interface(), - param: ct.param, - kind: kind, - typ: typ, - }, - ) - } - - return - } - - ct = ct.next - } - - default: - - // set Field Level fields - v.slflParent = parent - v.flField = current - v.cf = cf - v.ct = ct - - if !ct.fn(ctx, v) { - - v.str1 = string(append(ns, cf.altName...)) - - if v.v.hasTagNameFunc { - v.str2 = string(append(structNs, cf.name...)) - } else { - v.str2 = v.str1 - } - - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: ct.aliasTag, - actualTag: ct.tag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(cf.altName)), - structfieldLen: uint8(len(cf.name)), - value: current.Interface(), - param: ct.param, - kind: kind, - typ: typ, - }, - ) - - return - } - ct = ct.next - } - } - -} diff --git a/vendor/github.com/go-playground/validator/v10/validator_instance.go b/vendor/github.com/go-playground/validator/v10/validator_instance.go deleted file mode 100644 index 9493da4..0000000 --- a/vendor/github.com/go-playground/validator/v10/validator_instance.go +++ /dev/null @@ -1,699 +0,0 @@ -package validator - -import ( - "context" - "errors" - "fmt" - "reflect" - "strings" - "sync" - "time" - - ut "github.com/go-playground/universal-translator" -) - -const ( - defaultTagName = "validate" - utf8HexComma = "0x2C" - utf8Pipe = "0x7C" - tagSeparator = "," - orSeparator = "|" - tagKeySeparator = "=" - structOnlyTag = "structonly" - noStructLevelTag = "nostructlevel" - omitempty = "omitempty" - isdefault = "isdefault" - requiredWithoutAllTag = "required_without_all" - requiredWithoutTag = "required_without" - requiredWithTag = "required_with" - requiredWithAllTag = "required_with_all" - requiredIfTag = "required_if" - requiredUnlessTag = "required_unless" - excludedWithoutAllTag = "excluded_without_all" - excludedWithoutTag = "excluded_without" - excludedWithTag = "excluded_with" - excludedWithAllTag = "excluded_with_all" - excludedIfTag = "excluded_if" - excludedUnlessTag = "excluded_unless" - skipValidationTag = "-" - diveTag = "dive" - keysTag = "keys" - endKeysTag = "endkeys" - requiredTag = "required" - namespaceSeparator = "." - leftBracket = "[" - rightBracket = "]" - restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}" - restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" - restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" -) - -var ( - timeDurationType = reflect.TypeOf(time.Duration(0)) - timeType = reflect.TypeOf(time.Time{}) - - defaultCField = &cField{namesEqual: true} -) - -// FilterFunc is the type used to filter fields using -// StructFiltered(...) function. -// returning true results in the field being filtered/skiped from -// validation -type FilterFunc func(ns []byte) bool - -// CustomTypeFunc allows for overriding or adding custom field type handler functions -// field = field value of the type to return a value to be validated -// example Valuer from sql drive see https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29 -type CustomTypeFunc func(field reflect.Value) interface{} - -// TagNameFunc allows for adding of a custom tag name parser -type TagNameFunc func(field reflect.StructField) string - -type internalValidationFuncWrapper struct { - fn FuncCtx - runValidatinOnNil bool -} - -// Validate contains the validator settings and cache -type Validate struct { - tagName string - pool *sync.Pool - hasCustomFuncs bool - hasTagNameFunc bool - tagNameFunc TagNameFunc - structLevelFuncs map[reflect.Type]StructLevelFuncCtx - customFuncs map[reflect.Type]CustomTypeFunc - aliases map[string]string - validations map[string]internalValidationFuncWrapper - transTagFunc map[ut.Translator]map[string]TranslationFunc // map[]map[]TranslationFunc - rules map[reflect.Type]map[string]string - tagCache *tagCache - structCache *structCache -} - -// New returns a new instance of 'validate' with sane defaults. -// Validate is designed to be thread-safe and used as a singleton instance. -// It caches information about your struct and validations, -// in essence only parsing your validation tags once per struct type. -// Using multiple instances neglects the benefit of caching. -func New() *Validate { - - tc := new(tagCache) - tc.m.Store(make(map[string]*cTag)) - - sc := new(structCache) - sc.m.Store(make(map[reflect.Type]*cStruct)) - - v := &Validate{ - tagName: defaultTagName, - aliases: make(map[string]string, len(bakedInAliases)), - validations: make(map[string]internalValidationFuncWrapper, len(bakedInValidators)), - tagCache: tc, - structCache: sc, - } - - // must copy alias validators for separate validations to be used in each validator instance - for k, val := range bakedInAliases { - v.RegisterAlias(k, val) - } - - // must copy validators for separate validations to be used in each instance - for k, val := range bakedInValidators { - - switch k { - // these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour - case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag, - excludedIfTag, excludedUnlessTag, excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag: - _ = v.registerValidation(k, wrapFunc(val), true, true) - default: - // no need to error check here, baked in will always be valid - _ = v.registerValidation(k, wrapFunc(val), true, false) - } - } - - v.pool = &sync.Pool{ - New: func() interface{} { - return &validate{ - v: v, - ns: make([]byte, 0, 64), - actualNs: make([]byte, 0, 64), - misc: make([]byte, 32), - } - }, - } - - return v -} - -// SetTagName allows for changing of the default tag name of 'validate' -func (v *Validate) SetTagName(name string) { - v.tagName = name -} - -// ValidateMapCtx validates a map using a map of validation rules and allows passing of contextual -// validation validation information via context.Context. -func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{}, rules map[string]interface{}) map[string]interface{} { - errs := make(map[string]interface{}) - for field, rule := range rules { - if ruleObj, ok := rule.(map[string]interface{}); ok { - if dataObj, ok := data[field].(map[string]interface{}); ok { - err := v.ValidateMapCtx(ctx, dataObj, ruleObj) - if len(err) > 0 { - errs[field] = err - } - } else if dataObjs, ok := data[field].([]map[string]interface{}); ok { - for _, obj := range dataObjs { - err := v.ValidateMapCtx(ctx, obj, ruleObj) - if len(err) > 0 { - errs[field] = err - } - } - } else { - errs[field] = errors.New("The field: '" + field + "' is not a map to dive") - } - } else if ruleStr, ok := rule.(string); ok { - err := v.VarCtx(ctx, data[field], ruleStr) - if err != nil { - errs[field] = err - } - } - } - return errs -} - -// ValidateMap validates map data from a map of tags -func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]interface{}) map[string]interface{} { - return v.ValidateMapCtx(context.Background(), data, rules) -} - -// RegisterTagNameFunc registers a function to get alternate names for StructFields. -// -// eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names: -// -// validate.RegisterTagNameFunc(func(fld reflect.StructField) string { -// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] -// // skip if tag key says it should be ignored -// if name == "-" { -// return "" -// } -// return name -// }) -func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) { - v.tagNameFunc = fn - v.hasTagNameFunc = true -} - -// RegisterValidation adds a validation with the given tag -// -// NOTES: -// - if the key already exists, the previous validation function will be replaced. -// - this method is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterValidation(tag string, fn Func, callValidationEvenIfNull ...bool) error { - return v.RegisterValidationCtx(tag, wrapFunc(fn), callValidationEvenIfNull...) -} - -// RegisterValidationCtx does the same as RegisterValidation on accepts a FuncCtx validation -// allowing context.Context validation support. -func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx, callValidationEvenIfNull ...bool) error { - var nilCheckable bool - if len(callValidationEvenIfNull) > 0 { - nilCheckable = callValidationEvenIfNull[0] - } - return v.registerValidation(tag, fn, false, nilCheckable) -} - -func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error { - if len(tag) == 0 { - return errors.New("function Key cannot be empty") - } - - if fn == nil { - return errors.New("function cannot be empty") - } - - _, ok := restrictedTags[tag] - if !bakedIn && (ok || strings.ContainsAny(tag, restrictedTagChars)) { - panic(fmt.Sprintf(restrictedTagErr, tag)) - } - v.validations[tag] = internalValidationFuncWrapper{fn: fn, runValidatinOnNil: nilCheckable} - return nil -} - -// RegisterAlias registers a mapping of a single validation tag that -// defines a common or complex set of validation(s) to simplify adding validation -// to structs. -// -// NOTE: this function is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterAlias(alias, tags string) { - - _, ok := restrictedTags[alias] - - if ok || strings.ContainsAny(alias, restrictedTagChars) { - panic(fmt.Sprintf(restrictedAliasErr, alias)) - } - - v.aliases[alias] = tags -} - -// RegisterStructValidation registers a StructLevelFunc against a number of types. -// -// NOTE: -// - this method is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) { - v.RegisterStructValidationCtx(wrapStructLevelFunc(fn), types...) -} - -// RegisterStructValidationCtx registers a StructLevelFuncCtx against a number of types and allows passing -// of contextual validation information via context.Context. -// -// NOTE: -// - this method is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...interface{}) { - - if v.structLevelFuncs == nil { - v.structLevelFuncs = make(map[reflect.Type]StructLevelFuncCtx) - } - - for _, t := range types { - tv := reflect.ValueOf(t) - if tv.Kind() == reflect.Ptr { - t = reflect.Indirect(tv).Interface() - } - - v.structLevelFuncs[reflect.TypeOf(t)] = fn - } -} - -// RegisterStructValidationMapRules registers validate map rules. -// Be aware that map validation rules supersede those defined on a/the struct if present. -// -// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterStructValidationMapRules(rules map[string]string, types ...interface{}) { - if v.rules == nil { - v.rules = make(map[reflect.Type]map[string]string) - } - - deepCopyRules := make(map[string]string) - for i, rule := range rules { - deepCopyRules[i] = rule - } - - for _, t := range types { - typ := reflect.TypeOf(t) - - if typ.Kind() == reflect.Ptr { - typ = typ.Elem() - } - - if typ.Kind() != reflect.Struct { - continue - } - v.rules[typ] = deepCopyRules - } -} - -// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types -// -// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) { - - if v.customFuncs == nil { - v.customFuncs = make(map[reflect.Type]CustomTypeFunc) - } - - for _, t := range types { - v.customFuncs[reflect.TypeOf(t)] = fn - } - - v.hasCustomFuncs = true -} - -// RegisterTranslation registers translations against the provided tag. -func (v *Validate) RegisterTranslation(tag string, trans ut.Translator, registerFn RegisterTranslationsFunc, translationFn TranslationFunc) (err error) { - - if v.transTagFunc == nil { - v.transTagFunc = make(map[ut.Translator]map[string]TranslationFunc) - } - - if err = registerFn(trans); err != nil { - return - } - - m, ok := v.transTagFunc[trans] - if !ok { - m = make(map[string]TranslationFunc) - v.transTagFunc[trans] = m - } - - m[tag] = translationFn - - return -} - -// Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified. -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) Struct(s interface{}) error { - return v.StructCtx(context.Background(), s) -} - -// StructCtx validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified -// and also allows passing of context.Context for contextual validation information. -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) { - - val := reflect.ValueOf(s) - top := val - - if val.Kind() == reflect.Ptr && !val.IsNil() { - val = val.Elem() - } - - if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { - return &InvalidValidationError{Type: reflect.TypeOf(s)} - } - - // good to validate - vd := v.pool.Get().(*validate) - vd.top = top - vd.isPartial = false - // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept - - vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil) - - if len(vd.errs) > 0 { - err = vd.errs - vd.errs = nil - } - - v.pool.Put(vd) - - return -} - -// StructFiltered validates a structs exposed fields, that pass the FilterFunc check and automatically validates -// nested structs, unless otherwise specified. -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructFiltered(s interface{}, fn FilterFunc) error { - return v.StructFilteredCtx(context.Background(), s, fn) -} - -// StructFilteredCtx validates a structs exposed fields, that pass the FilterFunc check and automatically validates -// nested structs, unless otherwise specified and also allows passing of contextual validation information via -// context.Context -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructFilteredCtx(ctx context.Context, s interface{}, fn FilterFunc) (err error) { - val := reflect.ValueOf(s) - top := val - - if val.Kind() == reflect.Ptr && !val.IsNil() { - val = val.Elem() - } - - if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { - return &InvalidValidationError{Type: reflect.TypeOf(s)} - } - - // good to validate - vd := v.pool.Get().(*validate) - vd.top = top - vd.isPartial = true - vd.ffn = fn - // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept - - vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil) - - if len(vd.errs) > 0 { - err = vd.errs - vd.errs = nil - } - - v.pool.Put(vd) - - return -} - -// StructPartial validates the fields passed in only, ignoring all others. -// Fields may be provided in a namespaced fashion relative to the struct provided -// eg. NestedStruct.Field or NestedArrayField[0].Struct.Name -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructPartial(s interface{}, fields ...string) error { - return v.StructPartialCtx(context.Background(), s, fields...) -} - -// StructPartialCtx validates the fields passed in only, ignoring all others and allows passing of contextual -// validation validation information via context.Context -// Fields may be provided in a namespaced fashion relative to the struct provided -// eg. NestedStruct.Field or NestedArrayField[0].Struct.Name -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields ...string) (err error) { - val := reflect.ValueOf(s) - top := val - - if val.Kind() == reflect.Ptr && !val.IsNil() { - val = val.Elem() - } - - if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { - return &InvalidValidationError{Type: reflect.TypeOf(s)} - } - - // good to validate - vd := v.pool.Get().(*validate) - vd.top = top - vd.isPartial = true - vd.ffn = nil - vd.hasExcludes = false - vd.includeExclude = make(map[string]struct{}) - - typ := val.Type() - name := typ.Name() - - for _, k := range fields { - - flds := strings.Split(k, namespaceSeparator) - if len(flds) > 0 { - - vd.misc = append(vd.misc[0:0], name...) - // Don't append empty name for unnamed structs - if len(vd.misc) != 0 { - vd.misc = append(vd.misc, '.') - } - - for _, s := range flds { - - idx := strings.Index(s, leftBracket) - - if idx != -1 { - for idx != -1 { - vd.misc = append(vd.misc, s[:idx]...) - vd.includeExclude[string(vd.misc)] = struct{}{} - - idx2 := strings.Index(s, rightBracket) - idx2++ - vd.misc = append(vd.misc, s[idx:idx2]...) - vd.includeExclude[string(vd.misc)] = struct{}{} - s = s[idx2:] - idx = strings.Index(s, leftBracket) - } - } else { - - vd.misc = append(vd.misc, s...) - vd.includeExclude[string(vd.misc)] = struct{}{} - } - - vd.misc = append(vd.misc, '.') - } - } - } - - vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) - - if len(vd.errs) > 0 { - err = vd.errs - vd.errs = nil - } - - v.pool.Put(vd) - - return -} - -// StructExcept validates all fields except the ones passed in. -// Fields may be provided in a namespaced fashion relative to the struct provided -// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructExcept(s interface{}, fields ...string) error { - return v.StructExceptCtx(context.Background(), s, fields...) -} - -// StructExceptCtx validates all fields except the ones passed in and allows passing of contextual -// validation validation information via context.Context -// Fields may be provided in a namespaced fashion relative to the struct provided -// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields ...string) (err error) { - val := reflect.ValueOf(s) - top := val - - if val.Kind() == reflect.Ptr && !val.IsNil() { - val = val.Elem() - } - - if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { - return &InvalidValidationError{Type: reflect.TypeOf(s)} - } - - // good to validate - vd := v.pool.Get().(*validate) - vd.top = top - vd.isPartial = true - vd.ffn = nil - vd.hasExcludes = true - vd.includeExclude = make(map[string]struct{}) - - typ := val.Type() - name := typ.Name() - - for _, key := range fields { - - vd.misc = vd.misc[0:0] - - if len(name) > 0 { - vd.misc = append(vd.misc, name...) - vd.misc = append(vd.misc, '.') - } - - vd.misc = append(vd.misc, key...) - vd.includeExclude[string(vd.misc)] = struct{}{} - } - - vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) - - if len(vd.errs) > 0 { - err = vd.errs - vd.errs = nil - } - - v.pool.Put(vd) - - return -} - -// Var validates a single variable using tag style validation. -// eg. -// var i int -// validate.Var(i, "gt=1,lt=10") -// -// WARNING: a struct can be passed for validation eg. time.Time is a struct or -// if you have a custom type and have registered a custom type handler, so must -// allow it; however unforeseen validations will occur if trying to validate a -// struct that is meant to be passed to 'validate.Struct' -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -// validate Array, Slice and maps fields which may contain more than one error -func (v *Validate) Var(field interface{}, tag string) error { - return v.VarCtx(context.Background(), field, tag) -} - -// VarCtx validates a single variable using tag style validation and allows passing of contextual -// validation validation information via context.Context. -// eg. -// var i int -// validate.Var(i, "gt=1,lt=10") -// -// WARNING: a struct can be passed for validation eg. time.Time is a struct or -// if you have a custom type and have registered a custom type handler, so must -// allow it; however unforeseen validations will occur if trying to validate a -// struct that is meant to be passed to 'validate.Struct' -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -// validate Array, Slice and maps fields which may contain more than one error -func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (err error) { - if len(tag) == 0 || tag == skipValidationTag { - return nil - } - - ctag := v.fetchCacheTag(tag) - val := reflect.ValueOf(field) - vd := v.pool.Get().(*validate) - vd.top = val - vd.isPartial = false - vd.traverseField(ctx, val, val, vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) - - if len(vd.errs) > 0 { - err = vd.errs - vd.errs = nil - } - v.pool.Put(vd) - return -} - -// VarWithValue validates a single variable, against another variable/field's value using tag style validation -// eg. -// s1 := "abcd" -// s2 := "abcd" -// validate.VarWithValue(s1, s2, "eqcsfield") // returns true -// -// WARNING: a struct can be passed for validation eg. time.Time is a struct or -// if you have a custom type and have registered a custom type handler, so must -// allow it; however unforeseen validations will occur if trying to validate a -// struct that is meant to be passed to 'validate.Struct' -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -// validate Array, Slice and maps fields which may contain more than one error -func (v *Validate) VarWithValue(field interface{}, other interface{}, tag string) error { - return v.VarWithValueCtx(context.Background(), field, other, tag) -} - -// VarWithValueCtx validates a single variable, against another variable/field's value using tag style validation and -// allows passing of contextual validation validation information via context.Context. -// eg. -// s1 := "abcd" -// s2 := "abcd" -// validate.VarWithValue(s1, s2, "eqcsfield") // returns true -// -// WARNING: a struct can be passed for validation eg. time.Time is a struct or -// if you have a custom type and have registered a custom type handler, so must -// allow it; however unforeseen validations will occur if trying to validate a -// struct that is meant to be passed to 'validate.Struct' -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -// validate Array, Slice and maps fields which may contain more than one error -func (v *Validate) VarWithValueCtx(ctx context.Context, field interface{}, other interface{}, tag string) (err error) { - if len(tag) == 0 || tag == skipValidationTag { - return nil - } - ctag := v.fetchCacheTag(tag) - otherVal := reflect.ValueOf(other) - vd := v.pool.Get().(*validate) - vd.top = otherVal - vd.isPartial = false - vd.traverseField(ctx, otherVal, reflect.ValueOf(field), vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) - - if len(vd.errs) > 0 { - err = vd.errs - vd.errs = nil - } - v.pool.Put(vd) - return -} diff --git a/vendor/github.com/go-redis/redis/v9/.gitignore b/vendor/github.com/go-redis/redis/v9/.gitignore deleted file mode 100644 index b975a7b..0000000 --- a/vendor/github.com/go-redis/redis/v9/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.rdb -testdata/*/ -.idea/ diff --git a/vendor/github.com/go-redis/redis/v9/.golangci.yml b/vendor/github.com/go-redis/redis/v9/.golangci.yml deleted file mode 100644 index de51455..0000000 --- a/vendor/github.com/go-redis/redis/v9/.golangci.yml +++ /dev/null @@ -1,4 +0,0 @@ -run: - concurrency: 8 - deadline: 5m - tests: false diff --git a/vendor/github.com/go-redis/redis/v9/.prettierrc.yml b/vendor/github.com/go-redis/redis/v9/.prettierrc.yml deleted file mode 100644 index 8b7f044..0000000 --- a/vendor/github.com/go-redis/redis/v9/.prettierrc.yml +++ /dev/null @@ -1,4 +0,0 @@ -semi: false -singleQuote: true -proseWrap: always -printWidth: 100 diff --git a/vendor/github.com/go-redis/redis/v9/CHANGELOG.md b/vendor/github.com/go-redis/redis/v9/CHANGELOG.md deleted file mode 100644 index 9c18618..0000000 --- a/vendor/github.com/go-redis/redis/v9/CHANGELOG.md +++ /dev/null @@ -1,70 +0,0 @@ -# [9.0.0-beta.2](https://github.com/go-redis/redis/compare/v9.0.0-beta.1...v9.0.0-beta.2) (2022-07-28) - - -### Bug Fixes - -* [#2114](https://github.com/go-redis/redis/issues/2114) for redis-server not support Hello ([b6d2a92](https://github.com/go-redis/redis/commit/b6d2a925297e3e516eb5c76c114c1c9fcd5b68c5)) -* additional node failures in clustered pipelined reads ([03376a5](https://github.com/go-redis/redis/commit/03376a5d9c7dfd7197b14ce13b24a0431a07a663)) -* disregard failed pings in updateLatency() for cluster nodes ([64f972f](https://github.com/go-redis/redis/commit/64f972fbeae401e52a2c066a0e1c922af617e15c)) -* don't panic when test cannot start ([9e16c79](https://github.com/go-redis/redis/commit/9e16c79951e7769621b7320f1ecdf04baf539b82)) -* handle panic in ringShards Hash function when Ring got closed ([a80b84f](https://github.com/go-redis/redis/commit/a80b84f01f9fc0d3e6f08445ba21f7e07880775e)), closes [#2126](https://github.com/go-redis/redis/issues/2126) -* ignore Nil error when reading EntriesRead ([89d6dfe](https://github.com/go-redis/redis/commit/89d6dfe09a88321d445858c1c5b24d2757b95a3e)) -* log errors from cmdsInfoCache ([fa4d1ea](https://github.com/go-redis/redis/commit/fa4d1ea8398cd729ad5cbaaff88e4b8805393945)) -* provide a signal channel to end heartbeat goroutine ([f032c12](https://github.com/go-redis/redis/commit/f032c126db3e2c1a239ce1790b0ab81994df75cf)) -* remove conn reaper from the pool and uptrace option names ([f6a8adc](https://github.com/go-redis/redis/commit/f6a8adc50cdaec30527f50d06468f9176ee674fe)) -* replace heartbeat signal channel with context.WithCancel ([20d0ca2](https://github.com/go-redis/redis/commit/20d0ca235efff48ad48cc05b98790b825d4ba979)) - - - -# [9.0.0-beta.1](https://github.com/go-redis/redis/compare/v8.11.5...v9.0.0-beta.1) (2022-06-04) - -### Bug Fixes - -- **#1943:** xInfoConsumer.Idle should be time.Duration instead of int64 - ([#2052](https://github.com/go-redis/redis/issues/2052)) - ([997ab5e](https://github.com/go-redis/redis/commit/997ab5e7e3ddf53837917013a4babbded73e944f)), - closes [#1943](https://github.com/go-redis/redis/issues/1943) -- add XInfoConsumers test - ([6f1a1ac](https://github.com/go-redis/redis/commit/6f1a1ac284ea3f683eeb3b06a59969e8424b6376)) -- fix tests - ([3a722be](https://github.com/go-redis/redis/commit/3a722be81180e4d2a9cf0a29dc9a1ee1421f5859)) -- remove test(XInfoConsumer.idle), not a stable return value when tested. - ([f5fbb36](https://github.com/go-redis/redis/commit/f5fbb367e7d9dfd7f391fc535a7387002232fa8a)) -- update ChannelWithSubscriptions to accept options - ([c98c5f0](https://github.com/go-redis/redis/commit/c98c5f0eebf8d254307183c2ce702a48256b718d)) -- update COMMAND parser for Redis 7 - ([b0bb514](https://github.com/go-redis/redis/commit/b0bb514059249e01ed7328c9094e5b8a439dfb12)) -- use redis over ssh channel([#2057](https://github.com/go-redis/redis/issues/2057)) - ([#2060](https://github.com/go-redis/redis/issues/2060)) - ([3961b95](https://github.com/go-redis/redis/commit/3961b9577f622a3079fe74f8fc8da12ba67a77ff)) - -### Features - -- add ClientUnpause - ([91171f5](https://github.com/go-redis/redis/commit/91171f5e19a261dc4cfbf8706626d461b6ba03e4)) -- add NewXPendingResult for unit testing XPending - ([#2066](https://github.com/go-redis/redis/issues/2066)) - ([b7fd09e](https://github.com/go-redis/redis/commit/b7fd09e59479bc6ed5b3b13c4645a3620fd448a3)) -- add WriteArg and Scan net.IP([#2062](https://github.com/go-redis/redis/issues/2062)) - ([7d5167e](https://github.com/go-redis/redis/commit/7d5167e8624ac1515e146ed183becb97dadb3d1a)) -- **pool:** add check for badConnection - ([a8a7665](https://github.com/go-redis/redis/commit/a8a7665ddf8cc657c5226b1826a8ee83dab4b8c1)), - closes [#2053](https://github.com/go-redis/redis/issues/2053) -- provide a username and password callback method, so that the plaintext username and password will - not be stored in the memory, and the username and password will only be generated once when the - CredentialsProvider is called. After the method is executed, the username and password strings on - the stack will be released. ([#2097](https://github.com/go-redis/redis/issues/2097)) - ([56a3dbc](https://github.com/go-redis/redis/commit/56a3dbc7b656525eb88e0735e239d56e04a23bee)) -- upgrade to Redis 7 - ([d09c27e](https://github.com/go-redis/redis/commit/d09c27e6046129fd27b1d275e5a13a477bd7f778)) - -## v9 UNRELEASED - -- Added support for [RESP3](https://github.com/antirez/RESP3/blob/master/spec.md) protocol. -- Removed `Pipeline.Close` since there is no real need to explicitly manage pipeline resources. - `Pipeline.Discard` is still available if you want to reset commands for some reason. -- Replaced `*redis.Z` with `redis.Z` since it is small enough to be passed as value. -- Renamed `MaxConnAge` to `ConnMaxLifetime`. -- Renamed `IdleTimeout` to `ConnMaxIdleTime`. -- Removed connection reaper in favor of `MaxIdleConns`. -- Removed `WithContext`. diff --git a/vendor/github.com/go-redis/redis/v9/LICENSE b/vendor/github.com/go-redis/redis/v9/LICENSE deleted file mode 100644 index 298bed9..0000000 --- a/vendor/github.com/go-redis/redis/v9/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2013 The github.com/go-redis/redis Authors. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/go-redis/redis/v9/Makefile b/vendor/github.com/go-redis/redis/v9/Makefile deleted file mode 100644 index 5dbd7ae..0000000 --- a/vendor/github.com/go-redis/redis/v9/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -PACKAGE_DIRS := $(shell find . -mindepth 2 -type f -name 'go.mod' -exec dirname {} \; | sort) - -test: testdeps - go test ./... - go test ./... -short -race - go test ./... -run=NONE -bench=. -benchmem - env GOOS=linux GOARCH=386 go test ./... - go vet - -testdeps: testdata/redis/src/redis-server - -bench: testdeps - go test ./... -test.run=NONE -test.bench=. -test.benchmem - -.PHONY: all test testdeps bench - -testdata/redis: - mkdir -p $@ - wget -qO- https://download.redis.io/releases/redis-7.0.0.tar.gz | tar xvz --strip-components=1 -C $@ - -testdata/redis/src/redis-server: testdata/redis - cd $< && make all - -fmt: - gofmt -w -s ./ - goimports -w -local github.com/go-redis/redis ./ - -go_mod_tidy: - set -e; for dir in $(PACKAGE_DIRS); do \ - echo "go mod tidy in $${dir}"; \ - (cd "$${dir}" && \ - go get -u ./... && \ - go mod tidy -compat=1.17); \ - done diff --git a/vendor/github.com/go-redis/redis/v9/README.md b/vendor/github.com/go-redis/redis/v9/README.md deleted file mode 100644 index 468cf10..0000000 --- a/vendor/github.com/go-redis/redis/v9/README.md +++ /dev/null @@ -1,195 +0,0 @@ -# Redis client for Go - -![build workflow](https://github.com/go-redis/redis/actions/workflows/build.yml/badge.svg) -[![PkgGoDev](https://pkg.go.dev/badge/github.com/go-redis/redis/v8)](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc) -[![Documentation](https://img.shields.io/badge/redis-documentation-informational)](https://redis.uptrace.dev/) -[![Chat](https://discordapp.com/api/guilds/752070105847955518/widget.png)](https://discord.gg/rWtp5Aj) - -> go-redis is brought to you by :star: [**uptrace/uptrace**](https://github.com/uptrace/uptrace). -> Uptrace is an open source and blazingly fast -> [distributed tracing tool](https://get.uptrace.dev/compare/distributed-tracing-tools.html) powered -> by OpenTelemetry and ClickHouse. Give it a star as well! - -## Sponsors - -### Upstash: Serverless Database for Redis - -Upstash - -Upstash is a Serverless Database with Redis/REST API and durable storage. It is the perfect database -for your applications thanks to its per request pricing and low latency data. - -[Start for free in 30 seconds!](https://upstash.com/?utm_source=goredis) - -
- -## Resources - -- [Documentation](https://redis.uptrace.dev) -- [Discussions](https://github.com/go-redis/redis/discussions) -- [Chat](https://discord.gg/rWtp5Aj) -- [Reference](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc) -- [Examples](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#pkg-examples) - -## Ecosystem - -- [Redis Mock](https://github.com/go-redis/redismock) -- [Distributed Locks](https://github.com/bsm/redislock) -- [Redis Cache](https://github.com/go-redis/cache) -- [Rate limiting](https://github.com/go-redis/redis_rate) - -This client also works with [kvrocks](https://github.com/KvrocksLabs/kvrocks), a distributed key -value NoSQL database that uses RocksDB as storage engine and is compatible with Redis protocol. - -## Features - -- Redis 3 commands except QUIT, MONITOR, and SYNC. -- Automatic connection pooling with -- [Pub/Sub](https://redis.uptrace.dev/guide/go-redis-pubsub.html). -- [Pipelines and transactions](https://redis.uptrace.dev/guide/go-redis-pipelines.html). -- [Scripting](https://redis.uptrace.dev/guide/lua-scripting.html). -- [Redis Sentinel](https://redis.uptrace.dev/guide/go-redis-sentinel.html). -- [Redis Cluster](https://redis.uptrace.dev/guide/go-redis-cluster.html). -- [Redis Ring](https://redis.uptrace.dev/guide/ring.html). -- [Redis Performance Monitoring](https://redis.uptrace.dev/guide/redis-performance-monitoring.html). - -## Installation - -go-redis supports 2 last Go versions and requires a Go version with -[modules](https://github.com/golang/go/wiki/Modules) support. So make sure to initialize a Go -module: - -```shell -go mod init github.com/my/repo -``` - -If you are using **Redis 6**, install go-redis/**v8**: - -```shell -go get github.com/go-redis/redis/v8 -``` - -If you are using **Redis 7**, install go-redis/**v9**: - -```shell -go get github.com/go-redis/redis/v9 -``` - -## Quickstart - -```go -import ( - "context" - "github.com/go-redis/redis/v8" - "fmt" -) - -var ctx = context.Background() - -func ExampleClient() { - rdb := redis.NewClient(&redis.Options{ - Addr: "localhost:6379", - Password: "", // no password set - DB: 0, // use default DB - }) - - err := rdb.Set(ctx, "key", "value", 0).Err() - if err != nil { - panic(err) - } - - val, err := rdb.Get(ctx, "key").Result() - if err != nil { - panic(err) - } - fmt.Println("key", val) - - val2, err := rdb.Get(ctx, "key2").Result() - if err == redis.Nil { - fmt.Println("key2 does not exist") - } else if err != nil { - panic(err) - } else { - fmt.Println("key2", val2) - } - // Output: key value - // key2 does not exist -} -``` - -## Look and feel - -Some corner cases: - -```go -// SET key value EX 10 NX -set, err := rdb.SetNX(ctx, "key", "value", 10*time.Second).Result() - -// SET key value keepttl NX -set, err := rdb.SetNX(ctx, "key", "value", redis.KeepTTL).Result() - -// SORT list LIMIT 0 2 ASC -vals, err := rdb.Sort(ctx, "list", &redis.Sort{Offset: 0, Count: 2, Order: "ASC"}).Result() - -// ZRANGEBYSCORE zset -inf +inf WITHSCORES LIMIT 0 2 -vals, err := rdb.ZRangeByScoreWithScores(ctx, "zset", &redis.ZRangeBy{ - Min: "-inf", - Max: "+inf", - Offset: 0, - Count: 2, -}).Result() - -// ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3 AGGREGATE SUM -vals, err := rdb.ZInterStore(ctx, "out", &redis.ZStore{ - Keys: []string{"zset1", "zset2"}, - Weights: []int64{2, 3} -}).Result() - -// EVAL "return {KEYS[1],ARGV[1]}" 1 "key" "hello" -vals, err := rdb.Eval(ctx, "return {KEYS[1],ARGV[1]}", []string{"key"}, "hello").Result() - -// custom command -res, err := rdb.Do(ctx, "set", "key", "value").Result() -``` - -## Run the test - -go-redis will start a redis-server and run the test cases. - -The paths of redis-server bin file and redis config file are defined in `main_test.go`: - -```go -var ( - redisServerBin, _ = filepath.Abs(filepath.Join("testdata", "redis", "src", "redis-server")) - redisServerConf, _ = filepath.Abs(filepath.Join("testdata", "redis", "redis.conf")) -) -``` - -For local testing, you can change the variables to refer to your local files, or create a soft link -to the corresponding folder for redis-server and copy the config file to `testdata/redis/`: - -```shell -ln -s /usr/bin/redis-server ./go-redis/testdata/redis/src -cp ./go-redis/testdata/redis.conf ./go-redis/testdata/redis/ -``` - -Lastly, run: - -```shell -go test -``` - -## See also - -- [Golang ORM](https://bun.uptrace.dev) for PostgreSQL, MySQL, MSSQL, and SQLite -- [Golang PostgreSQL](https://bun.uptrace.dev/postgres/) -- [Golang HTTP router](https://bunrouter.uptrace.dev/) -- [Golang ClickHouse ORM](https://github.com/uptrace/go-clickhouse) - -## Contributors - -Thanks to all the people who already contributed! - - - - diff --git a/vendor/github.com/go-redis/redis/v9/RELEASING.md b/vendor/github.com/go-redis/redis/v9/RELEASING.md deleted file mode 100644 index 1115db4..0000000 --- a/vendor/github.com/go-redis/redis/v9/RELEASING.md +++ /dev/null @@ -1,15 +0,0 @@ -# Releasing - -1. Run `release.sh` script which updates versions in go.mod files and pushes a new branch to GitHub: - -```shell -TAG=v1.0.0 ./scripts/release.sh -``` - -2. Open a pull request and wait for the build to finish. - -3. Merge the pull request and run `tag.sh` to create tags for packages: - -```shell -TAG=v1.0.0 ./scripts/tag.sh -``` diff --git a/vendor/github.com/go-redis/redis/v9/cluster.go b/vendor/github.com/go-redis/redis/v9/cluster.go deleted file mode 100644 index 05b234a..0000000 --- a/vendor/github.com/go-redis/redis/v9/cluster.go +++ /dev/null @@ -1,1711 +0,0 @@ -package redis - -import ( - "context" - "crypto/tls" - "fmt" - "math" - "net" - "runtime" - "sort" - "sync" - "sync/atomic" - "time" - - "github.com/go-redis/redis/v9/internal" - "github.com/go-redis/redis/v9/internal/hashtag" - "github.com/go-redis/redis/v9/internal/pool" - "github.com/go-redis/redis/v9/internal/proto" - "github.com/go-redis/redis/v9/internal/rand" -) - -var errClusterNoNodes = fmt.Errorf("redis: cluster has no nodes") - -// ClusterOptions are used to configure a cluster client and should be -// passed to NewClusterClient. -type ClusterOptions struct { - // A seed list of host:port addresses of cluster nodes. - Addrs []string - - // NewClient creates a cluster node client with provided name and options. - NewClient func(opt *Options) *Client - - // The maximum number of retries before giving up. Command is retried - // on network errors and MOVED/ASK redirects. - // Default is 3 retries. - MaxRedirects int - - // Enables read-only commands on slave nodes. - ReadOnly bool - // Allows routing read-only commands to the closest master or slave node. - // It automatically enables ReadOnly. - RouteByLatency bool - // Allows routing read-only commands to the random master or slave node. - // It automatically enables ReadOnly. - RouteRandomly bool - - // Optional function that returns cluster slots information. - // It is useful to manually create cluster of standalone Redis servers - // and load-balance read/write operations between master and slaves. - // It can use service like ZooKeeper to maintain configuration information - // and Cluster.ReloadState to manually trigger state reloading. - ClusterSlots func(context.Context) ([]ClusterSlot, error) - - // Following options are copied from Options struct. - - Dialer func(ctx context.Context, network, addr string) (net.Conn, error) - - OnConnect func(ctx context.Context, cn *Conn) error - - Username string - Password string - - MaxRetries int - MinRetryBackoff time.Duration - MaxRetryBackoff time.Duration - - DialTimeout time.Duration - ReadTimeout time.Duration - WriteTimeout time.Duration - - // PoolFIFO uses FIFO mode for each node connection pool GET/PUT (default LIFO). - PoolFIFO bool - - // PoolSize applies per cluster node and not for the whole cluster. - PoolSize int - PoolTimeout time.Duration - MinIdleConns int - MaxIdleConns int - ConnMaxIdleTime time.Duration - ConnMaxLifetime time.Duration - - TLSConfig *tls.Config -} - -func (opt *ClusterOptions) init() { - if opt.MaxRedirects == -1 { - opt.MaxRedirects = 0 - } else if opt.MaxRedirects == 0 { - opt.MaxRedirects = 3 - } - - if opt.RouteByLatency || opt.RouteRandomly { - opt.ReadOnly = true - } - - if opt.PoolSize == 0 { - opt.PoolSize = 5 * runtime.GOMAXPROCS(0) - } - - switch opt.ReadTimeout { - case -1: - opt.ReadTimeout = 0 - case 0: - opt.ReadTimeout = 3 * time.Second - } - switch opt.WriteTimeout { - case -1: - opt.WriteTimeout = 0 - case 0: - opt.WriteTimeout = opt.ReadTimeout - } - - if opt.MaxRetries == 0 { - opt.MaxRetries = -1 - } - switch opt.MinRetryBackoff { - case -1: - opt.MinRetryBackoff = 0 - case 0: - opt.MinRetryBackoff = 8 * time.Millisecond - } - switch opt.MaxRetryBackoff { - case -1: - opt.MaxRetryBackoff = 0 - case 0: - opt.MaxRetryBackoff = 512 * time.Millisecond - } - - if opt.NewClient == nil { - opt.NewClient = NewClient - } -} - -func (opt *ClusterOptions) clientOptions() *Options { - return &Options{ - Dialer: opt.Dialer, - OnConnect: opt.OnConnect, - - Username: opt.Username, - Password: opt.Password, - - MaxRetries: opt.MaxRetries, - MinRetryBackoff: opt.MinRetryBackoff, - MaxRetryBackoff: opt.MaxRetryBackoff, - - DialTimeout: opt.DialTimeout, - ReadTimeout: opt.ReadTimeout, - WriteTimeout: opt.WriteTimeout, - - PoolFIFO: opt.PoolFIFO, - PoolSize: opt.PoolSize, - PoolTimeout: opt.PoolTimeout, - MinIdleConns: opt.MinIdleConns, - MaxIdleConns: opt.MaxIdleConns, - ConnMaxIdleTime: opt.ConnMaxIdleTime, - ConnMaxLifetime: opt.ConnMaxLifetime, - - TLSConfig: opt.TLSConfig, - // If ClusterSlots is populated, then we probably have an artificial - // cluster whose nodes are not in clustering mode (otherwise there isn't - // much use for ClusterSlots config). This means we cannot execute the - // READONLY command against that node -- setting readOnly to false in such - // situations in the options below will prevent that from happening. - readOnly: opt.ReadOnly && opt.ClusterSlots == nil, - } -} - -//------------------------------------------------------------------------------ - -type clusterNode struct { - Client *Client - - latency uint32 // atomic - generation uint32 // atomic - failing uint32 // atomic -} - -func newClusterNode(clOpt *ClusterOptions, addr string) *clusterNode { - opt := clOpt.clientOptions() - opt.Addr = addr - node := clusterNode{ - Client: clOpt.NewClient(opt), - } - - node.latency = math.MaxUint32 - if clOpt.RouteByLatency { - go node.updateLatency() - } - - return &node -} - -func (n *clusterNode) String() string { - return n.Client.String() -} - -func (n *clusterNode) Close() error { - return n.Client.Close() -} - -func (n *clusterNode) updateLatency() { - const numProbe = 10 - var dur uint64 - - successes := 0 - for i := 0; i < numProbe; i++ { - time.Sleep(time.Duration(10+rand.Intn(10)) * time.Millisecond) - - start := time.Now() - err := n.Client.Ping(context.TODO()).Err() - if err == nil { - dur += uint64(time.Since(start) / time.Microsecond) - successes++ - } - } - - var latency float64 - if successes == 0 { - // If none of the pings worked, set latency to some arbitrarily high value so this node gets - // least priority. - latency = float64((1 * time.Minute) / time.Microsecond) - } else { - latency = float64(dur) / float64(successes) - } - atomic.StoreUint32(&n.latency, uint32(latency+0.5)) -} - -func (n *clusterNode) Latency() time.Duration { - latency := atomic.LoadUint32(&n.latency) - return time.Duration(latency) * time.Microsecond -} - -func (n *clusterNode) MarkAsFailing() { - atomic.StoreUint32(&n.failing, uint32(time.Now().Unix())) -} - -func (n *clusterNode) Failing() bool { - const timeout = 15 // 15 seconds - - failing := atomic.LoadUint32(&n.failing) - if failing == 0 { - return false - } - if time.Now().Unix()-int64(failing) < timeout { - return true - } - atomic.StoreUint32(&n.failing, 0) - return false -} - -func (n *clusterNode) Generation() uint32 { - return atomic.LoadUint32(&n.generation) -} - -func (n *clusterNode) SetGeneration(gen uint32) { - for { - v := atomic.LoadUint32(&n.generation) - if gen < v || atomic.CompareAndSwapUint32(&n.generation, v, gen) { - break - } - } -} - -//------------------------------------------------------------------------------ - -type clusterNodes struct { - opt *ClusterOptions - - mu sync.RWMutex - addrs []string - nodes map[string]*clusterNode - activeAddrs []string - closed bool - - _generation uint32 // atomic -} - -func newClusterNodes(opt *ClusterOptions) *clusterNodes { - return &clusterNodes{ - opt: opt, - - addrs: opt.Addrs, - nodes: make(map[string]*clusterNode), - } -} - -func (c *clusterNodes) Close() error { - c.mu.Lock() - defer c.mu.Unlock() - - if c.closed { - return nil - } - c.closed = true - - var firstErr error - for _, node := range c.nodes { - if err := node.Client.Close(); err != nil && firstErr == nil { - firstErr = err - } - } - - c.nodes = nil - c.activeAddrs = nil - - return firstErr -} - -func (c *clusterNodes) Addrs() ([]string, error) { - var addrs []string - - c.mu.RLock() - closed := c.closed //nolint:ifshort - if !closed { - if len(c.activeAddrs) > 0 { - addrs = c.activeAddrs - } else { - addrs = c.addrs - } - } - c.mu.RUnlock() - - if closed { - return nil, pool.ErrClosed - } - if len(addrs) == 0 { - return nil, errClusterNoNodes - } - return addrs, nil -} - -func (c *clusterNodes) NextGeneration() uint32 { - return atomic.AddUint32(&c._generation, 1) -} - -// GC removes unused nodes. -func (c *clusterNodes) GC(generation uint32) { - //nolint:prealloc - var collected []*clusterNode - - c.mu.Lock() - - c.activeAddrs = c.activeAddrs[:0] - for addr, node := range c.nodes { - if node.Generation() >= generation { - c.activeAddrs = append(c.activeAddrs, addr) - if c.opt.RouteByLatency { - go node.updateLatency() - } - continue - } - - delete(c.nodes, addr) - collected = append(collected, node) - } - - c.mu.Unlock() - - for _, node := range collected { - _ = node.Client.Close() - } -} - -func (c *clusterNodes) GetOrCreate(addr string) (*clusterNode, error) { - node, err := c.get(addr) - if err != nil { - return nil, err - } - if node != nil { - return node, nil - } - - c.mu.Lock() - defer c.mu.Unlock() - - if c.closed { - return nil, pool.ErrClosed - } - - node, ok := c.nodes[addr] - if ok { - return node, nil - } - - node = newClusterNode(c.opt, addr) - - c.addrs = appendIfNotExists(c.addrs, addr) - c.nodes[addr] = node - - return node, nil -} - -func (c *clusterNodes) get(addr string) (*clusterNode, error) { - var node *clusterNode - var err error - c.mu.RLock() - if c.closed { - err = pool.ErrClosed - } else { - node = c.nodes[addr] - } - c.mu.RUnlock() - return node, err -} - -func (c *clusterNodes) All() ([]*clusterNode, error) { - c.mu.RLock() - defer c.mu.RUnlock() - - if c.closed { - return nil, pool.ErrClosed - } - - cp := make([]*clusterNode, 0, len(c.nodes)) - for _, node := range c.nodes { - cp = append(cp, node) - } - return cp, nil -} - -func (c *clusterNodes) Random() (*clusterNode, error) { - addrs, err := c.Addrs() - if err != nil { - return nil, err - } - - n := rand.Intn(len(addrs)) - return c.GetOrCreate(addrs[n]) -} - -//------------------------------------------------------------------------------ - -type clusterSlot struct { - start, end int - nodes []*clusterNode -} - -type clusterSlotSlice []*clusterSlot - -func (p clusterSlotSlice) Len() int { - return len(p) -} - -func (p clusterSlotSlice) Less(i, j int) bool { - return p[i].start < p[j].start -} - -func (p clusterSlotSlice) Swap(i, j int) { - p[i], p[j] = p[j], p[i] -} - -type clusterState struct { - nodes *clusterNodes - Masters []*clusterNode - Slaves []*clusterNode - - slots []*clusterSlot - - generation uint32 - createdAt time.Time -} - -func newClusterState( - nodes *clusterNodes, slots []ClusterSlot, origin string, -) (*clusterState, error) { - c := clusterState{ - nodes: nodes, - - slots: make([]*clusterSlot, 0, len(slots)), - - generation: nodes.NextGeneration(), - createdAt: time.Now(), - } - - originHost, _, _ := net.SplitHostPort(origin) - isLoopbackOrigin := isLoopback(originHost) - - for _, slot := range slots { - var nodes []*clusterNode - for i, slotNode := range slot.Nodes { - addr := slotNode.Addr - if !isLoopbackOrigin { - addr = replaceLoopbackHost(addr, originHost) - } - - node, err := c.nodes.GetOrCreate(addr) - if err != nil { - return nil, err - } - - node.SetGeneration(c.generation) - nodes = append(nodes, node) - - if i == 0 { - c.Masters = appendUniqueNode(c.Masters, node) - } else { - c.Slaves = appendUniqueNode(c.Slaves, node) - } - } - - c.slots = append(c.slots, &clusterSlot{ - start: slot.Start, - end: slot.End, - nodes: nodes, - }) - } - - sort.Sort(clusterSlotSlice(c.slots)) - - time.AfterFunc(time.Minute, func() { - nodes.GC(c.generation) - }) - - return &c, nil -} - -func replaceLoopbackHost(nodeAddr, originHost string) string { - nodeHost, nodePort, err := net.SplitHostPort(nodeAddr) - if err != nil { - return nodeAddr - } - - nodeIP := net.ParseIP(nodeHost) - if nodeIP == nil { - return nodeAddr - } - - if !nodeIP.IsLoopback() { - return nodeAddr - } - - // Use origin host which is not loopback and node port. - return net.JoinHostPort(originHost, nodePort) -} - -func isLoopback(host string) bool { - ip := net.ParseIP(host) - if ip == nil { - return true - } - return ip.IsLoopback() -} - -func (c *clusterState) slotMasterNode(slot int) (*clusterNode, error) { - nodes := c.slotNodes(slot) - if len(nodes) > 0 { - return nodes[0], nil - } - return c.nodes.Random() -} - -func (c *clusterState) slotSlaveNode(slot int) (*clusterNode, error) { - nodes := c.slotNodes(slot) - switch len(nodes) { - case 0: - return c.nodes.Random() - case 1: - return nodes[0], nil - case 2: - if slave := nodes[1]; !slave.Failing() { - return slave, nil - } - return nodes[0], nil - default: - var slave *clusterNode - for i := 0; i < 10; i++ { - n := rand.Intn(len(nodes)-1) + 1 - slave = nodes[n] - if !slave.Failing() { - return slave, nil - } - } - - // All slaves are loading - use master. - return nodes[0], nil - } -} - -func (c *clusterState) slotClosestNode(slot int) (*clusterNode, error) { - nodes := c.slotNodes(slot) - if len(nodes) == 0 { - return c.nodes.Random() - } - - var node *clusterNode - for _, n := range nodes { - if n.Failing() { - continue - } - if node == nil || n.Latency() < node.Latency() { - node = n - } - } - if node != nil { - return node, nil - } - - // If all nodes are failing - return random node - return c.nodes.Random() -} - -func (c *clusterState) slotRandomNode(slot int) (*clusterNode, error) { - nodes := c.slotNodes(slot) - if len(nodes) == 0 { - return c.nodes.Random() - } - if len(nodes) == 1 { - return nodes[0], nil - } - randomNodes := rand.Perm(len(nodes)) - for _, idx := range randomNodes { - if node := nodes[idx]; !node.Failing() { - return node, nil - } - } - return nodes[randomNodes[0]], nil -} - -func (c *clusterState) slotNodes(slot int) []*clusterNode { - i := sort.Search(len(c.slots), func(i int) bool { - return c.slots[i].end >= slot - }) - if i >= len(c.slots) { - return nil - } - x := c.slots[i] - if slot >= x.start && slot <= x.end { - return x.nodes - } - return nil -} - -//------------------------------------------------------------------------------ - -type clusterStateHolder struct { - load func(ctx context.Context) (*clusterState, error) - - state atomic.Value - reloading uint32 // atomic -} - -func newClusterStateHolder(fn func(ctx context.Context) (*clusterState, error)) *clusterStateHolder { - return &clusterStateHolder{ - load: fn, - } -} - -func (c *clusterStateHolder) Reload(ctx context.Context) (*clusterState, error) { - state, err := c.load(ctx) - if err != nil { - return nil, err - } - c.state.Store(state) - return state, nil -} - -func (c *clusterStateHolder) LazyReload() { - if !atomic.CompareAndSwapUint32(&c.reloading, 0, 1) { - return - } - go func() { - defer atomic.StoreUint32(&c.reloading, 0) - - _, err := c.Reload(context.Background()) - if err != nil { - return - } - time.Sleep(200 * time.Millisecond) - }() -} - -func (c *clusterStateHolder) Get(ctx context.Context) (*clusterState, error) { - v := c.state.Load() - if v == nil { - return c.Reload(ctx) - } - - state := v.(*clusterState) - if time.Since(state.createdAt) > 10*time.Second { - c.LazyReload() - } - return state, nil -} - -func (c *clusterStateHolder) ReloadOrGet(ctx context.Context) (*clusterState, error) { - state, err := c.Reload(ctx) - if err == nil { - return state, nil - } - return c.Get(ctx) -} - -//------------------------------------------------------------------------------ - -type clusterClient struct { - opt *ClusterOptions - nodes *clusterNodes - state *clusterStateHolder //nolint:structcheck - cmdsInfoCache *cmdsInfoCache //nolint:structcheck -} - -// ClusterClient is a Redis Cluster client representing a pool of zero -// or more underlying connections. It's safe for concurrent use by -// multiple goroutines. -type ClusterClient struct { - *clusterClient - cmdable - hooks -} - -// NewClusterClient returns a Redis Cluster client as described in -// http://redis.io/topics/cluster-spec. -func NewClusterClient(opt *ClusterOptions) *ClusterClient { - opt.init() - - c := &ClusterClient{ - clusterClient: &clusterClient{ - opt: opt, - nodes: newClusterNodes(opt), - }, - } - c.state = newClusterStateHolder(c.loadState) - c.cmdsInfoCache = newCmdsInfoCache(c.cmdsInfo) - c.cmdable = c.Process - - return c -} - -// Options returns read-only Options that were used to create the client. -func (c *ClusterClient) Options() *ClusterOptions { - return c.opt -} - -// ReloadState reloads cluster state. If available it calls ClusterSlots func -// to get cluster slots information. -func (c *ClusterClient) ReloadState(ctx context.Context) { - c.state.LazyReload() -} - -// Close closes the cluster client, releasing any open resources. -// -// It is rare to Close a ClusterClient, as the ClusterClient is meant -// to be long-lived and shared between many goroutines. -func (c *ClusterClient) Close() error { - return c.nodes.Close() -} - -// Do creates a Cmd from the args and processes the cmd. -func (c *ClusterClient) Do(ctx context.Context, args ...interface{}) *Cmd { - cmd := NewCmd(ctx, args...) - _ = c.Process(ctx, cmd) - return cmd -} - -func (c *ClusterClient) Process(ctx context.Context, cmd Cmder) error { - return c.hooks.process(ctx, cmd, c.process) -} - -func (c *ClusterClient) process(ctx context.Context, cmd Cmder) error { - cmdInfo := c.cmdInfo(ctx, cmd.Name()) - slot := c.cmdSlot(ctx, cmd) - - var node *clusterNode - var ask bool - var lastErr error - for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ { - if attempt > 0 { - if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil { - return err - } - } - - if node == nil { - var err error - node, err = c.cmdNode(ctx, cmdInfo, slot) - if err != nil { - return err - } - } - - if ask { - pipe := node.Client.Pipeline() - _ = pipe.Process(ctx, NewCmd(ctx, "asking")) - _ = pipe.Process(ctx, cmd) - _, lastErr = pipe.Exec(ctx) - ask = false - } else { - lastErr = node.Client.Process(ctx, cmd) - } - - // If there is no error - we are done. - if lastErr == nil { - return nil - } - if isReadOnly := isReadOnlyError(lastErr); isReadOnly || lastErr == pool.ErrClosed { - if isReadOnly { - c.state.LazyReload() - } - node = nil - continue - } - - // If slave is loading - pick another node. - if c.opt.ReadOnly && isLoadingError(lastErr) { - node.MarkAsFailing() - node = nil - continue - } - - var moved bool - var addr string - moved, ask, addr = isMovedError(lastErr) - if moved || ask { - c.state.LazyReload() - - var err error - node, err = c.nodes.GetOrCreate(addr) - if err != nil { - return err - } - continue - } - - if shouldRetry(lastErr, cmd.readTimeout() == nil) { - // First retry the same node. - if attempt == 0 { - continue - } - - // Second try another node. - node.MarkAsFailing() - node = nil - continue - } - - return lastErr - } - return lastErr -} - -// ForEachMaster concurrently calls the fn on each master node in the cluster. -// It returns the first error if any. -func (c *ClusterClient) ForEachMaster( - ctx context.Context, - fn func(ctx context.Context, client *Client) error, -) error { - state, err := c.state.ReloadOrGet(ctx) - if err != nil { - return err - } - - var wg sync.WaitGroup - errCh := make(chan error, 1) - - for _, master := range state.Masters { - wg.Add(1) - go func(node *clusterNode) { - defer wg.Done() - err := fn(ctx, node.Client) - if err != nil { - select { - case errCh <- err: - default: - } - } - }(master) - } - - wg.Wait() - - select { - case err := <-errCh: - return err - default: - return nil - } -} - -// ForEachSlave concurrently calls the fn on each slave node in the cluster. -// It returns the first error if any. -func (c *ClusterClient) ForEachSlave( - ctx context.Context, - fn func(ctx context.Context, client *Client) error, -) error { - state, err := c.state.ReloadOrGet(ctx) - if err != nil { - return err - } - - var wg sync.WaitGroup - errCh := make(chan error, 1) - - for _, slave := range state.Slaves { - wg.Add(1) - go func(node *clusterNode) { - defer wg.Done() - err := fn(ctx, node.Client) - if err != nil { - select { - case errCh <- err: - default: - } - } - }(slave) - } - - wg.Wait() - - select { - case err := <-errCh: - return err - default: - return nil - } -} - -// ForEachShard concurrently calls the fn on each known node in the cluster. -// It returns the first error if any. -func (c *ClusterClient) ForEachShard( - ctx context.Context, - fn func(ctx context.Context, client *Client) error, -) error { - state, err := c.state.ReloadOrGet(ctx) - if err != nil { - return err - } - - var wg sync.WaitGroup - errCh := make(chan error, 1) - - worker := func(node *clusterNode) { - defer wg.Done() - err := fn(ctx, node.Client) - if err != nil { - select { - case errCh <- err: - default: - } - } - } - - for _, node := range state.Masters { - wg.Add(1) - go worker(node) - } - for _, node := range state.Slaves { - wg.Add(1) - go worker(node) - } - - wg.Wait() - - select { - case err := <-errCh: - return err - default: - return nil - } -} - -// PoolStats returns accumulated connection pool stats. -func (c *ClusterClient) PoolStats() *PoolStats { - var acc PoolStats - - state, _ := c.state.Get(context.TODO()) - if state == nil { - return &acc - } - - for _, node := range state.Masters { - s := node.Client.connPool.Stats() - acc.Hits += s.Hits - acc.Misses += s.Misses - acc.Timeouts += s.Timeouts - - acc.TotalConns += s.TotalConns - acc.IdleConns += s.IdleConns - acc.StaleConns += s.StaleConns - } - - for _, node := range state.Slaves { - s := node.Client.connPool.Stats() - acc.Hits += s.Hits - acc.Misses += s.Misses - acc.Timeouts += s.Timeouts - - acc.TotalConns += s.TotalConns - acc.IdleConns += s.IdleConns - acc.StaleConns += s.StaleConns - } - - return &acc -} - -func (c *ClusterClient) loadState(ctx context.Context) (*clusterState, error) { - if c.opt.ClusterSlots != nil { - slots, err := c.opt.ClusterSlots(ctx) - if err != nil { - return nil, err - } - return newClusterState(c.nodes, slots, "") - } - - addrs, err := c.nodes.Addrs() - if err != nil { - return nil, err - } - - var firstErr error - - for _, idx := range rand.Perm(len(addrs)) { - addr := addrs[idx] - - node, err := c.nodes.GetOrCreate(addr) - if err != nil { - if firstErr == nil { - firstErr = err - } - continue - } - - slots, err := node.Client.ClusterSlots(ctx).Result() - if err != nil { - if firstErr == nil { - firstErr = err - } - continue - } - - return newClusterState(c.nodes, slots, node.Client.opt.Addr) - } - - /* - * No node is connectable. It's possible that all nodes' IP has changed. - * Clear activeAddrs to let client be able to re-connect using the initial - * setting of the addresses (e.g. [redis-cluster-0:6379, redis-cluster-1:6379]), - * which might have chance to resolve domain name and get updated IP address. - */ - c.nodes.mu.Lock() - c.nodes.activeAddrs = nil - c.nodes.mu.Unlock() - - return nil, firstErr -} - -func (c *ClusterClient) Pipeline() Pipeliner { - pipe := Pipeline{ - exec: c.processPipeline, - } - pipe.init() - return &pipe -} - -func (c *ClusterClient) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { - return c.Pipeline().Pipelined(ctx, fn) -} - -func (c *ClusterClient) processPipeline(ctx context.Context, cmds []Cmder) error { - return c.hooks.processPipeline(ctx, cmds, c._processPipeline) -} - -func (c *ClusterClient) _processPipeline(ctx context.Context, cmds []Cmder) error { - cmdsMap := newCmdsMap() - err := c.mapCmdsByNode(ctx, cmdsMap, cmds) - if err != nil { - setCmdsErr(cmds, err) - return err - } - - for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ { - if attempt > 0 { - if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil { - setCmdsErr(cmds, err) - return err - } - } - - failedCmds := newCmdsMap() - var wg sync.WaitGroup - - for node, cmds := range cmdsMap.m { - wg.Add(1) - go func(node *clusterNode, cmds []Cmder) { - defer wg.Done() - - err := c._processPipelineNode(ctx, node, cmds, failedCmds) - if err == nil { - return - } - if attempt < c.opt.MaxRedirects { - if err := c.mapCmdsByNode(ctx, failedCmds, cmds); err != nil { - setCmdsErr(cmds, err) - } - } else { - setCmdsErr(cmds, err) - } - }(node, cmds) - } - - wg.Wait() - if len(failedCmds.m) == 0 { - break - } - cmdsMap = failedCmds - } - - return cmdsFirstErr(cmds) -} - -func (c *ClusterClient) mapCmdsByNode(ctx context.Context, cmdsMap *cmdsMap, cmds []Cmder) error { - state, err := c.state.Get(ctx) - if err != nil { - return err - } - - if c.opt.ReadOnly && c.cmdsAreReadOnly(ctx, cmds) { - for _, cmd := range cmds { - slot := c.cmdSlot(ctx, cmd) - node, err := c.slotReadOnlyNode(state, slot) - if err != nil { - return err - } - cmdsMap.Add(node, cmd) - } - return nil - } - - for _, cmd := range cmds { - slot := c.cmdSlot(ctx, cmd) - node, err := state.slotMasterNode(slot) - if err != nil { - return err - } - cmdsMap.Add(node, cmd) - } - return nil -} - -func (c *ClusterClient) cmdsAreReadOnly(ctx context.Context, cmds []Cmder) bool { - for _, cmd := range cmds { - cmdInfo := c.cmdInfo(ctx, cmd.Name()) - if cmdInfo == nil || !cmdInfo.ReadOnly { - return false - } - } - return true -} - -func (c *ClusterClient) _processPipelineNode( - ctx context.Context, node *clusterNode, cmds []Cmder, failedCmds *cmdsMap, -) error { - return node.Client.hooks.processPipeline(ctx, cmds, func(ctx context.Context, cmds []Cmder) error { - return node.Client.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error { - err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error { - return writeCmds(wr, cmds) - }) - if err != nil { - return err - } - - return cn.WithReader(ctx, c.opt.ReadTimeout, func(rd *proto.Reader) error { - return c.pipelineReadCmds(ctx, node, rd, cmds, failedCmds) - }) - }) - }) -} - -func (c *ClusterClient) pipelineReadCmds( - ctx context.Context, - node *clusterNode, - rd *proto.Reader, - cmds []Cmder, - failedCmds *cmdsMap, -) error { - for _, cmd := range cmds { - err := cmd.readReply(rd) - cmd.SetErr(err) - - if err == nil { - continue - } - - if c.checkMovedErr(ctx, cmd, err, failedCmds) { - continue - } - - if c.opt.ReadOnly && (isLoadingError(err) || !isRedisError(err)) { - node.MarkAsFailing() - return err - } - if isRedisError(err) { - continue - } - return err - } - return nil -} - -func (c *ClusterClient) checkMovedErr( - ctx context.Context, cmd Cmder, err error, failedCmds *cmdsMap, -) bool { - moved, ask, addr := isMovedError(err) - if !moved && !ask { - return false - } - - node, err := c.nodes.GetOrCreate(addr) - if err != nil { - return false - } - - if moved { - c.state.LazyReload() - failedCmds.Add(node, cmd) - return true - } - - if ask { - failedCmds.Add(node, NewCmd(ctx, "asking"), cmd) - return true - } - - panic("not reached") -} - -// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC. -func (c *ClusterClient) TxPipeline() Pipeliner { - pipe := Pipeline{ - exec: c.processTxPipeline, - } - pipe.init() - return &pipe -} - -func (c *ClusterClient) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { - return c.TxPipeline().Pipelined(ctx, fn) -} - -func (c *ClusterClient) processTxPipeline(ctx context.Context, cmds []Cmder) error { - return c.hooks.processTxPipeline(ctx, cmds, c._processTxPipeline) -} - -func (c *ClusterClient) _processTxPipeline(ctx context.Context, cmds []Cmder) error { - // Trim multi .. exec. - cmds = cmds[1 : len(cmds)-1] - - state, err := c.state.Get(ctx) - if err != nil { - setCmdsErr(cmds, err) - return err - } - - cmdsMap := c.mapCmdsBySlot(ctx, cmds) - for slot, cmds := range cmdsMap { - node, err := state.slotMasterNode(slot) - if err != nil { - setCmdsErr(cmds, err) - continue - } - - cmdsMap := map[*clusterNode][]Cmder{node: cmds} - for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ { - if attempt > 0 { - if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil { - setCmdsErr(cmds, err) - return err - } - } - - failedCmds := newCmdsMap() - var wg sync.WaitGroup - - for node, cmds := range cmdsMap { - wg.Add(1) - go func(node *clusterNode, cmds []Cmder) { - defer wg.Done() - - err := c._processTxPipelineNode(ctx, node, cmds, failedCmds) - if err == nil { - return - } - - if attempt < c.opt.MaxRedirects { - if err := c.mapCmdsByNode(ctx, failedCmds, cmds); err != nil { - setCmdsErr(cmds, err) - } - } else { - setCmdsErr(cmds, err) - } - }(node, cmds) - } - - wg.Wait() - if len(failedCmds.m) == 0 { - break - } - cmdsMap = failedCmds.m - } - } - - return cmdsFirstErr(cmds) -} - -func (c *ClusterClient) mapCmdsBySlot(ctx context.Context, cmds []Cmder) map[int][]Cmder { - cmdsMap := make(map[int][]Cmder) - for _, cmd := range cmds { - slot := c.cmdSlot(ctx, cmd) - cmdsMap[slot] = append(cmdsMap[slot], cmd) - } - return cmdsMap -} - -func (c *ClusterClient) _processTxPipelineNode( - ctx context.Context, node *clusterNode, cmds []Cmder, failedCmds *cmdsMap, -) error { - return node.Client.hooks.processTxPipeline(ctx, cmds, func(ctx context.Context, cmds []Cmder) error { - return node.Client.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error { - err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error { - return writeCmds(wr, cmds) - }) - if err != nil { - return err - } - - return cn.WithReader(ctx, c.opt.ReadTimeout, func(rd *proto.Reader) error { - statusCmd := cmds[0].(*StatusCmd) - // Trim multi and exec. - cmds = cmds[1 : len(cmds)-1] - - err := c.txPipelineReadQueued(ctx, rd, statusCmd, cmds, failedCmds) - if err != nil { - moved, ask, addr := isMovedError(err) - if moved || ask { - return c.cmdsMoved(ctx, cmds, moved, ask, addr, failedCmds) - } - return err - } - - return pipelineReadCmds(rd, cmds) - }) - }) - }) -} - -func (c *ClusterClient) txPipelineReadQueued( - ctx context.Context, - rd *proto.Reader, - statusCmd *StatusCmd, - cmds []Cmder, - failedCmds *cmdsMap, -) error { - // Parse queued replies. - if err := statusCmd.readReply(rd); err != nil { - return err - } - - for _, cmd := range cmds { - err := statusCmd.readReply(rd) - if err == nil || c.checkMovedErr(ctx, cmd, err, failedCmds) || isRedisError(err) { - continue - } - return err - } - - // Parse number of replies. - line, err := rd.ReadLine() - if err != nil { - if err == Nil { - err = TxFailedErr - } - return err - } - - if line[0] != proto.RespArray { - return fmt.Errorf("redis: expected '*', but got line %q", line) - } - - return nil -} - -func (c *ClusterClient) cmdsMoved( - ctx context.Context, cmds []Cmder, - moved, ask bool, - addr string, - failedCmds *cmdsMap, -) error { - node, err := c.nodes.GetOrCreate(addr) - if err != nil { - return err - } - - if moved { - c.state.LazyReload() - for _, cmd := range cmds { - failedCmds.Add(node, cmd) - } - return nil - } - - if ask { - for _, cmd := range cmds { - failedCmds.Add(node, NewCmd(ctx, "asking"), cmd) - } - return nil - } - - return nil -} - -func (c *ClusterClient) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error { - if len(keys) == 0 { - return fmt.Errorf("redis: Watch requires at least one key") - } - - slot := hashtag.Slot(keys[0]) - for _, key := range keys[1:] { - if hashtag.Slot(key) != slot { - err := fmt.Errorf("redis: Watch requires all keys to be in the same slot") - return err - } - } - - node, err := c.slotMasterNode(ctx, slot) - if err != nil { - return err - } - - for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ { - if attempt > 0 { - if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil { - return err - } - } - - err = node.Client.Watch(ctx, fn, keys...) - if err == nil { - break - } - - moved, ask, addr := isMovedError(err) - if moved || ask { - node, err = c.nodes.GetOrCreate(addr) - if err != nil { - return err - } - continue - } - - if isReadOnly := isReadOnlyError(err); isReadOnly || err == pool.ErrClosed { - if isReadOnly { - c.state.LazyReload() - } - node, err = c.slotMasterNode(ctx, slot) - if err != nil { - return err - } - continue - } - - if shouldRetry(err, true) { - continue - } - - return err - } - - return err -} - -func (c *ClusterClient) pubSub() *PubSub { - var node *clusterNode - pubsub := &PubSub{ - opt: c.opt.clientOptions(), - - newConn: func(ctx context.Context, channels []string) (*pool.Conn, error) { - if node != nil { - panic("node != nil") - } - - var err error - if len(channels) > 0 { - slot := hashtag.Slot(channels[0]) - node, err = c.slotMasterNode(ctx, slot) - } else { - node, err = c.nodes.Random() - } - if err != nil { - return nil, err - } - - cn, err := node.Client.newConn(context.TODO()) - if err != nil { - node = nil - - return nil, err - } - - return cn, nil - }, - closeConn: func(cn *pool.Conn) error { - err := node.Client.connPool.CloseConn(cn) - node = nil - return err - }, - } - pubsub.init() - - return pubsub -} - -// Subscribe subscribes the client to the specified channels. -// Channels can be omitted to create empty subscription. -func (c *ClusterClient) Subscribe(ctx context.Context, channels ...string) *PubSub { - pubsub := c.pubSub() - if len(channels) > 0 { - _ = pubsub.Subscribe(ctx, channels...) - } - return pubsub -} - -// PSubscribe subscribes the client to the given patterns. -// Patterns can be omitted to create empty subscription. -func (c *ClusterClient) PSubscribe(ctx context.Context, channels ...string) *PubSub { - pubsub := c.pubSub() - if len(channels) > 0 { - _ = pubsub.PSubscribe(ctx, channels...) - } - return pubsub -} - -func (c *ClusterClient) retryBackoff(attempt int) time.Duration { - return internal.RetryBackoff(attempt, c.opt.MinRetryBackoff, c.opt.MaxRetryBackoff) -} - -func (c *ClusterClient) cmdsInfo(ctx context.Context) (map[string]*CommandInfo, error) { - // Try 3 random nodes. - const nodeLimit = 3 - - addrs, err := c.nodes.Addrs() - if err != nil { - return nil, err - } - - var firstErr error - - perm := rand.Perm(len(addrs)) - if len(perm) > nodeLimit { - perm = perm[:nodeLimit] - } - - for _, idx := range perm { - addr := addrs[idx] - - node, err := c.nodes.GetOrCreate(addr) - if err != nil { - if firstErr == nil { - firstErr = err - } - continue - } - - info, err := node.Client.Command(ctx).Result() - if err == nil { - return info, nil - } - if firstErr == nil { - firstErr = err - } - } - - if firstErr == nil { - panic("not reached") - } - return nil, firstErr -} - -func (c *ClusterClient) cmdInfo(ctx context.Context, name string) *CommandInfo { - cmdsInfo, err := c.cmdsInfoCache.Get(ctx) - if err != nil { - internal.Logger.Printf(context.TODO(), "getting command info: %s", err) - return nil - } - - info := cmdsInfo[name] - if info == nil { - internal.Logger.Printf(context.TODO(), "info for cmd=%s not found", name) - } - return info -} - -func (c *ClusterClient) cmdSlot(ctx context.Context, cmd Cmder) int { - args := cmd.Args() - if args[0] == "cluster" && args[1] == "getkeysinslot" { - return args[2].(int) - } - - cmdInfo := c.cmdInfo(ctx, cmd.Name()) - return cmdSlot(cmd, cmdFirstKeyPos(cmd, cmdInfo)) -} - -func cmdSlot(cmd Cmder, pos int) int { - if pos == 0 { - return hashtag.RandomSlot() - } - firstKey := cmd.stringArg(pos) - return hashtag.Slot(firstKey) -} - -func (c *ClusterClient) cmdNode( - ctx context.Context, - cmdInfo *CommandInfo, - slot int, -) (*clusterNode, error) { - state, err := c.state.Get(ctx) - if err != nil { - return nil, err - } - - if c.opt.ReadOnly && cmdInfo != nil && cmdInfo.ReadOnly { - return c.slotReadOnlyNode(state, slot) - } - return state.slotMasterNode(slot) -} - -func (c *clusterClient) slotReadOnlyNode(state *clusterState, slot int) (*clusterNode, error) { - if c.opt.RouteByLatency { - return state.slotClosestNode(slot) - } - if c.opt.RouteRandomly { - return state.slotRandomNode(slot) - } - return state.slotSlaveNode(slot) -} - -func (c *ClusterClient) slotMasterNode(ctx context.Context, slot int) (*clusterNode, error) { - state, err := c.state.Get(ctx) - if err != nil { - return nil, err - } - return state.slotMasterNode(slot) -} - -// SlaveForKey gets a client for a replica node to run any command on it. -// This is especially useful if we want to run a particular lua script which has -// only read only commands on the replica. -// This is because other redis commands generally have a flag that points that -// they are read only and automatically run on the replica nodes -// if ClusterOptions.ReadOnly flag is set to true. -func (c *ClusterClient) SlaveForKey(ctx context.Context, key string) (*Client, error) { - state, err := c.state.Get(ctx) - if err != nil { - return nil, err - } - slot := hashtag.Slot(key) - node, err := c.slotReadOnlyNode(state, slot) - if err != nil { - return nil, err - } - return node.Client, err -} - -// MasterForKey return a client to the master node for a particular key. -func (c *ClusterClient) MasterForKey(ctx context.Context, key string) (*Client, error) { - slot := hashtag.Slot(key) - node, err := c.slotMasterNode(ctx, slot) - if err != nil { - return nil, err - } - return node.Client, err -} - -func appendUniqueNode(nodes []*clusterNode, node *clusterNode) []*clusterNode { - for _, n := range nodes { - if n == node { - return nodes - } - } - return append(nodes, node) -} - -func appendIfNotExists(ss []string, es ...string) []string { -loop: - for _, e := range es { - for _, s := range ss { - if s == e { - continue loop - } - } - ss = append(ss, e) - } - return ss -} - -//------------------------------------------------------------------------------ - -type cmdsMap struct { - mu sync.Mutex - m map[*clusterNode][]Cmder -} - -func newCmdsMap() *cmdsMap { - return &cmdsMap{ - m: make(map[*clusterNode][]Cmder), - } -} - -func (m *cmdsMap) Add(node *clusterNode, cmds ...Cmder) { - m.mu.Lock() - m.m[node] = append(m.m[node], cmds...) - m.mu.Unlock() -} diff --git a/vendor/github.com/go-redis/redis/v9/cluster_commands.go b/vendor/github.com/go-redis/redis/v9/cluster_commands.go deleted file mode 100644 index 085bce8..0000000 --- a/vendor/github.com/go-redis/redis/v9/cluster_commands.go +++ /dev/null @@ -1,109 +0,0 @@ -package redis - -import ( - "context" - "sync" - "sync/atomic" -) - -func (c *ClusterClient) DBSize(ctx context.Context) *IntCmd { - cmd := NewIntCmd(ctx, "dbsize") - _ = c.hooks.process(ctx, cmd, func(ctx context.Context, _ Cmder) error { - var size int64 - err := c.ForEachMaster(ctx, func(ctx context.Context, master *Client) error { - n, err := master.DBSize(ctx).Result() - if err != nil { - return err - } - atomic.AddInt64(&size, n) - return nil - }) - if err != nil { - cmd.SetErr(err) - } else { - cmd.val = size - } - return nil - }) - return cmd -} - -func (c *ClusterClient) ScriptLoad(ctx context.Context, script string) *StringCmd { - cmd := NewStringCmd(ctx, "script", "load", script) - _ = c.hooks.process(ctx, cmd, func(ctx context.Context, _ Cmder) error { - mu := &sync.Mutex{} - err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error { - val, err := shard.ScriptLoad(ctx, script).Result() - if err != nil { - return err - } - - mu.Lock() - if cmd.Val() == "" { - cmd.val = val - } - mu.Unlock() - - return nil - }) - if err != nil { - cmd.SetErr(err) - } - return nil - }) - return cmd -} - -func (c *ClusterClient) ScriptFlush(ctx context.Context) *StatusCmd { - cmd := NewStatusCmd(ctx, "script", "flush") - _ = c.hooks.process(ctx, cmd, func(ctx context.Context, _ Cmder) error { - err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error { - return shard.ScriptFlush(ctx).Err() - }) - if err != nil { - cmd.SetErr(err) - } - return nil - }) - return cmd -} - -func (c *ClusterClient) ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd { - args := make([]interface{}, 2+len(hashes)) - args[0] = "script" - args[1] = "exists" - for i, hash := range hashes { - args[2+i] = hash - } - cmd := NewBoolSliceCmd(ctx, args...) - - result := make([]bool, len(hashes)) - for i := range result { - result[i] = true - } - - _ = c.hooks.process(ctx, cmd, func(ctx context.Context, _ Cmder) error { - mu := &sync.Mutex{} - err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error { - val, err := shard.ScriptExists(ctx, hashes...).Result() - if err != nil { - return err - } - - mu.Lock() - for i, v := range val { - result[i] = result[i] && v - } - mu.Unlock() - - return nil - }) - if err != nil { - cmd.SetErr(err) - } else { - cmd.val = result - } - return nil - }) - return cmd -} diff --git a/vendor/github.com/go-redis/redis/v9/command.go b/vendor/github.com/go-redis/redis/v9/command.go deleted file mode 100644 index a6f74db..0000000 --- a/vendor/github.com/go-redis/redis/v9/command.go +++ /dev/null @@ -1,3680 +0,0 @@ -package redis - -import ( - "context" - "fmt" - "net" - "strconv" - "time" - - "github.com/go-redis/redis/v9/internal" - "github.com/go-redis/redis/v9/internal/hscan" - "github.com/go-redis/redis/v9/internal/proto" - "github.com/go-redis/redis/v9/internal/util" -) - -type Cmder interface { - Name() string - FullName() string - Args() []interface{} - String() string - stringArg(int) string - firstKeyPos() int8 - SetFirstKeyPos(int8) - - readTimeout() *time.Duration - readReply(rd *proto.Reader) error - - SetErr(error) - Err() error -} - -func setCmdsErr(cmds []Cmder, e error) { - for _, cmd := range cmds { - if cmd.Err() == nil { - cmd.SetErr(e) - } - } -} - -func cmdsFirstErr(cmds []Cmder) error { - for _, cmd := range cmds { - if err := cmd.Err(); err != nil { - return err - } - } - return nil -} - -func writeCmds(wr *proto.Writer, cmds []Cmder) error { - for _, cmd := range cmds { - if err := writeCmd(wr, cmd); err != nil { - return err - } - } - return nil -} - -func writeCmd(wr *proto.Writer, cmd Cmder) error { - return wr.WriteArgs(cmd.Args()) -} - -func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int { - if pos := cmd.firstKeyPos(); pos != 0 { - return int(pos) - } - - switch cmd.Name() { - case "eval", "evalsha": - if cmd.stringArg(2) != "0" { - return 3 - } - - return 0 - case "publish": - return 1 - case "memory": - // https://github.com/redis/redis/issues/7493 - if cmd.stringArg(1) == "usage" { - return 2 - } - } - - if info != nil { - return int(info.FirstKeyPos) - } - return 1 -} - -func cmdString(cmd Cmder, val interface{}) string { - b := make([]byte, 0, 64) - - for i, arg := range cmd.Args() { - if i > 0 { - b = append(b, ' ') - } - b = internal.AppendArg(b, arg) - } - - if err := cmd.Err(); err != nil { - b = append(b, ": "...) - b = append(b, err.Error()...) - } else if val != nil { - b = append(b, ": "...) - b = internal.AppendArg(b, val) - } - - return internal.String(b) -} - -//------------------------------------------------------------------------------ - -type baseCmd struct { - ctx context.Context - args []interface{} - err error - keyPos int8 - - _readTimeout *time.Duration -} - -var _ Cmder = (*Cmd)(nil) - -func (cmd *baseCmd) Name() string { - if len(cmd.args) == 0 { - return "" - } - // Cmd name must be lower cased. - return internal.ToLower(cmd.stringArg(0)) -} - -func (cmd *baseCmd) FullName() string { - switch name := cmd.Name(); name { - case "cluster", "command": - if len(cmd.args) == 1 { - return name - } - if s2, ok := cmd.args[1].(string); ok { - return name + " " + s2 - } - return name - default: - return name - } -} - -func (cmd *baseCmd) Args() []interface{} { - return cmd.args -} - -func (cmd *baseCmd) stringArg(pos int) string { - if pos < 0 || pos >= len(cmd.args) { - return "" - } - arg := cmd.args[pos] - switch v := arg.(type) { - case string: - return v - default: - // TODO: consider using appendArg - return fmt.Sprint(v) - } -} - -func (cmd *baseCmd) firstKeyPos() int8 { - return cmd.keyPos -} - -func (cmd *baseCmd) SetFirstKeyPos(keyPos int8) { - cmd.keyPos = keyPos -} - -func (cmd *baseCmd) SetErr(e error) { - cmd.err = e -} - -func (cmd *baseCmd) Err() error { - return cmd.err -} - -func (cmd *baseCmd) readTimeout() *time.Duration { - return cmd._readTimeout -} - -func (cmd *baseCmd) setReadTimeout(d time.Duration) { - cmd._readTimeout = &d -} - -//------------------------------------------------------------------------------ - -type Cmd struct { - baseCmd - - val interface{} -} - -func NewCmd(ctx context.Context, args ...interface{}) *Cmd { - return &Cmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *Cmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *Cmd) SetVal(val interface{}) { - cmd.val = val -} - -func (cmd *Cmd) Val() interface{} { - return cmd.val -} - -func (cmd *Cmd) Result() (interface{}, error) { - return cmd.val, cmd.err -} - -func (cmd *Cmd) Text() (string, error) { - if cmd.err != nil { - return "", cmd.err - } - return toString(cmd.val) -} - -func toString(val interface{}) (string, error) { - switch val := val.(type) { - case string: - return val, nil - default: - err := fmt.Errorf("redis: unexpected type=%T for String", val) - return "", err - } -} - -func (cmd *Cmd) Int() (int, error) { - if cmd.err != nil { - return 0, cmd.err - } - switch val := cmd.val.(type) { - case int64: - return int(val), nil - case string: - return strconv.Atoi(val) - default: - err := fmt.Errorf("redis: unexpected type=%T for Int", val) - return 0, err - } -} - -func (cmd *Cmd) Int64() (int64, error) { - if cmd.err != nil { - return 0, cmd.err - } - return toInt64(cmd.val) -} - -func toInt64(val interface{}) (int64, error) { - switch val := val.(type) { - case int64: - return val, nil - case string: - return strconv.ParseInt(val, 10, 64) - default: - err := fmt.Errorf("redis: unexpected type=%T for Int64", val) - return 0, err - } -} - -func (cmd *Cmd) Uint64() (uint64, error) { - if cmd.err != nil { - return 0, cmd.err - } - return toUint64(cmd.val) -} - -func toUint64(val interface{}) (uint64, error) { - switch val := val.(type) { - case int64: - return uint64(val), nil - case string: - return strconv.ParseUint(val, 10, 64) - default: - err := fmt.Errorf("redis: unexpected type=%T for Uint64", val) - return 0, err - } -} - -func (cmd *Cmd) Float32() (float32, error) { - if cmd.err != nil { - return 0, cmd.err - } - return toFloat32(cmd.val) -} - -func toFloat32(val interface{}) (float32, error) { - switch val := val.(type) { - case int64: - return float32(val), nil - case string: - f, err := strconv.ParseFloat(val, 32) - if err != nil { - return 0, err - } - return float32(f), nil - default: - err := fmt.Errorf("redis: unexpected type=%T for Float32", val) - return 0, err - } -} - -func (cmd *Cmd) Float64() (float64, error) { - if cmd.err != nil { - return 0, cmd.err - } - return toFloat64(cmd.val) -} - -func toFloat64(val interface{}) (float64, error) { - switch val := val.(type) { - case int64: - return float64(val), nil - case string: - return strconv.ParseFloat(val, 64) - default: - err := fmt.Errorf("redis: unexpected type=%T for Float64", val) - return 0, err - } -} - -func (cmd *Cmd) Bool() (bool, error) { - if cmd.err != nil { - return false, cmd.err - } - return toBool(cmd.val) -} - -func toBool(val interface{}) (bool, error) { - switch val := val.(type) { - case int64: - return val != 0, nil - case string: - return strconv.ParseBool(val) - default: - err := fmt.Errorf("redis: unexpected type=%T for Bool", val) - return false, err - } -} - -func (cmd *Cmd) Slice() ([]interface{}, error) { - if cmd.err != nil { - return nil, cmd.err - } - switch val := cmd.val.(type) { - case []interface{}: - return val, nil - default: - return nil, fmt.Errorf("redis: unexpected type=%T for Slice", val) - } -} - -func (cmd *Cmd) StringSlice() ([]string, error) { - slice, err := cmd.Slice() - if err != nil { - return nil, err - } - - ss := make([]string, len(slice)) - for i, iface := range slice { - val, err := toString(iface) - if err != nil { - return nil, err - } - ss[i] = val - } - return ss, nil -} - -func (cmd *Cmd) Int64Slice() ([]int64, error) { - slice, err := cmd.Slice() - if err != nil { - return nil, err - } - - nums := make([]int64, len(slice)) - for i, iface := range slice { - val, err := toInt64(iface) - if err != nil { - return nil, err - } - nums[i] = val - } - return nums, nil -} - -func (cmd *Cmd) Uint64Slice() ([]uint64, error) { - slice, err := cmd.Slice() - if err != nil { - return nil, err - } - - nums := make([]uint64, len(slice)) - for i, iface := range slice { - val, err := toUint64(iface) - if err != nil { - return nil, err - } - nums[i] = val - } - return nums, nil -} - -func (cmd *Cmd) Float32Slice() ([]float32, error) { - slice, err := cmd.Slice() - if err != nil { - return nil, err - } - - floats := make([]float32, len(slice)) - for i, iface := range slice { - val, err := toFloat32(iface) - if err != nil { - return nil, err - } - floats[i] = val - } - return floats, nil -} - -func (cmd *Cmd) Float64Slice() ([]float64, error) { - slice, err := cmd.Slice() - if err != nil { - return nil, err - } - - floats := make([]float64, len(slice)) - for i, iface := range slice { - val, err := toFloat64(iface) - if err != nil { - return nil, err - } - floats[i] = val - } - return floats, nil -} - -func (cmd *Cmd) BoolSlice() ([]bool, error) { - slice, err := cmd.Slice() - if err != nil { - return nil, err - } - - bools := make([]bool, len(slice)) - for i, iface := range slice { - val, err := toBool(iface) - if err != nil { - return nil, err - } - bools[i] = val - } - return bools, nil -} - -func (cmd *Cmd) readReply(rd *proto.Reader) (err error) { - cmd.val, err = rd.ReadReply() - return err -} - -//------------------------------------------------------------------------------ - -type SliceCmd struct { - baseCmd - - val []interface{} -} - -var _ Cmder = (*SliceCmd)(nil) - -func NewSliceCmd(ctx context.Context, args ...interface{}) *SliceCmd { - return &SliceCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *SliceCmd) SetVal(val []interface{}) { - cmd.val = val -} - -func (cmd *SliceCmd) Val() []interface{} { - return cmd.val -} - -func (cmd *SliceCmd) Result() ([]interface{}, error) { - return cmd.val, cmd.err -} - -func (cmd *SliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -// Scan scans the results from the map into a destination struct. The map keys -// are matched in the Redis struct fields by the `redis:"field"` tag. -func (cmd *SliceCmd) Scan(dst interface{}) error { - if cmd.err != nil { - return cmd.err - } - - // Pass the list of keys and values. - // Skip the first two args for: HMGET key - var args []interface{} - if cmd.args[0] == "hmget" { - args = cmd.args[2:] - } else { - // Otherwise, it's: MGET field field ... - args = cmd.args[1:] - } - - return hscan.Scan(dst, args, cmd.val) -} - -func (cmd *SliceCmd) readReply(rd *proto.Reader) (err error) { - cmd.val, err = rd.ReadSlice() - return err -} - -//------------------------------------------------------------------------------ - -type StatusCmd struct { - baseCmd - - val string -} - -var _ Cmder = (*StatusCmd)(nil) - -func NewStatusCmd(ctx context.Context, args ...interface{}) *StatusCmd { - return &StatusCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *StatusCmd) SetVal(val string) { - cmd.val = val -} - -func (cmd *StatusCmd) Val() string { - return cmd.val -} - -func (cmd *StatusCmd) Result() (string, error) { - return cmd.val, cmd.err -} - -func (cmd *StatusCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *StatusCmd) readReply(rd *proto.Reader) (err error) { - cmd.val, err = rd.ReadString() - return err -} - -//------------------------------------------------------------------------------ - -type IntCmd struct { - baseCmd - - val int64 -} - -var _ Cmder = (*IntCmd)(nil) - -func NewIntCmd(ctx context.Context, args ...interface{}) *IntCmd { - return &IntCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *IntCmd) SetVal(val int64) { - cmd.val = val -} - -func (cmd *IntCmd) Val() int64 { - return cmd.val -} - -func (cmd *IntCmd) Result() (int64, error) { - return cmd.val, cmd.err -} - -func (cmd *IntCmd) Uint64() (uint64, error) { - return uint64(cmd.val), cmd.err -} - -func (cmd *IntCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *IntCmd) readReply(rd *proto.Reader) (err error) { - cmd.val, err = rd.ReadInt() - return err -} - -//------------------------------------------------------------------------------ - -type IntSliceCmd struct { - baseCmd - - val []int64 -} - -var _ Cmder = (*IntSliceCmd)(nil) - -func NewIntSliceCmd(ctx context.Context, args ...interface{}) *IntSliceCmd { - return &IntSliceCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *IntSliceCmd) SetVal(val []int64) { - cmd.val = val -} - -func (cmd *IntSliceCmd) Val() []int64 { - return cmd.val -} - -func (cmd *IntSliceCmd) Result() ([]int64, error) { - return cmd.val, cmd.err -} - -func (cmd *IntSliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *IntSliceCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmd.val = make([]int64, n) - for i := 0; i < len(cmd.val); i++ { - if cmd.val[i], err = rd.ReadInt(); err != nil { - return err - } - } - return nil -} - -//------------------------------------------------------------------------------ - -type DurationCmd struct { - baseCmd - - val time.Duration - precision time.Duration -} - -var _ Cmder = (*DurationCmd)(nil) - -func NewDurationCmd(ctx context.Context, precision time.Duration, args ...interface{}) *DurationCmd { - return &DurationCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - precision: precision, - } -} - -func (cmd *DurationCmd) SetVal(val time.Duration) { - cmd.val = val -} - -func (cmd *DurationCmd) Val() time.Duration { - return cmd.val -} - -func (cmd *DurationCmd) Result() (time.Duration, error) { - return cmd.val, cmd.err -} - -func (cmd *DurationCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *DurationCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadInt() - if err != nil { - return err - } - switch n { - // -2 if the key does not exist - // -1 if the key exists but has no associated expire - case -2, -1: - cmd.val = time.Duration(n) - default: - cmd.val = time.Duration(n) * cmd.precision - } - return nil -} - -//------------------------------------------------------------------------------ - -type TimeCmd struct { - baseCmd - - val time.Time -} - -var _ Cmder = (*TimeCmd)(nil) - -func NewTimeCmd(ctx context.Context, args ...interface{}) *TimeCmd { - return &TimeCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *TimeCmd) SetVal(val time.Time) { - cmd.val = val -} - -func (cmd *TimeCmd) Val() time.Time { - return cmd.val -} - -func (cmd *TimeCmd) Result() (time.Time, error) { - return cmd.val, cmd.err -} - -func (cmd *TimeCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *TimeCmd) readReply(rd *proto.Reader) error { - if err := rd.ReadFixedArrayLen(2); err != nil { - return err - } - second, err := rd.ReadInt() - if err != nil { - return err - } - microsecond, err := rd.ReadInt() - if err != nil { - return err - } - cmd.val = time.Unix(second, microsecond*1000) - return nil -} - -//------------------------------------------------------------------------------ - -type BoolCmd struct { - baseCmd - - val bool -} - -var _ Cmder = (*BoolCmd)(nil) - -func NewBoolCmd(ctx context.Context, args ...interface{}) *BoolCmd { - return &BoolCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *BoolCmd) SetVal(val bool) { - cmd.val = val -} - -func (cmd *BoolCmd) Val() bool { - return cmd.val -} - -func (cmd *BoolCmd) Result() (bool, error) { - return cmd.val, cmd.err -} - -func (cmd *BoolCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *BoolCmd) readReply(rd *proto.Reader) (err error) { - cmd.val, err = rd.ReadBool() - - // `SET key value NX` returns nil when key already exists. But - // `SETNX key value` returns bool (0/1). So convert nil to bool. - if err == Nil { - cmd.val = false - err = nil - } - return err -} - -//------------------------------------------------------------------------------ - -type StringCmd struct { - baseCmd - - val string -} - -var _ Cmder = (*StringCmd)(nil) - -func NewStringCmd(ctx context.Context, args ...interface{}) *StringCmd { - return &StringCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *StringCmd) SetVal(val string) { - cmd.val = val -} - -func (cmd *StringCmd) Val() string { - return cmd.val -} - -func (cmd *StringCmd) Result() (string, error) { - return cmd.Val(), cmd.err -} - -func (cmd *StringCmd) Bytes() ([]byte, error) { - return util.StringToBytes(cmd.val), cmd.err -} - -func (cmd *StringCmd) Bool() (bool, error) { - if cmd.err != nil { - return false, cmd.err - } - return strconv.ParseBool(cmd.val) -} - -func (cmd *StringCmd) Int() (int, error) { - if cmd.err != nil { - return 0, cmd.err - } - return strconv.Atoi(cmd.Val()) -} - -func (cmd *StringCmd) Int64() (int64, error) { - if cmd.err != nil { - return 0, cmd.err - } - return strconv.ParseInt(cmd.Val(), 10, 64) -} - -func (cmd *StringCmd) Uint64() (uint64, error) { - if cmd.err != nil { - return 0, cmd.err - } - return strconv.ParseUint(cmd.Val(), 10, 64) -} - -func (cmd *StringCmd) Float32() (float32, error) { - if cmd.err != nil { - return 0, cmd.err - } - f, err := strconv.ParseFloat(cmd.Val(), 32) - if err != nil { - return 0, err - } - return float32(f), nil -} - -func (cmd *StringCmd) Float64() (float64, error) { - if cmd.err != nil { - return 0, cmd.err - } - return strconv.ParseFloat(cmd.Val(), 64) -} - -func (cmd *StringCmd) Time() (time.Time, error) { - if cmd.err != nil { - return time.Time{}, cmd.err - } - return time.Parse(time.RFC3339Nano, cmd.Val()) -} - -func (cmd *StringCmd) Scan(val interface{}) error { - if cmd.err != nil { - return cmd.err - } - return proto.Scan([]byte(cmd.val), val) -} - -func (cmd *StringCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *StringCmd) readReply(rd *proto.Reader) (err error) { - cmd.val, err = rd.ReadString() - return err -} - -//------------------------------------------------------------------------------ - -type FloatCmd struct { - baseCmd - - val float64 -} - -var _ Cmder = (*FloatCmd)(nil) - -func NewFloatCmd(ctx context.Context, args ...interface{}) *FloatCmd { - return &FloatCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *FloatCmd) SetVal(val float64) { - cmd.val = val -} - -func (cmd *FloatCmd) Val() float64 { - return cmd.val -} - -func (cmd *FloatCmd) Result() (float64, error) { - return cmd.Val(), cmd.Err() -} - -func (cmd *FloatCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *FloatCmd) readReply(rd *proto.Reader) (err error) { - cmd.val, err = rd.ReadFloat() - return err -} - -//------------------------------------------------------------------------------ - -type FloatSliceCmd struct { - baseCmd - - val []float64 -} - -var _ Cmder = (*FloatSliceCmd)(nil) - -func NewFloatSliceCmd(ctx context.Context, args ...interface{}) *FloatSliceCmd { - return &FloatSliceCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *FloatSliceCmd) SetVal(val []float64) { - cmd.val = val -} - -func (cmd *FloatSliceCmd) Val() []float64 { - return cmd.val -} - -func (cmd *FloatSliceCmd) Result() ([]float64, error) { - return cmd.val, cmd.err -} - -func (cmd *FloatSliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *FloatSliceCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - - cmd.val = make([]float64, n) - for i := 0; i < len(cmd.val); i++ { - switch num, err := rd.ReadFloat(); { - case err == Nil: - cmd.val[i] = 0 - case err != nil: - return err - default: - cmd.val[i] = num - } - } - return nil -} - -//------------------------------------------------------------------------------ - -type StringSliceCmd struct { - baseCmd - - val []string -} - -var _ Cmder = (*StringSliceCmd)(nil) - -func NewStringSliceCmd(ctx context.Context, args ...interface{}) *StringSliceCmd { - return &StringSliceCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *StringSliceCmd) SetVal(val []string) { - cmd.val = val -} - -func (cmd *StringSliceCmd) Val() []string { - return cmd.val -} - -func (cmd *StringSliceCmd) Result() ([]string, error) { - return cmd.Val(), cmd.Err() -} - -func (cmd *StringSliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *StringSliceCmd) ScanSlice(container interface{}) error { - return proto.ScanSlice(cmd.Val(), container) -} - -func (cmd *StringSliceCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmd.val = make([]string, n) - for i := 0; i < len(cmd.val); i++ { - switch s, err := rd.ReadString(); { - case err == Nil: - cmd.val[i] = "" - case err != nil: - return err - default: - cmd.val[i] = s - } - } - return nil -} - -//------------------------------------------------------------------------------ - -type KeyValue struct { - Key string - Value string -} - -type KeyValueSliceCmd struct { - baseCmd - - val []KeyValue -} - -var _ Cmder = (*KeyValueSliceCmd)(nil) - -func NewKeyValueSliceCmd(ctx context.Context, args ...interface{}) *KeyValueSliceCmd { - return &KeyValueSliceCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *KeyValueSliceCmd) Val() []KeyValue { - return cmd.val -} - -func (cmd *KeyValueSliceCmd) Result() ([]KeyValue, error) { - return cmd.val, cmd.err -} - -func (cmd *KeyValueSliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -// Many commands will respond to two formats: -// 1) 1) "one" -// 2) (double) 1 -// 2) 1) "two" -// 2) (double) 2 -// OR: -// 1) "two" -// 2) (double) 2 -// 3) "one" -// 4) (double) 1 -func (cmd *KeyValueSliceCmd) readReply(rd *proto.Reader) error { // nolint:dupl - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - - // If the n is 0, can't continue reading. - if n == 0 { - cmd.val = make([]KeyValue, 0) - return nil - } - - typ, err := rd.PeekReplyType() - if err != nil { - return err - } - array := typ == proto.RespArray - - if array { - cmd.val = make([]KeyValue, n) - } else { - cmd.val = make([]KeyValue, n/2) - } - - for i := 0; i < len(cmd.val); i++ { - if array { - if err = rd.ReadFixedArrayLen(2); err != nil { - return err - } - } - - if cmd.val[i].Key, err = rd.ReadString(); err != nil { - return err - } - - if cmd.val[i].Value, err = rd.ReadString(); err != nil { - return err - } - } - - return nil -} - -//------------------------------------------------------------------------------ - -type BoolSliceCmd struct { - baseCmd - - val []bool -} - -var _ Cmder = (*BoolSliceCmd)(nil) - -func NewBoolSliceCmd(ctx context.Context, args ...interface{}) *BoolSliceCmd { - return &BoolSliceCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *BoolSliceCmd) SetVal(val []bool) { - cmd.val = val -} - -func (cmd *BoolSliceCmd) Val() []bool { - return cmd.val -} - -func (cmd *BoolSliceCmd) Result() ([]bool, error) { - return cmd.val, cmd.err -} - -func (cmd *BoolSliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *BoolSliceCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmd.val = make([]bool, n) - for i := 0; i < len(cmd.val); i++ { - if cmd.val[i], err = rd.ReadBool(); err != nil { - return err - } - } - return nil -} - -//------------------------------------------------------------------------------ - -type MapStringStringCmd struct { - baseCmd - - val map[string]string -} - -var _ Cmder = (*MapStringStringCmd)(nil) - -func NewMapStringStringCmd(ctx context.Context, args ...interface{}) *MapStringStringCmd { - return &MapStringStringCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *MapStringStringCmd) Val() map[string]string { - return cmd.val -} - -func (cmd *MapStringStringCmd) SetVal(val map[string]string) { - cmd.val = val -} - -func (cmd *MapStringStringCmd) Result() (map[string]string, error) { - return cmd.val, cmd.err -} - -func (cmd *MapStringStringCmd) String() string { - return cmdString(cmd, cmd.val) -} - -// Scan scans the results from the map into a destination struct. The map keys -// are matched in the Redis struct fields by the `redis:"field"` tag. -func (cmd *MapStringStringCmd) Scan(dest interface{}) error { - if cmd.err != nil { - return cmd.err - } - - strct, err := hscan.Struct(dest) - if err != nil { - return err - } - - for k, v := range cmd.val { - if err := strct.Scan(k, v); err != nil { - return err - } - } - - return nil -} - -func (cmd *MapStringStringCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadMapLen() - if err != nil { - return err - } - - cmd.val = make(map[string]string, n) - for i := 0; i < n; i++ { - key, err := rd.ReadString() - if err != nil { - return err - } - - value, err := rd.ReadString() - if err != nil { - return err - } - - cmd.val[key] = value - } - return nil -} - -//------------------------------------------------------------------------------ - -type StringIntMapCmd struct { - baseCmd - - val map[string]int64 -} - -var _ Cmder = (*StringIntMapCmd)(nil) - -func NewStringIntMapCmd(ctx context.Context, args ...interface{}) *StringIntMapCmd { - return &StringIntMapCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *StringIntMapCmd) SetVal(val map[string]int64) { - cmd.val = val -} - -func (cmd *StringIntMapCmd) Val() map[string]int64 { - return cmd.val -} - -func (cmd *StringIntMapCmd) Result() (map[string]int64, error) { - return cmd.val, cmd.err -} - -func (cmd *StringIntMapCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *StringIntMapCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadMapLen() - if err != nil { - return err - } - - cmd.val = make(map[string]int64, n) - for i := 0; i < n; i++ { - key, err := rd.ReadString() - if err != nil { - return err - } - - nn, err := rd.ReadInt() - if err != nil { - return err - } - cmd.val[key] = nn - } - return nil -} - -//------------------------------------------------------------------------------ - -type StringStructMapCmd struct { - baseCmd - - val map[string]struct{} -} - -var _ Cmder = (*StringStructMapCmd)(nil) - -func NewStringStructMapCmd(ctx context.Context, args ...interface{}) *StringStructMapCmd { - return &StringStructMapCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *StringStructMapCmd) SetVal(val map[string]struct{}) { - cmd.val = val -} - -func (cmd *StringStructMapCmd) Val() map[string]struct{} { - return cmd.val -} - -func (cmd *StringStructMapCmd) Result() (map[string]struct{}, error) { - return cmd.val, cmd.err -} - -func (cmd *StringStructMapCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *StringStructMapCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - - cmd.val = make(map[string]struct{}, n) - for i := 0; i < n; i++ { - key, err := rd.ReadString() - if err != nil { - return err - } - cmd.val[key] = struct{}{} - } - return nil -} - -//------------------------------------------------------------------------------ - -type XMessage struct { - ID string - Values map[string]interface{} -} - -type XMessageSliceCmd struct { - baseCmd - - val []XMessage -} - -var _ Cmder = (*XMessageSliceCmd)(nil) - -func NewXMessageSliceCmd(ctx context.Context, args ...interface{}) *XMessageSliceCmd { - return &XMessageSliceCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *XMessageSliceCmd) SetVal(val []XMessage) { - cmd.val = val -} - -func (cmd *XMessageSliceCmd) Val() []XMessage { - return cmd.val -} - -func (cmd *XMessageSliceCmd) Result() ([]XMessage, error) { - return cmd.val, cmd.err -} - -func (cmd *XMessageSliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *XMessageSliceCmd) readReply(rd *proto.Reader) (err error) { - cmd.val, err = readXMessageSlice(rd) - return err -} - -func readXMessageSlice(rd *proto.Reader) ([]XMessage, error) { - n, err := rd.ReadArrayLen() - if err != nil { - return nil, err - } - - msgs := make([]XMessage, n) - for i := 0; i < len(msgs); i++ { - if msgs[i], err = readXMessage(rd); err != nil { - return nil, err - } - } - return msgs, nil -} - -func readXMessage(rd *proto.Reader) (XMessage, error) { - if err := rd.ReadFixedArrayLen(2); err != nil { - return XMessage{}, err - } - - id, err := rd.ReadString() - if err != nil { - return XMessage{}, err - } - - v, err := stringInterfaceMapParser(rd) - if err != nil { - if err != proto.Nil { - return XMessage{}, err - } - } - - return XMessage{ - ID: id, - Values: v, - }, nil -} - -func stringInterfaceMapParser(rd *proto.Reader) (map[string]interface{}, error) { - n, err := rd.ReadMapLen() - if err != nil { - return nil, err - } - - m := make(map[string]interface{}, n) - for i := 0; i < n; i++ { - key, err := rd.ReadString() - if err != nil { - return nil, err - } - - value, err := rd.ReadString() - if err != nil { - return nil, err - } - - m[key] = value - } - return m, nil -} - -//------------------------------------------------------------------------------ - -type XStream struct { - Stream string - Messages []XMessage -} - -type XStreamSliceCmd struct { - baseCmd - - val []XStream -} - -var _ Cmder = (*XStreamSliceCmd)(nil) - -func NewXStreamSliceCmd(ctx context.Context, args ...interface{}) *XStreamSliceCmd { - return &XStreamSliceCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *XStreamSliceCmd) SetVal(val []XStream) { - cmd.val = val -} - -func (cmd *XStreamSliceCmd) Val() []XStream { - return cmd.val -} - -func (cmd *XStreamSliceCmd) Result() ([]XStream, error) { - return cmd.val, cmd.err -} - -func (cmd *XStreamSliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *XStreamSliceCmd) readReply(rd *proto.Reader) error { - typ, err := rd.PeekReplyType() - if err != nil { - return err - } - - var n int - if typ == proto.RespMap { - n, err = rd.ReadMapLen() - } else { - n, err = rd.ReadArrayLen() - } - if err != nil { - return err - } - cmd.val = make([]XStream, n) - for i := 0; i < len(cmd.val); i++ { - if typ != proto.RespMap { - if err = rd.ReadFixedArrayLen(2); err != nil { - return err - } - } - if cmd.val[i].Stream, err = rd.ReadString(); err != nil { - return err - } - if cmd.val[i].Messages, err = readXMessageSlice(rd); err != nil { - return err - } - } - return nil -} - -//------------------------------------------------------------------------------ - -type XPending struct { - Count int64 - Lower string - Higher string - Consumers map[string]int64 -} - -type XPendingCmd struct { - baseCmd - val *XPending -} - -var _ Cmder = (*XPendingCmd)(nil) - -func NewXPendingCmd(ctx context.Context, args ...interface{}) *XPendingCmd { - return &XPendingCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *XPendingCmd) SetVal(val *XPending) { - cmd.val = val -} - -func (cmd *XPendingCmd) Val() *XPending { - return cmd.val -} - -func (cmd *XPendingCmd) Result() (*XPending, error) { - return cmd.val, cmd.err -} - -func (cmd *XPendingCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *XPendingCmd) readReply(rd *proto.Reader) error { - var err error - if err = rd.ReadFixedArrayLen(4); err != nil { - return err - } - cmd.val = &XPending{} - - if cmd.val.Count, err = rd.ReadInt(); err != nil { - return err - } - - if cmd.val.Lower, err = rd.ReadString(); err != nil && err != Nil { - return err - } - - if cmd.val.Higher, err = rd.ReadString(); err != nil && err != Nil { - return err - } - - n, err := rd.ReadArrayLen() - if err != nil && err != Nil { - return err - } - cmd.val.Consumers = make(map[string]int64, n) - for i := 0; i < n; i++ { - if err = rd.ReadFixedArrayLen(2); err != nil { - return err - } - - consumerName, err := rd.ReadString() - if err != nil { - return err - } - consumerPending, err := rd.ReadInt() - if err != nil { - return err - } - cmd.val.Consumers[consumerName] = consumerPending - } - return nil -} - -//------------------------------------------------------------------------------ - -type XPendingExt struct { - ID string - Consumer string - Idle time.Duration - RetryCount int64 -} - -type XPendingExtCmd struct { - baseCmd - val []XPendingExt -} - -var _ Cmder = (*XPendingExtCmd)(nil) - -func NewXPendingExtCmd(ctx context.Context, args ...interface{}) *XPendingExtCmd { - return &XPendingExtCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *XPendingExtCmd) SetVal(val []XPendingExt) { - cmd.val = val -} - -func (cmd *XPendingExtCmd) Val() []XPendingExt { - return cmd.val -} - -func (cmd *XPendingExtCmd) Result() ([]XPendingExt, error) { - return cmd.val, cmd.err -} - -func (cmd *XPendingExtCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *XPendingExtCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmd.val = make([]XPendingExt, n) - - for i := 0; i < len(cmd.val); i++ { - if err = rd.ReadFixedArrayLen(4); err != nil { - return err - } - - if cmd.val[i].ID, err = rd.ReadString(); err != nil { - return err - } - - if cmd.val[i].Consumer, err = rd.ReadString(); err != nil && err != Nil { - return err - } - - idle, err := rd.ReadInt() - if err != nil && err != Nil { - return err - } - cmd.val[i].Idle = time.Duration(idle) * time.Millisecond - - if cmd.val[i].RetryCount, err = rd.ReadInt(); err != nil && err != Nil { - return err - } - } - - return nil -} - -//------------------------------------------------------------------------------ - -type XAutoClaimCmd struct { - baseCmd - - start string - val []XMessage -} - -var _ Cmder = (*XAutoClaimCmd)(nil) - -func NewXAutoClaimCmd(ctx context.Context, args ...interface{}) *XAutoClaimCmd { - return &XAutoClaimCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *XAutoClaimCmd) SetVal(val []XMessage, start string) { - cmd.val = val - cmd.start = start -} - -func (cmd *XAutoClaimCmd) Val() (messages []XMessage, start string) { - return cmd.val, cmd.start -} - -func (cmd *XAutoClaimCmd) Result() (messages []XMessage, start string, err error) { - return cmd.val, cmd.start, cmd.err -} - -func (cmd *XAutoClaimCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *XAutoClaimCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - - switch n { - case 2, // Redis 6 - 3: // Redis 7: - // ok - default: - return fmt.Errorf("redis: got %d elements in XAutoClaim reply, wanted 2/3", n) - } - - cmd.start, err = rd.ReadString() - if err != nil { - return err - } - - cmd.val, err = readXMessageSlice(rd) - if err != nil { - return err - } - - if n >= 3 { - if err := rd.DiscardNext(); err != nil { - return err - } - } - - return nil -} - -//------------------------------------------------------------------------------ - -type XAutoClaimJustIDCmd struct { - baseCmd - - start string - val []string -} - -var _ Cmder = (*XAutoClaimJustIDCmd)(nil) - -func NewXAutoClaimJustIDCmd(ctx context.Context, args ...interface{}) *XAutoClaimJustIDCmd { - return &XAutoClaimJustIDCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *XAutoClaimJustIDCmd) SetVal(val []string, start string) { - cmd.val = val - cmd.start = start -} - -func (cmd *XAutoClaimJustIDCmd) Val() (ids []string, start string) { - return cmd.val, cmd.start -} - -func (cmd *XAutoClaimJustIDCmd) Result() (ids []string, start string, err error) { - return cmd.val, cmd.start, cmd.err -} - -func (cmd *XAutoClaimJustIDCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *XAutoClaimJustIDCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - - switch n { - case 2, // Redis 6 - 3: // Redis 7: - // ok - default: - return fmt.Errorf("redis: got %d elements in XAutoClaimJustID reply, wanted 2/3", n) - } - - cmd.start, err = rd.ReadString() - if err != nil { - return err - } - - nn, err := rd.ReadArrayLen() - if err != nil { - return err - } - - cmd.val = make([]string, nn) - for i := 0; i < nn; i++ { - cmd.val[i], err = rd.ReadString() - if err != nil { - return err - } - } - - if n >= 3 { - if err := rd.DiscardNext(); err != nil { - return err - } - } - - return nil -} - -//------------------------------------------------------------------------------ - -type XInfoConsumersCmd struct { - baseCmd - val []XInfoConsumer -} - -type XInfoConsumer struct { - Name string - Pending int64 - Idle time.Duration -} - -var _ Cmder = (*XInfoConsumersCmd)(nil) - -func NewXInfoConsumersCmd(ctx context.Context, stream string, group string) *XInfoConsumersCmd { - return &XInfoConsumersCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: []interface{}{"xinfo", "consumers", stream, group}, - }, - } -} - -func (cmd *XInfoConsumersCmd) SetVal(val []XInfoConsumer) { - cmd.val = val -} - -func (cmd *XInfoConsumersCmd) Val() []XInfoConsumer { - return cmd.val -} - -func (cmd *XInfoConsumersCmd) Result() ([]XInfoConsumer, error) { - return cmd.val, cmd.err -} - -func (cmd *XInfoConsumersCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *XInfoConsumersCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmd.val = make([]XInfoConsumer, n) - - for i := 0; i < len(cmd.val); i++ { - if err = rd.ReadFixedMapLen(3); err != nil { - return err - } - - var key string - for f := 0; f < 3; f++ { - key, err = rd.ReadString() - if err != nil { - return err - } - - switch key { - case "name": - cmd.val[i].Name, err = rd.ReadString() - case "pending": - cmd.val[i].Pending, err = rd.ReadInt() - case "idle": - var idle int64 - idle, err = rd.ReadInt() - cmd.val[i].Idle = time.Duration(idle) * time.Millisecond - default: - return fmt.Errorf("redis: unexpected content %s in XINFO CONSUMERS reply", key) - } - if err != nil { - return err - } - } - } - - return nil -} - -//------------------------------------------------------------------------------ - -type XInfoGroupsCmd struct { - baseCmd - val []XInfoGroup -} - -type XInfoGroup struct { - Name string - Consumers int64 - Pending int64 - LastDeliveredID string - EntriesRead int64 - Lag int64 -} - -var _ Cmder = (*XInfoGroupsCmd)(nil) - -func NewXInfoGroupsCmd(ctx context.Context, stream string) *XInfoGroupsCmd { - return &XInfoGroupsCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: []interface{}{"xinfo", "groups", stream}, - }, - } -} - -func (cmd *XInfoGroupsCmd) SetVal(val []XInfoGroup) { - cmd.val = val -} - -func (cmd *XInfoGroupsCmd) Val() []XInfoGroup { - return cmd.val -} - -func (cmd *XInfoGroupsCmd) Result() ([]XInfoGroup, error) { - return cmd.val, cmd.err -} - -func (cmd *XInfoGroupsCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *XInfoGroupsCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmd.val = make([]XInfoGroup, n) - - for i := 0; i < len(cmd.val); i++ { - group := &cmd.val[i] - - nn, err := rd.ReadMapLen() - if err != nil { - return err - } - - var key string - for j := 0; j < nn; j++ { - key, err = rd.ReadString() - if err != nil { - return err - } - - switch key { - case "name": - group.Name, err = rd.ReadString() - if err != nil { - return err - } - case "consumers": - group.Consumers, err = rd.ReadInt() - if err != nil { - return err - } - case "pending": - group.Pending, err = rd.ReadInt() - if err != nil { - return err - } - case "last-delivered-id": - group.LastDeliveredID, err = rd.ReadString() - if err != nil { - return err - } - case "entries-read": - group.EntriesRead, err = rd.ReadInt() - if err != nil && err != Nil { - return err - } - case "lag": - group.Lag, err = rd.ReadInt() - if err != nil { - return err - } - default: - return fmt.Errorf("redis: unexpected key %q in XINFO GROUPS reply", key) - } - } - } - - return nil -} - -//------------------------------------------------------------------------------ - -type XInfoStreamCmd struct { - baseCmd - val *XInfoStream -} - -type XInfoStream struct { - Length int64 - RadixTreeKeys int64 - RadixTreeNodes int64 - Groups int64 - LastGeneratedID string - MaxDeletedEntryID string - EntriesAdded int64 - FirstEntry XMessage - LastEntry XMessage - RecordedFirstEntryID string -} - -var _ Cmder = (*XInfoStreamCmd)(nil) - -func NewXInfoStreamCmd(ctx context.Context, stream string) *XInfoStreamCmd { - return &XInfoStreamCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: []interface{}{"xinfo", "stream", stream}, - }, - } -} - -func (cmd *XInfoStreamCmd) SetVal(val *XInfoStream) { - cmd.val = val -} - -func (cmd *XInfoStreamCmd) Val() *XInfoStream { - return cmd.val -} - -func (cmd *XInfoStreamCmd) Result() (*XInfoStream, error) { - return cmd.val, cmd.err -} - -func (cmd *XInfoStreamCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *XInfoStreamCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadMapLen() - if err != nil { - return err - } - cmd.val = &XInfoStream{} - - for i := 0; i < n; i++ { - key, err := rd.ReadString() - if err != nil { - return err - } - switch key { - case "length": - cmd.val.Length, err = rd.ReadInt() - if err != nil { - return err - } - case "radix-tree-keys": - cmd.val.RadixTreeKeys, err = rd.ReadInt() - if err != nil { - return err - } - case "radix-tree-nodes": - cmd.val.RadixTreeNodes, err = rd.ReadInt() - if err != nil { - return err - } - case "groups": - cmd.val.Groups, err = rd.ReadInt() - if err != nil { - return err - } - case "last-generated-id": - cmd.val.LastGeneratedID, err = rd.ReadString() - if err != nil { - return err - } - case "max-deleted-entry-id": - cmd.val.MaxDeletedEntryID, err = rd.ReadString() - if err != nil { - return err - } - case "entries-added": - cmd.val.EntriesAdded, err = rd.ReadInt() - if err != nil { - return err - } - case "first-entry": - cmd.val.FirstEntry, err = readXMessage(rd) - if err != nil && err != Nil { - return err - } - case "last-entry": - cmd.val.LastEntry, err = readXMessage(rd) - if err != nil && err != Nil { - return err - } - case "recorded-first-entry-id": - cmd.val.RecordedFirstEntryID, err = rd.ReadString() - if err != nil { - return err - } - default: - return fmt.Errorf("redis: unexpected key %q in XINFO STREAM reply", key) - } - } - return nil -} - -//------------------------------------------------------------------------------ - -type XInfoStreamFullCmd struct { - baseCmd - val *XInfoStreamFull -} - -type XInfoStreamFull struct { - Length int64 - RadixTreeKeys int64 - RadixTreeNodes int64 - LastGeneratedID string - MaxDeletedEntryID string - EntriesAdded int64 - Entries []XMessage - Groups []XInfoStreamGroup - RecordedFirstEntryID string -} - -type XInfoStreamGroup struct { - Name string - LastDeliveredID string - EntriesRead int64 - Lag int64 - PelCount int64 - Pending []XInfoStreamGroupPending - Consumers []XInfoStreamConsumer -} - -type XInfoStreamGroupPending struct { - ID string - Consumer string - DeliveryTime time.Time - DeliveryCount int64 -} - -type XInfoStreamConsumer struct { - Name string - SeenTime time.Time - PelCount int64 - Pending []XInfoStreamConsumerPending -} - -type XInfoStreamConsumerPending struct { - ID string - DeliveryTime time.Time - DeliveryCount int64 -} - -var _ Cmder = (*XInfoStreamFullCmd)(nil) - -func NewXInfoStreamFullCmd(ctx context.Context, args ...interface{}) *XInfoStreamFullCmd { - return &XInfoStreamFullCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *XInfoStreamFullCmd) SetVal(val *XInfoStreamFull) { - cmd.val = val -} - -func (cmd *XInfoStreamFullCmd) Val() *XInfoStreamFull { - return cmd.val -} - -func (cmd *XInfoStreamFullCmd) Result() (*XInfoStreamFull, error) { - return cmd.val, cmd.err -} - -func (cmd *XInfoStreamFullCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *XInfoStreamFullCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadMapLen() - if err != nil { - return err - } - - cmd.val = &XInfoStreamFull{} - - for i := 0; i < n; i++ { - key, err := rd.ReadString() - if err != nil { - return err - } - - switch key { - case "length": - cmd.val.Length, err = rd.ReadInt() - if err != nil { - return err - } - case "radix-tree-keys": - cmd.val.RadixTreeKeys, err = rd.ReadInt() - if err != nil { - return err - } - case "radix-tree-nodes": - cmd.val.RadixTreeNodes, err = rd.ReadInt() - if err != nil { - return err - } - case "last-generated-id": - cmd.val.LastGeneratedID, err = rd.ReadString() - if err != nil { - return err - } - case "entries-added": - cmd.val.EntriesAdded, err = rd.ReadInt() - if err != nil { - return err - } - case "entries": - cmd.val.Entries, err = readXMessageSlice(rd) - if err != nil { - return err - } - case "groups": - cmd.val.Groups, err = readStreamGroups(rd) - if err != nil { - return err - } - case "max-deleted-entry-id": - cmd.val.MaxDeletedEntryID, err = rd.ReadString() - if err != nil { - return err - } - case "recorded-first-entry-id": - cmd.val.RecordedFirstEntryID, err = rd.ReadString() - if err != nil { - return err - } - default: - return fmt.Errorf("redis: unexpected key %q in XINFO STREAM FULL reply", key) - } - } - return nil -} - -func readStreamGroups(rd *proto.Reader) ([]XInfoStreamGroup, error) { - n, err := rd.ReadArrayLen() - if err != nil { - return nil, err - } - groups := make([]XInfoStreamGroup, 0, n) - for i := 0; i < n; i++ { - nn, err := rd.ReadMapLen() - if err != nil { - return nil, err - } - - group := XInfoStreamGroup{} - - for j := 0; j < nn; j++ { - key, err := rd.ReadString() - if err != nil { - return nil, err - } - - switch key { - case "name": - group.Name, err = rd.ReadString() - if err != nil { - return nil, err - } - case "last-delivered-id": - group.LastDeliveredID, err = rd.ReadString() - if err != nil { - return nil, err - } - case "entries-read": - group.EntriesRead, err = rd.ReadInt() - if err != nil { - return nil, err - } - case "lag": - group.Lag, err = rd.ReadInt() - if err != nil { - return nil, err - } - case "pel-count": - group.PelCount, err = rd.ReadInt() - if err != nil { - return nil, err - } - case "pending": - group.Pending, err = readXInfoStreamGroupPending(rd) - if err != nil { - return nil, err - } - case "consumers": - group.Consumers, err = readXInfoStreamConsumers(rd) - if err != nil { - return nil, err - } - default: - return nil, fmt.Errorf("redis: unexpected key %q in XINFO STREAM FULL reply", key) - } - } - - groups = append(groups, group) - } - - return groups, nil -} - -func readXInfoStreamGroupPending(rd *proto.Reader) ([]XInfoStreamGroupPending, error) { - n, err := rd.ReadArrayLen() - if err != nil { - return nil, err - } - - pending := make([]XInfoStreamGroupPending, 0, n) - - for i := 0; i < n; i++ { - if err = rd.ReadFixedArrayLen(4); err != nil { - return nil, err - } - - p := XInfoStreamGroupPending{} - - p.ID, err = rd.ReadString() - if err != nil { - return nil, err - } - - p.Consumer, err = rd.ReadString() - if err != nil { - return nil, err - } - - delivery, err := rd.ReadInt() - if err != nil { - return nil, err - } - p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond)) - - p.DeliveryCount, err = rd.ReadInt() - if err != nil { - return nil, err - } - - pending = append(pending, p) - } - - return pending, nil -} - -func readXInfoStreamConsumers(rd *proto.Reader) ([]XInfoStreamConsumer, error) { - n, err := rd.ReadArrayLen() - if err != nil { - return nil, err - } - - consumers := make([]XInfoStreamConsumer, 0, n) - - for i := 0; i < n; i++ { - if err = rd.ReadFixedMapLen(4); err != nil { - return nil, err - } - - c := XInfoStreamConsumer{} - - for f := 0; f < 4; f++ { - cKey, err := rd.ReadString() - if err != nil { - return nil, err - } - - switch cKey { - case "name": - c.Name, err = rd.ReadString() - case "seen-time": - seen, err := rd.ReadInt() - if err != nil { - return nil, err - } - c.SeenTime = time.Unix(seen/1000, seen%1000*int64(time.Millisecond)) - case "pel-count": - c.PelCount, err = rd.ReadInt() - case "pending": - pendingNumber, err := rd.ReadArrayLen() - if err != nil { - return nil, err - } - - c.Pending = make([]XInfoStreamConsumerPending, 0, pendingNumber) - - for pn := 0; pn < pendingNumber; pn++ { - if err = rd.ReadFixedArrayLen(3); err != nil { - return nil, err - } - - p := XInfoStreamConsumerPending{} - - p.ID, err = rd.ReadString() - if err != nil { - return nil, err - } - - delivery, err := rd.ReadInt() - if err != nil { - return nil, err - } - p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond)) - - p.DeliveryCount, err = rd.ReadInt() - if err != nil { - return nil, err - } - - c.Pending = append(c.Pending, p) - } - default: - return nil, fmt.Errorf("redis: unexpected content %s "+ - "in XINFO STREAM FULL reply", cKey) - } - if err != nil { - return nil, err - } - } - consumers = append(consumers, c) - } - - return consumers, nil -} - -//------------------------------------------------------------------------------ - -type ZSliceCmd struct { - baseCmd - - val []Z -} - -var _ Cmder = (*ZSliceCmd)(nil) - -func NewZSliceCmd(ctx context.Context, args ...interface{}) *ZSliceCmd { - return &ZSliceCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *ZSliceCmd) SetVal(val []Z) { - cmd.val = val -} - -func (cmd *ZSliceCmd) Val() []Z { - return cmd.val -} - -func (cmd *ZSliceCmd) Result() ([]Z, error) { - return cmd.val, cmd.err -} - -func (cmd *ZSliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *ZSliceCmd) readReply(rd *proto.Reader) error { // nolint:dupl - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - - // If the n is 0, can't continue reading. - if n == 0 { - cmd.val = make([]Z, 0) - return nil - } - - typ, err := rd.PeekReplyType() - if err != nil { - return err - } - array := typ == proto.RespArray - - if array { - cmd.val = make([]Z, n) - } else { - cmd.val = make([]Z, n/2) - } - - for i := 0; i < len(cmd.val); i++ { - if array { - if err = rd.ReadFixedArrayLen(2); err != nil { - return err - } - } - - if cmd.val[i].Member, err = rd.ReadString(); err != nil { - return err - } - - if cmd.val[i].Score, err = rd.ReadFloat(); err != nil { - return err - } - } - - return nil -} - -//------------------------------------------------------------------------------ - -type ZWithKeyCmd struct { - baseCmd - - val *ZWithKey -} - -var _ Cmder = (*ZWithKeyCmd)(nil) - -func NewZWithKeyCmd(ctx context.Context, args ...interface{}) *ZWithKeyCmd { - return &ZWithKeyCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *ZWithKeyCmd) SetVal(val *ZWithKey) { - cmd.val = val -} - -func (cmd *ZWithKeyCmd) Val() *ZWithKey { - return cmd.val -} - -func (cmd *ZWithKeyCmd) Result() (*ZWithKey, error) { - return cmd.Val(), cmd.Err() -} - -func (cmd *ZWithKeyCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *ZWithKeyCmd) readReply(rd *proto.Reader) (err error) { - if err = rd.ReadFixedArrayLen(3); err != nil { - return err - } - cmd.val = &ZWithKey{} - - if cmd.val.Key, err = rd.ReadString(); err != nil { - return err - } - if cmd.val.Member, err = rd.ReadString(); err != nil { - return err - } - if cmd.val.Score, err = rd.ReadFloat(); err != nil { - return err - } - - return nil -} - -//------------------------------------------------------------------------------ - -type ScanCmd struct { - baseCmd - - page []string - cursor uint64 - - process cmdable -} - -var _ Cmder = (*ScanCmd)(nil) - -func NewScanCmd(ctx context.Context, process cmdable, args ...interface{}) *ScanCmd { - return &ScanCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - process: process, - } -} - -func (cmd *ScanCmd) SetVal(page []string, cursor uint64) { - cmd.page = page - cmd.cursor = cursor -} - -func (cmd *ScanCmd) Val() (keys []string, cursor uint64) { - return cmd.page, cmd.cursor -} - -func (cmd *ScanCmd) Result() (keys []string, cursor uint64, err error) { - return cmd.page, cmd.cursor, cmd.err -} - -func (cmd *ScanCmd) String() string { - return cmdString(cmd, cmd.page) -} - -func (cmd *ScanCmd) readReply(rd *proto.Reader) error { - if err := rd.ReadFixedArrayLen(2); err != nil { - return err - } - - cursor, err := rd.ReadInt() - if err != nil { - return err - } - cmd.cursor = uint64(cursor) - - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmd.page = make([]string, n) - - for i := 0; i < len(cmd.page); i++ { - if cmd.page[i], err = rd.ReadString(); err != nil { - return err - } - } - return nil -} - -// Iterator creates a new ScanIterator. -func (cmd *ScanCmd) Iterator() *ScanIterator { - return &ScanIterator{ - cmd: cmd, - } -} - -//------------------------------------------------------------------------------ - -type ClusterNode struct { - ID string - Addr string - NetworkingMetadata map[string]string -} - -type ClusterSlot struct { - Start int - End int - Nodes []ClusterNode -} - -type ClusterSlotsCmd struct { - baseCmd - - val []ClusterSlot -} - -var _ Cmder = (*ClusterSlotsCmd)(nil) - -func NewClusterSlotsCmd(ctx context.Context, args ...interface{}) *ClusterSlotsCmd { - return &ClusterSlotsCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *ClusterSlotsCmd) SetVal(val []ClusterSlot) { - cmd.val = val -} - -func (cmd *ClusterSlotsCmd) Val() []ClusterSlot { - return cmd.val -} - -func (cmd *ClusterSlotsCmd) Result() ([]ClusterSlot, error) { - return cmd.Val(), cmd.Err() -} - -func (cmd *ClusterSlotsCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *ClusterSlotsCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmd.val = make([]ClusterSlot, n) - - for i := 0; i < len(cmd.val); i++ { - n, err = rd.ReadArrayLen() - if err != nil { - return err - } - if n < 2 { - return fmt.Errorf("redis: got %d elements in cluster info, expected at least 2", n) - } - - start, err := rd.ReadInt() - if err != nil { - return err - } - - end, err := rd.ReadInt() - if err != nil { - return err - } - - // subtract start and end. - nodes := make([]ClusterNode, n-2) - - for j := 0; j < len(nodes); j++ { - nn, err := rd.ReadArrayLen() - if err != nil { - return err - } - if nn < 2 || nn > 4 { - return fmt.Errorf("got %d elements in cluster info address, expected 2, 3, or 4", n) - } - - ip, err := rd.ReadString() - if err != nil { - return err - } - - port, err := rd.ReadString() - if err != nil { - return err - } - - nodes[j].Addr = net.JoinHostPort(ip, port) - - if nn >= 3 { - id, err := rd.ReadString() - if err != nil { - return err - } - nodes[j].ID = id - } - - if nn >= 4 { - networkingMetadata := make(map[string]string) - - metadataLength, err := rd.ReadMapLen() - if err != nil { - return err - } - - if metadataLength%2 != 0 { - return fmt.Errorf( - "got %d elements in metadata, expected an even number", metadataLength) - } - - for i := 0; i < metadataLength; i += 2 { - key, err := rd.ReadString() - if err != nil { - return err - } - value, err := rd.ReadString() - if err != nil { - return err - } - networkingMetadata[key] = value - } - - nodes[j].NetworkingMetadata = networkingMetadata - } - } - - cmd.val[i] = ClusterSlot{ - Start: int(start), - End: int(end), - Nodes: nodes, - } - } - - return nil -} - -//------------------------------------------------------------------------------ - -// GeoLocation is used with GeoAdd to add geospatial location. -type GeoLocation struct { - Name string - Longitude, Latitude, Dist float64 - GeoHash int64 -} - -// GeoRadiusQuery is used with GeoRadius to query geospatial index. -type GeoRadiusQuery struct { - Radius float64 - // Can be m, km, ft, or mi. Default is km. - Unit string - WithCoord bool - WithDist bool - WithGeoHash bool - Count int - // Can be ASC or DESC. Default is no sort order. - Sort string - Store string - StoreDist string - - // WithCoord+WithDist+WithGeoHash - withLen int -} - -type GeoLocationCmd struct { - baseCmd - - q *GeoRadiusQuery - locations []GeoLocation -} - -var _ Cmder = (*GeoLocationCmd)(nil) - -func NewGeoLocationCmd(ctx context.Context, q *GeoRadiusQuery, args ...interface{}) *GeoLocationCmd { - return &GeoLocationCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: geoLocationArgs(q, args...), - }, - q: q, - } -} - -func geoLocationArgs(q *GeoRadiusQuery, args ...interface{}) []interface{} { - args = append(args, q.Radius) - if q.Unit != "" { - args = append(args, q.Unit) - } else { - args = append(args, "km") - } - if q.WithCoord { - args = append(args, "withcoord") - q.withLen++ - } - if q.WithDist { - args = append(args, "withdist") - q.withLen++ - } - if q.WithGeoHash { - args = append(args, "withhash") - q.withLen++ - } - if q.Count > 0 { - args = append(args, "count", q.Count) - } - if q.Sort != "" { - args = append(args, q.Sort) - } - if q.Store != "" { - args = append(args, "store") - args = append(args, q.Store) - } - if q.StoreDist != "" { - args = append(args, "storedist") - args = append(args, q.StoreDist) - } - return args -} - -func (cmd *GeoLocationCmd) SetVal(locations []GeoLocation) { - cmd.locations = locations -} - -func (cmd *GeoLocationCmd) Val() []GeoLocation { - return cmd.locations -} - -func (cmd *GeoLocationCmd) Result() ([]GeoLocation, error) { - return cmd.locations, cmd.err -} - -func (cmd *GeoLocationCmd) String() string { - return cmdString(cmd, cmd.locations) -} - -func (cmd *GeoLocationCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmd.locations = make([]GeoLocation, n) - - for i := 0; i < len(cmd.locations); i++ { - // only name - if cmd.q.withLen == 0 { - if cmd.locations[i].Name, err = rd.ReadString(); err != nil { - return err - } - continue - } - - // +name - if err = rd.ReadFixedArrayLen(cmd.q.withLen + 1); err != nil { - return err - } - - if cmd.locations[i].Name, err = rd.ReadString(); err != nil { - return err - } - if cmd.q.WithDist { - if cmd.locations[i].Dist, err = rd.ReadFloat(); err != nil { - return err - } - } - if cmd.q.WithGeoHash { - if cmd.locations[i].GeoHash, err = rd.ReadInt(); err != nil { - return err - } - } - if cmd.q.WithCoord { - if err = rd.ReadFixedArrayLen(2); err != nil { - return err - } - if cmd.locations[i].Longitude, err = rd.ReadFloat(); err != nil { - return err - } - if cmd.locations[i].Latitude, err = rd.ReadFloat(); err != nil { - return err - } - } - } - - return nil -} - -//------------------------------------------------------------------------------ - -// GeoSearchQuery is used for GEOSearch/GEOSearchStore command query. -type GeoSearchQuery struct { - Member string - - // Latitude and Longitude when using FromLonLat option. - Longitude float64 - Latitude float64 - - // Distance and unit when using ByRadius option. - // Can use m, km, ft, or mi. Default is km. - Radius float64 - RadiusUnit string - - // Height, width and unit when using ByBox option. - // Can be m, km, ft, or mi. Default is km. - BoxWidth float64 - BoxHeight float64 - BoxUnit string - - // Can be ASC or DESC. Default is no sort order. - Sort string - Count int - CountAny bool -} - -type GeoSearchLocationQuery struct { - GeoSearchQuery - - WithCoord bool - WithDist bool - WithHash bool -} - -type GeoSearchStoreQuery struct { - GeoSearchQuery - - // When using the StoreDist option, the command stores the items in a - // sorted set populated with their distance from the center of the circle or box, - // as a floating-point number, in the same unit specified for that shape. - StoreDist bool -} - -func geoSearchLocationArgs(q *GeoSearchLocationQuery, args []interface{}) []interface{} { - args = geoSearchArgs(&q.GeoSearchQuery, args) - - if q.WithCoord { - args = append(args, "withcoord") - } - if q.WithDist { - args = append(args, "withdist") - } - if q.WithHash { - args = append(args, "withhash") - } - - return args -} - -func geoSearchArgs(q *GeoSearchQuery, args []interface{}) []interface{} { - if q.Member != "" { - args = append(args, "frommember", q.Member) - } else { - args = append(args, "fromlonlat", q.Longitude, q.Latitude) - } - - if q.Radius > 0 { - if q.RadiusUnit == "" { - q.RadiusUnit = "km" - } - args = append(args, "byradius", q.Radius, q.RadiusUnit) - } else { - if q.BoxUnit == "" { - q.BoxUnit = "km" - } - args = append(args, "bybox", q.BoxWidth, q.BoxHeight, q.BoxUnit) - } - - if q.Sort != "" { - args = append(args, q.Sort) - } - - if q.Count > 0 { - args = append(args, "count", q.Count) - if q.CountAny { - args = append(args, "any") - } - } - - return args -} - -type GeoSearchLocationCmd struct { - baseCmd - - opt *GeoSearchLocationQuery - val []GeoLocation -} - -var _ Cmder = (*GeoSearchLocationCmd)(nil) - -func NewGeoSearchLocationCmd( - ctx context.Context, opt *GeoSearchLocationQuery, args ...interface{}, -) *GeoSearchLocationCmd { - return &GeoSearchLocationCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - opt: opt, - } -} - -func (cmd *GeoSearchLocationCmd) Val() []GeoLocation { - return cmd.val -} - -func (cmd *GeoSearchLocationCmd) Result() ([]GeoLocation, error) { - return cmd.val, cmd.err -} - -func (cmd *GeoSearchLocationCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *GeoSearchLocationCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - - cmd.val = make([]GeoLocation, n) - for i := 0; i < n; i++ { - _, err = rd.ReadArrayLen() - if err != nil { - return err - } - - var loc GeoLocation - - loc.Name, err = rd.ReadString() - if err != nil { - return err - } - if cmd.opt.WithDist { - loc.Dist, err = rd.ReadFloat() - if err != nil { - return err - } - } - if cmd.opt.WithHash { - loc.GeoHash, err = rd.ReadInt() - if err != nil { - return err - } - } - if cmd.opt.WithCoord { - if err = rd.ReadFixedArrayLen(2); err != nil { - return err - } - loc.Longitude, err = rd.ReadFloat() - if err != nil { - return err - } - loc.Latitude, err = rd.ReadFloat() - if err != nil { - return err - } - } - - cmd.val[i] = loc - } - - return nil -} - -//------------------------------------------------------------------------------ - -type GeoPos struct { - Longitude, Latitude float64 -} - -type GeoPosCmd struct { - baseCmd - - val []*GeoPos -} - -var _ Cmder = (*GeoPosCmd)(nil) - -func NewGeoPosCmd(ctx context.Context, args ...interface{}) *GeoPosCmd { - return &GeoPosCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *GeoPosCmd) SetVal(val []*GeoPos) { - cmd.val = val -} - -func (cmd *GeoPosCmd) Val() []*GeoPos { - return cmd.val -} - -func (cmd *GeoPosCmd) Result() ([]*GeoPos, error) { - return cmd.Val(), cmd.Err() -} - -func (cmd *GeoPosCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *GeoPosCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmd.val = make([]*GeoPos, n) - - for i := 0; i < len(cmd.val); i++ { - err = rd.ReadFixedArrayLen(2) - if err != nil { - if err == Nil { - cmd.val[i] = nil - continue - } - return err - } - - longitude, err := rd.ReadFloat() - if err != nil { - return err - } - latitude, err := rd.ReadFloat() - if err != nil { - return err - } - - cmd.val[i] = &GeoPos{ - Longitude: longitude, - Latitude: latitude, - } - } - - return nil -} - -//------------------------------------------------------------------------------ - -type CommandInfo struct { - Name string - Arity int8 - Flags []string - ACLFlags []string - FirstKeyPos int8 - LastKeyPos int8 - StepCount int8 - ReadOnly bool -} - -type CommandsInfoCmd struct { - baseCmd - - val map[string]*CommandInfo -} - -var _ Cmder = (*CommandsInfoCmd)(nil) - -func NewCommandsInfoCmd(ctx context.Context, args ...interface{}) *CommandsInfoCmd { - return &CommandsInfoCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *CommandsInfoCmd) SetVal(val map[string]*CommandInfo) { - cmd.val = val -} - -func (cmd *CommandsInfoCmd) Val() map[string]*CommandInfo { - return cmd.val -} - -func (cmd *CommandsInfoCmd) Result() (map[string]*CommandInfo, error) { - return cmd.Val(), cmd.Err() -} - -func (cmd *CommandsInfoCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *CommandsInfoCmd) readReply(rd *proto.Reader) error { - const numArgRedis5 = 6 - const numArgRedis6 = 7 - const numArgRedis7 = 10 - - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmd.val = make(map[string]*CommandInfo, n) - - for i := 0; i < n; i++ { - nn, err := rd.ReadArrayLen() - if err != nil { - return err - } - - switch nn { - case numArgRedis5, numArgRedis6, numArgRedis7: - // ok - default: - return fmt.Errorf("redis: got %d elements in COMMAND reply, wanted 6/7/10", nn) - } - - cmdInfo := &CommandInfo{} - if cmdInfo.Name, err = rd.ReadString(); err != nil { - return err - } - - arity, err := rd.ReadInt() - if err != nil { - return err - } - cmdInfo.Arity = int8(arity) - - flagLen, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmdInfo.Flags = make([]string, flagLen) - for f := 0; f < len(cmdInfo.Flags); f++ { - switch s, err := rd.ReadString(); { - case err == Nil: - cmdInfo.Flags[f] = "" - case err != nil: - return err - default: - if !cmdInfo.ReadOnly && s == "readonly" { - cmdInfo.ReadOnly = true - } - cmdInfo.Flags[f] = s - } - } - - firstKeyPos, err := rd.ReadInt() - if err != nil { - return err - } - cmdInfo.FirstKeyPos = int8(firstKeyPos) - - lastKeyPos, err := rd.ReadInt() - if err != nil { - return err - } - cmdInfo.LastKeyPos = int8(lastKeyPos) - - stepCount, err := rd.ReadInt() - if err != nil { - return err - } - cmdInfo.StepCount = int8(stepCount) - - if nn >= numArgRedis6 { - aclFlagLen, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmdInfo.ACLFlags = make([]string, aclFlagLen) - for f := 0; f < len(cmdInfo.ACLFlags); f++ { - switch s, err := rd.ReadString(); { - case err == Nil: - cmdInfo.ACLFlags[f] = "" - case err != nil: - return err - default: - cmdInfo.ACLFlags[f] = s - } - } - } - - if nn >= numArgRedis7 { - if err := rd.DiscardNext(); err != nil { - return err - } - if err := rd.DiscardNext(); err != nil { - return err - } - if err := rd.DiscardNext(); err != nil { - return err - } - } - - cmd.val[cmdInfo.Name] = cmdInfo - } - - return nil -} - -//------------------------------------------------------------------------------ - -type cmdsInfoCache struct { - fn func(ctx context.Context) (map[string]*CommandInfo, error) - - once internal.Once - cmds map[string]*CommandInfo -} - -func newCmdsInfoCache(fn func(ctx context.Context) (map[string]*CommandInfo, error)) *cmdsInfoCache { - return &cmdsInfoCache{ - fn: fn, - } -} - -func (c *cmdsInfoCache) Get(ctx context.Context) (map[string]*CommandInfo, error) { - err := c.once.Do(func() error { - cmds, err := c.fn(ctx) - if err != nil { - return err - } - - // Extensions have cmd names in upper case. Convert them to lower case. - for k, v := range cmds { - lower := internal.ToLower(k) - if lower != k { - cmds[lower] = v - } - } - - c.cmds = cmds - return nil - }) - return c.cmds, err -} - -//------------------------------------------------------------------------------ - -type SlowLog struct { - ID int64 - Time time.Time - Duration time.Duration - Args []string - // These are also optional fields emitted only by Redis 4.0 or greater: - // https://redis.io/commands/slowlog#output-format - ClientAddr string - ClientName string -} - -type SlowLogCmd struct { - baseCmd - - val []SlowLog -} - -var _ Cmder = (*SlowLogCmd)(nil) - -func NewSlowLogCmd(ctx context.Context, args ...interface{}) *SlowLogCmd { - return &SlowLogCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *SlowLogCmd) SetVal(val []SlowLog) { - cmd.val = val -} - -func (cmd *SlowLogCmd) Val() []SlowLog { - return cmd.val -} - -func (cmd *SlowLogCmd) Result() ([]SlowLog, error) { - return cmd.Val(), cmd.Err() -} - -func (cmd *SlowLogCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *SlowLogCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - cmd.val = make([]SlowLog, n) - - for i := 0; i < len(cmd.val); i++ { - nn, err := rd.ReadArrayLen() - if err != nil { - return err - } - if nn < 4 { - return fmt.Errorf("redis: got %d elements in slowlog get, expected at least 4", nn) - } - - if cmd.val[i].ID, err = rd.ReadInt(); err != nil { - return err - } - - createdAt, err := rd.ReadInt() - if err != nil { - return err - } - cmd.val[i].Time = time.Unix(createdAt, 0) - - costs, err := rd.ReadInt() - if err != nil { - return err - } - cmd.val[i].Duration = time.Duration(costs) * time.Microsecond - - cmdLen, err := rd.ReadArrayLen() - if err != nil { - return err - } - if cmdLen < 1 { - return fmt.Errorf("redis: got %d elements commands reply in slowlog get, expected at least 1", cmdLen) - } - - cmd.val[i].Args = make([]string, cmdLen) - for f := 0; f < len(cmd.val[i].Args); f++ { - cmd.val[i].Args[f], err = rd.ReadString() - if err != nil { - return err - } - } - - if nn >= 5 { - if cmd.val[i].ClientAddr, err = rd.ReadString(); err != nil { - return err - } - } - - if nn >= 6 { - if cmd.val[i].ClientName, err = rd.ReadString(); err != nil { - return err - } - } - } - - return nil -} - -//----------------------------------------------------------------------- - -type MapStringInterfaceCmd struct { - baseCmd - - val map[string]interface{} -} - -var _ Cmder = (*MapStringInterfaceCmd)(nil) - -func NewMapStringInterfaceCmd(ctx context.Context, args ...interface{}) *MapStringInterfaceCmd { - return &MapStringInterfaceCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *MapStringInterfaceCmd) Val() map[string]interface{} { - return cmd.val -} - -func (cmd *MapStringInterfaceCmd) Result() (map[string]interface{}, error) { - return cmd.Val(), cmd.Err() -} - -func (cmd *MapStringInterfaceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *MapStringInterfaceCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadMapLen() - if err != nil { - return err - } - - cmd.val = make(map[string]interface{}, n) - for i := 0; i < n; i++ { - k, err := rd.ReadString() - if err != nil { - return err - } - v, err := rd.ReadReply() - if err != nil { - if err == Nil { - cmd.val[k] = Nil - continue - } - if err, ok := err.(proto.RedisError); ok { - cmd.val[k] = err - continue - } - return err - } - cmd.val[k] = v - } - return nil -} - -//----------------------------------------------------------------------- - -type MapStringStringSliceCmd struct { - baseCmd - - val []map[string]string -} - -var _ Cmder = (*MapStringStringSliceCmd)(nil) - -func NewMapStringStringSliceCmd(ctx context.Context, args ...interface{}) *MapStringStringSliceCmd { - return &MapStringStringSliceCmd{ - baseCmd: baseCmd{ - ctx: ctx, - args: args, - }, - } -} - -func (cmd *MapStringStringSliceCmd) Val() []map[string]string { - return cmd.val -} - -func (cmd *MapStringStringSliceCmd) Result() ([]map[string]string, error) { - return cmd.Val(), cmd.Err() -} - -func (cmd *MapStringStringSliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *MapStringStringSliceCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() - if err != nil { - return err - } - - cmd.val = make([]map[string]string, n) - for i := 0; i < n; i++ { - nn, err := rd.ReadMapLen() - if err != nil { - return err - } - cmd.val[i] = make(map[string]string, nn) - for f := 0; f < nn; f++ { - k, err := rd.ReadString() - if err != nil { - return err - } - - v, err := rd.ReadString() - if err != nil { - return err - } - cmd.val[i][k] = v - } - } - return nil -} diff --git a/vendor/github.com/go-redis/redis/v9/commands.go b/vendor/github.com/go-redis/redis/v9/commands.go deleted file mode 100644 index beb3af2..0000000 --- a/vendor/github.com/go-redis/redis/v9/commands.go +++ /dev/null @@ -1,3378 +0,0 @@ -package redis - -import ( - "context" - "errors" - "io" - "time" - - "github.com/go-redis/redis/v9/internal" -) - -// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0, -// otherwise you will receive an error: (error) ERR syntax error. -// For example: -// -// rdb.Set(ctx, key, value, redis.KeepTTL) -const KeepTTL = -1 - -func usePrecise(dur time.Duration) bool { - return dur < time.Second || dur%time.Second != 0 -} - -func formatMs(ctx context.Context, dur time.Duration) int64 { - if dur > 0 && dur < time.Millisecond { - internal.Logger.Printf( - ctx, - "specified duration is %s, but minimal supported value is %s - truncating to 1ms", - dur, time.Millisecond, - ) - return 1 - } - return int64(dur / time.Millisecond) -} - -func formatSec(ctx context.Context, dur time.Duration) int64 { - if dur > 0 && dur < time.Second { - internal.Logger.Printf( - ctx, - "specified duration is %s, but minimal supported value is %s - truncating to 1s", - dur, time.Second, - ) - return 1 - } - return int64(dur / time.Second) -} - -func appendArgs(dst, src []interface{}) []interface{} { - if len(src) == 1 { - return appendArg(dst, src[0]) - } - - dst = append(dst, src...) - return dst -} - -func appendArg(dst []interface{}, arg interface{}) []interface{} { - switch arg := arg.(type) { - case []string: - for _, s := range arg { - dst = append(dst, s) - } - return dst - case []interface{}: - dst = append(dst, arg...) - return dst - case map[string]interface{}: - for k, v := range arg { - dst = append(dst, k, v) - } - return dst - case map[string]string: - for k, v := range arg { - dst = append(dst, k, v) - } - return dst - default: - return append(dst, arg) - } -} - -type Cmdable interface { - Pipeline() Pipeliner - Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) - - TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) - TxPipeline() Pipeliner - - Command(ctx context.Context) *CommandsInfoCmd - ClientGetName(ctx context.Context) *StringCmd - Echo(ctx context.Context, message interface{}) *StringCmd - Ping(ctx context.Context) *StatusCmd - Quit(ctx context.Context) *StatusCmd - Del(ctx context.Context, keys ...string) *IntCmd - Unlink(ctx context.Context, keys ...string) *IntCmd - Dump(ctx context.Context, key string) *StringCmd - Exists(ctx context.Context, keys ...string) *IntCmd - Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd - ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd - ExpireNX(ctx context.Context, key string, expiration time.Duration) *BoolCmd - ExpireXX(ctx context.Context, key string, expiration time.Duration) *BoolCmd - ExpireGT(ctx context.Context, key string, expiration time.Duration) *BoolCmd - ExpireLT(ctx context.Context, key string, expiration time.Duration) *BoolCmd - Keys(ctx context.Context, pattern string) *StringSliceCmd - Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd - Move(ctx context.Context, key string, db int) *BoolCmd - ObjectRefCount(ctx context.Context, key string) *IntCmd - ObjectEncoding(ctx context.Context, key string) *StringCmd - ObjectIdleTime(ctx context.Context, key string) *DurationCmd - Persist(ctx context.Context, key string) *BoolCmd - PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd - PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd - PTTL(ctx context.Context, key string) *DurationCmd - RandomKey(ctx context.Context) *StringCmd - Rename(ctx context.Context, key, newkey string) *StatusCmd - RenameNX(ctx context.Context, key, newkey string) *BoolCmd - Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd - RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd - Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd - SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd - SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd - Touch(ctx context.Context, keys ...string) *IntCmd - TTL(ctx context.Context, key string) *DurationCmd - Type(ctx context.Context, key string) *StatusCmd - Append(ctx context.Context, key, value string) *IntCmd - Decr(ctx context.Context, key string) *IntCmd - DecrBy(ctx context.Context, key string, decrement int64) *IntCmd - Get(ctx context.Context, key string) *StringCmd - GetRange(ctx context.Context, key string, start, end int64) *StringCmd - GetSet(ctx context.Context, key string, value interface{}) *StringCmd - GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd - GetDel(ctx context.Context, key string) *StringCmd - Incr(ctx context.Context, key string) *IntCmd - IncrBy(ctx context.Context, key string, value int64) *IntCmd - IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd - MGet(ctx context.Context, keys ...string) *SliceCmd - MSet(ctx context.Context, values ...interface{}) *StatusCmd - MSetNX(ctx context.Context, values ...interface{}) *BoolCmd - Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd - SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd - SetEx(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd - SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd - SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd - SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd - StrLen(ctx context.Context, key string) *IntCmd - Copy(ctx context.Context, sourceKey string, destKey string, db int, replace bool) *IntCmd - - GetBit(ctx context.Context, key string, offset int64) *IntCmd - SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd - BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd - BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd - BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd - BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd - BitOpNot(ctx context.Context, destKey string, key string) *IntCmd - BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd - BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd - - Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd - ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *ScanCmd - SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd - HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd - ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd - - HDel(ctx context.Context, key string, fields ...string) *IntCmd - HExists(ctx context.Context, key, field string) *BoolCmd - HGet(ctx context.Context, key, field string) *StringCmd - HGetAll(ctx context.Context, key string) *MapStringStringCmd - HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd - HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd - HKeys(ctx context.Context, key string) *StringSliceCmd - HLen(ctx context.Context, key string) *IntCmd - HMGet(ctx context.Context, key string, fields ...string) *SliceCmd - HSet(ctx context.Context, key string, values ...interface{}) *IntCmd - HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd - HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd - HVals(ctx context.Context, key string) *StringSliceCmd - HRandField(ctx context.Context, key string, count int) *StringSliceCmd - HRandFieldWithValues(ctx context.Context, key string, count int) *KeyValueSliceCmd - - BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd - BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd - BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd - LIndex(ctx context.Context, key string, index int64) *StringCmd - LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd - LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd - LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd - LLen(ctx context.Context, key string) *IntCmd - LPop(ctx context.Context, key string) *StringCmd - LPopCount(ctx context.Context, key string, count int) *StringSliceCmd - LPos(ctx context.Context, key string, value string, args LPosArgs) *IntCmd - LPosCount(ctx context.Context, key string, value string, count int64, args LPosArgs) *IntSliceCmd - LPush(ctx context.Context, key string, values ...interface{}) *IntCmd - LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd - LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd - LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd - LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd - LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd - RPop(ctx context.Context, key string) *StringCmd - RPopCount(ctx context.Context, key string, count int) *StringSliceCmd - RPopLPush(ctx context.Context, source, destination string) *StringCmd - RPush(ctx context.Context, key string, values ...interface{}) *IntCmd - RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd - LMove(ctx context.Context, source, destination, srcpos, destpos string) *StringCmd - BLMove(ctx context.Context, source, destination, srcpos, destpos string, timeout time.Duration) *StringCmd - - SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd - SCard(ctx context.Context, key string) *IntCmd - SDiff(ctx context.Context, keys ...string) *StringSliceCmd - SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd - SInter(ctx context.Context, keys ...string) *StringSliceCmd - SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd - SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd - SMIsMember(ctx context.Context, key string, members ...interface{}) *BoolSliceCmd - SMembers(ctx context.Context, key string) *StringSliceCmd - SMembersMap(ctx context.Context, key string) *StringStructMapCmd - SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd - SPop(ctx context.Context, key string) *StringCmd - SPopN(ctx context.Context, key string, count int64) *StringSliceCmd - SRandMember(ctx context.Context, key string) *StringCmd - SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd - SRem(ctx context.Context, key string, members ...interface{}) *IntCmd - SUnion(ctx context.Context, keys ...string) *StringSliceCmd - SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd - - XAdd(ctx context.Context, a *XAddArgs) *StringCmd - XDel(ctx context.Context, stream string, ids ...string) *IntCmd - XLen(ctx context.Context, stream string) *IntCmd - XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd - XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd - XRevRange(ctx context.Context, stream string, start, stop string) *XMessageSliceCmd - XRevRangeN(ctx context.Context, stream string, start, stop string, count int64) *XMessageSliceCmd - XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd - XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd - XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd - XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd - XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd - XGroupDestroy(ctx context.Context, stream, group string) *IntCmd - XGroupCreateConsumer(ctx context.Context, stream, group, consumer string) *IntCmd - XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd - XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd - XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd - XPending(ctx context.Context, stream, group string) *XPendingCmd - XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd - XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd - XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd - XAutoClaim(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimCmd - XAutoClaimJustID(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimJustIDCmd - XTrimMaxLen(ctx context.Context, key string, maxLen int64) *IntCmd - XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *IntCmd - XTrimMinID(ctx context.Context, key string, minID string) *IntCmd - XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *IntCmd - XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd - XInfoStream(ctx context.Context, key string) *XInfoStreamCmd - XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd - XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd - - BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd - BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd - - ZAdd(ctx context.Context, key string, members ...Z) *IntCmd - ZAddNX(ctx context.Context, key string, members ...Z) *IntCmd - ZAddXX(ctx context.Context, key string, members ...Z) *IntCmd - ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd - ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd - ZCard(ctx context.Context, key string) *IntCmd - ZCount(ctx context.Context, key, min, max string) *IntCmd - ZLexCount(ctx context.Context, key, min, max string) *IntCmd - ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd - ZInter(ctx context.Context, store *ZStore) *StringSliceCmd - ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd - ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd - ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd - ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd - ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd - ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd - ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd - ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd - ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd - ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd - ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd - ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd - ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd - ZRank(ctx context.Context, key, member string) *IntCmd - ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd - ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd - ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd - ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd - ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd - ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd - ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd - ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd - ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd - ZRevRank(ctx context.Context, key, member string) *IntCmd - ZScore(ctx context.Context, key, member string) *FloatCmd - ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd - ZRandMember(ctx context.Context, key string, count int) *StringSliceCmd - ZRandMemberWithScores(ctx context.Context, key string, count int) *ZSliceCmd - ZUnion(ctx context.Context, store ZStore) *StringSliceCmd - ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd - ZDiff(ctx context.Context, keys ...string) *StringSliceCmd - ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd - ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd - - PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd - PFCount(ctx context.Context, keys ...string) *IntCmd - PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd - - BgRewriteAOF(ctx context.Context) *StatusCmd - BgSave(ctx context.Context) *StatusCmd - ClientKill(ctx context.Context, ipPort string) *StatusCmd - ClientKillByFilter(ctx context.Context, keys ...string) *IntCmd - ClientList(ctx context.Context) *StringCmd - ClientPause(ctx context.Context, dur time.Duration) *BoolCmd - ClientUnpause(ctx context.Context) *BoolCmd - ClientID(ctx context.Context) *IntCmd - ClientUnblock(ctx context.Context, id int64) *IntCmd - ClientUnblockWithError(ctx context.Context, id int64) *IntCmd - ConfigGet(ctx context.Context, parameter string) *MapStringStringCmd - ConfigResetStat(ctx context.Context) *StatusCmd - ConfigSet(ctx context.Context, parameter, value string) *StatusCmd - ConfigRewrite(ctx context.Context) *StatusCmd - DBSize(ctx context.Context) *IntCmd - FlushAll(ctx context.Context) *StatusCmd - FlushAllAsync(ctx context.Context) *StatusCmd - FlushDB(ctx context.Context) *StatusCmd - FlushDBAsync(ctx context.Context) *StatusCmd - Info(ctx context.Context, section ...string) *StringCmd - LastSave(ctx context.Context) *IntCmd - Save(ctx context.Context) *StatusCmd - Shutdown(ctx context.Context) *StatusCmd - ShutdownSave(ctx context.Context) *StatusCmd - ShutdownNoSave(ctx context.Context) *StatusCmd - SlaveOf(ctx context.Context, host, port string) *StatusCmd - SlowLogGet(ctx context.Context, num int64) *SlowLogCmd - Time(ctx context.Context) *TimeCmd - DebugObject(ctx context.Context, key string) *StringCmd - ReadOnly(ctx context.Context) *StatusCmd - ReadWrite(ctx context.Context) *StatusCmd - MemoryUsage(ctx context.Context, key string, samples ...int) *IntCmd - - Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd - EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd - ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd - ScriptFlush(ctx context.Context) *StatusCmd - ScriptKill(ctx context.Context) *StatusCmd - ScriptLoad(ctx context.Context, script string) *StringCmd - - Publish(ctx context.Context, channel string, message interface{}) *IntCmd - PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd - PubSubNumSub(ctx context.Context, channels ...string) *StringIntMapCmd - PubSubNumPat(ctx context.Context) *IntCmd - - ClusterSlots(ctx context.Context) *ClusterSlotsCmd - ClusterNodes(ctx context.Context) *StringCmd - ClusterMeet(ctx context.Context, host, port string) *StatusCmd - ClusterForget(ctx context.Context, nodeID string) *StatusCmd - ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd - ClusterResetSoft(ctx context.Context) *StatusCmd - ClusterResetHard(ctx context.Context) *StatusCmd - ClusterInfo(ctx context.Context) *StringCmd - ClusterKeySlot(ctx context.Context, key string) *IntCmd - ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd - ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd - ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd - ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd - ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd - ClusterSaveConfig(ctx context.Context) *StatusCmd - ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd - ClusterFailover(ctx context.Context) *StatusCmd - ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd - ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd - - GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd - GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd - GeoRadius(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *GeoLocationCmd - GeoRadiusStore(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *IntCmd - GeoRadiusByMember(ctx context.Context, key, member string, query *GeoRadiusQuery) *GeoLocationCmd - GeoRadiusByMemberStore(ctx context.Context, key, member string, query *GeoRadiusQuery) *IntCmd - GeoSearch(ctx context.Context, key string, q *GeoSearchQuery) *StringSliceCmd - GeoSearchLocation(ctx context.Context, key string, q *GeoSearchLocationQuery) *GeoSearchLocationCmd - GeoSearchStore(ctx context.Context, key, store string, q *GeoSearchStoreQuery) *IntCmd - GeoDist(ctx context.Context, key string, member1, member2, unit string) *FloatCmd - GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd -} - -type StatefulCmdable interface { - Cmdable - Auth(ctx context.Context, password string) *StatusCmd - AuthACL(ctx context.Context, username, password string) *StatusCmd - Select(ctx context.Context, index int) *StatusCmd - SwapDB(ctx context.Context, index1, index2 int) *StatusCmd - ClientSetName(ctx context.Context, name string) *BoolCmd - Hello(ctx context.Context, ver int, username, password, clientName string) *MapStringInterfaceCmd -} - -var ( - _ Cmdable = (*Client)(nil) - _ Cmdable = (*Tx)(nil) - _ Cmdable = (*Ring)(nil) - _ Cmdable = (*ClusterClient)(nil) -) - -type cmdable func(ctx context.Context, cmd Cmder) error - -type statefulCmdable func(ctx context.Context, cmd Cmder) error - -//------------------------------------------------------------------------------ - -func (c statefulCmdable) Auth(ctx context.Context, password string) *StatusCmd { - cmd := NewStatusCmd(ctx, "auth", password) - _ = c(ctx, cmd) - return cmd -} - -// AuthACL Perform an AUTH command, using the given user and pass. -// Should be used to authenticate the current connection with one of the connections defined in the ACL list -// when connecting to a Redis 6.0 instance, or greater, that is using the Redis ACL system. -func (c statefulCmdable) AuthACL(ctx context.Context, username, password string) *StatusCmd { - cmd := NewStatusCmd(ctx, "auth", username, password) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Wait(ctx context.Context, numSlaves int, timeout time.Duration) *IntCmd { - cmd := NewIntCmd(ctx, "wait", numSlaves, int(timeout/time.Millisecond)) - cmd.setReadTimeout(timeout) - _ = c(ctx, cmd) - return cmd -} - -func (c statefulCmdable) Select(ctx context.Context, index int) *StatusCmd { - cmd := NewStatusCmd(ctx, "select", index) - _ = c(ctx, cmd) - return cmd -} - -func (c statefulCmdable) SwapDB(ctx context.Context, index1, index2 int) *StatusCmd { - cmd := NewStatusCmd(ctx, "swapdb", index1, index2) - _ = c(ctx, cmd) - return cmd -} - -// ClientSetName assigns a name to the connection. -func (c statefulCmdable) ClientSetName(ctx context.Context, name string) *BoolCmd { - cmd := NewBoolCmd(ctx, "client", "setname", name) - _ = c(ctx, cmd) - return cmd -} - -// Hello Set the resp protocol used. -func (c statefulCmdable) Hello(ctx context.Context, - ver int, username, password, clientName string) *MapStringInterfaceCmd { - args := make([]interface{}, 0, 7) - args = append(args, "hello", ver) - if password != "" { - if username != "" { - args = append(args, "auth", username, password) - } else { - args = append(args, "auth", "default", password) - } - } - if clientName != "" { - args = append(args, "setname", clientName) - } - cmd := NewMapStringInterfaceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c cmdable) Command(ctx context.Context) *CommandsInfoCmd { - cmd := NewCommandsInfoCmd(ctx, "command") - _ = c(ctx, cmd) - return cmd -} - -// ClientGetName returns the name of the connection. -func (c cmdable) ClientGetName(ctx context.Context) *StringCmd { - cmd := NewStringCmd(ctx, "client", "getname") - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Echo(ctx context.Context, message interface{}) *StringCmd { - cmd := NewStringCmd(ctx, "echo", message) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Ping(ctx context.Context) *StatusCmd { - cmd := NewStatusCmd(ctx, "ping") - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Quit(_ context.Context) *StatusCmd { - panic("not implemented") -} - -func (c cmdable) Del(ctx context.Context, keys ...string) *IntCmd { - args := make([]interface{}, 1+len(keys)) - args[0] = "del" - for i, key := range keys { - args[1+i] = key - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Unlink(ctx context.Context, keys ...string) *IntCmd { - args := make([]interface{}, 1+len(keys)) - args[0] = "unlink" - for i, key := range keys { - args[1+i] = key - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Dump(ctx context.Context, key string) *StringCmd { - cmd := NewStringCmd(ctx, "dump", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Exists(ctx context.Context, keys ...string) *IntCmd { - args := make([]interface{}, 1+len(keys)) - args[0] = "exists" - for i, key := range keys { - args[1+i] = key - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd { - return c.expire(ctx, key, expiration, "") -} - -func (c cmdable) ExpireNX(ctx context.Context, key string, expiration time.Duration) *BoolCmd { - return c.expire(ctx, key, expiration, "NX") -} - -func (c cmdable) ExpireXX(ctx context.Context, key string, expiration time.Duration) *BoolCmd { - return c.expire(ctx, key, expiration, "XX") -} - -func (c cmdable) ExpireGT(ctx context.Context, key string, expiration time.Duration) *BoolCmd { - return c.expire(ctx, key, expiration, "GT") -} - -func (c cmdable) ExpireLT(ctx context.Context, key string, expiration time.Duration) *BoolCmd { - return c.expire(ctx, key, expiration, "LT") -} - -func (c cmdable) expire( - ctx context.Context, key string, expiration time.Duration, mode string, -) *BoolCmd { - args := make([]interface{}, 3, 4) - args[0] = "expire" - args[1] = key - args[2] = formatSec(ctx, expiration) - if mode != "" { - args = append(args, mode) - } - - cmd := NewBoolCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd { - cmd := NewBoolCmd(ctx, "expireat", key, tm.Unix()) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Keys(ctx context.Context, pattern string) *StringSliceCmd { - cmd := NewStringSliceCmd(ctx, "keys", pattern) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd { - cmd := NewStatusCmd( - ctx, - "migrate", - host, - port, - key, - db, - formatMs(ctx, timeout), - ) - cmd.setReadTimeout(timeout) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Move(ctx context.Context, key string, db int) *BoolCmd { - cmd := NewBoolCmd(ctx, "move", key, db) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ObjectRefCount(ctx context.Context, key string) *IntCmd { - cmd := NewIntCmd(ctx, "object", "refcount", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ObjectEncoding(ctx context.Context, key string) *StringCmd { - cmd := NewStringCmd(ctx, "object", "encoding", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ObjectIdleTime(ctx context.Context, key string) *DurationCmd { - cmd := NewDurationCmd(ctx, time.Second, "object", "idletime", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Persist(ctx context.Context, key string) *BoolCmd { - cmd := NewBoolCmd(ctx, "persist", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd { - cmd := NewBoolCmd(ctx, "pexpire", key, formatMs(ctx, expiration)) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd { - cmd := NewBoolCmd( - ctx, - "pexpireat", - key, - tm.UnixNano()/int64(time.Millisecond), - ) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) PTTL(ctx context.Context, key string) *DurationCmd { - cmd := NewDurationCmd(ctx, time.Millisecond, "pttl", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) RandomKey(ctx context.Context) *StringCmd { - cmd := NewStringCmd(ctx, "randomkey") - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Rename(ctx context.Context, key, newkey string) *StatusCmd { - cmd := NewStatusCmd(ctx, "rename", key, newkey) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) RenameNX(ctx context.Context, key, newkey string) *BoolCmd { - cmd := NewBoolCmd(ctx, "renamenx", key, newkey) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd { - cmd := NewStatusCmd( - ctx, - "restore", - key, - formatMs(ctx, ttl), - value, - ) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd { - cmd := NewStatusCmd( - ctx, - "restore", - key, - formatMs(ctx, ttl), - value, - "replace", - ) - _ = c(ctx, cmd) - return cmd -} - -type Sort struct { - By string - Offset, Count int64 - Get []string - Order string - Alpha bool -} - -func (sort *Sort) args(key string) []interface{} { - args := []interface{}{"sort", key} - if sort.By != "" { - args = append(args, "by", sort.By) - } - if sort.Offset != 0 || sort.Count != 0 { - args = append(args, "limit", sort.Offset, sort.Count) - } - for _, get := range sort.Get { - args = append(args, "get", get) - } - if sort.Order != "" { - args = append(args, sort.Order) - } - if sort.Alpha { - args = append(args, "alpha") - } - return args -} - -func (c cmdable) Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd { - cmd := NewStringSliceCmd(ctx, sort.args(key)...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd { - args := sort.args(key) - if store != "" { - args = append(args, "store", store) - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd { - cmd := NewSliceCmd(ctx, sort.args(key)...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Touch(ctx context.Context, keys ...string) *IntCmd { - args := make([]interface{}, len(keys)+1) - args[0] = "touch" - for i, key := range keys { - args[i+1] = key - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) TTL(ctx context.Context, key string) *DurationCmd { - cmd := NewDurationCmd(ctx, time.Second, "ttl", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Type(ctx context.Context, key string) *StatusCmd { - cmd := NewStatusCmd(ctx, "type", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Append(ctx context.Context, key, value string) *IntCmd { - cmd := NewIntCmd(ctx, "append", key, value) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Decr(ctx context.Context, key string) *IntCmd { - cmd := NewIntCmd(ctx, "decr", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) DecrBy(ctx context.Context, key string, decrement int64) *IntCmd { - cmd := NewIntCmd(ctx, "decrby", key, decrement) - _ = c(ctx, cmd) - return cmd -} - -// Get Redis `GET key` command. It returns redis.Nil error when key does not exist. -func (c cmdable) Get(ctx context.Context, key string) *StringCmd { - cmd := NewStringCmd(ctx, "get", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) GetRange(ctx context.Context, key string, start, end int64) *StringCmd { - cmd := NewStringCmd(ctx, "getrange", key, start, end) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) GetSet(ctx context.Context, key string, value interface{}) *StringCmd { - cmd := NewStringCmd(ctx, "getset", key, value) - _ = c(ctx, cmd) - return cmd -} - -// GetEx An expiration of zero removes the TTL associated with the key (i.e. GETEX key persist). -// Requires Redis >= 6.2.0. -func (c cmdable) GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd { - args := make([]interface{}, 0, 4) - args = append(args, "getex", key) - if expiration > 0 { - if usePrecise(expiration) { - args = append(args, "px", formatMs(ctx, expiration)) - } else { - args = append(args, "ex", formatSec(ctx, expiration)) - } - } else if expiration == 0 { - args = append(args, "persist") - } - - cmd := NewStringCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -// GetDel redis-server version >= 6.2.0. -func (c cmdable) GetDel(ctx context.Context, key string) *StringCmd { - cmd := NewStringCmd(ctx, "getdel", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Incr(ctx context.Context, key string) *IntCmd { - cmd := NewIntCmd(ctx, "incr", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) IncrBy(ctx context.Context, key string, value int64) *IntCmd { - cmd := NewIntCmd(ctx, "incrby", key, value) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd { - cmd := NewFloatCmd(ctx, "incrbyfloat", key, value) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) MGet(ctx context.Context, keys ...string) *SliceCmd { - args := make([]interface{}, 1+len(keys)) - args[0] = "mget" - for i, key := range keys { - args[1+i] = key - } - cmd := NewSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -// MSet is like Set but accepts multiple values: -// - MSet("key1", "value1", "key2", "value2") -// - MSet([]string{"key1", "value1", "key2", "value2"}) -// - MSet(map[string]interface{}{"key1": "value1", "key2": "value2"}) -func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd { - args := make([]interface{}, 1, 1+len(values)) - args[0] = "mset" - args = appendArgs(args, values) - cmd := NewStatusCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -// MSetNX is like SetNX but accepts multiple values: -// - MSetNX("key1", "value1", "key2", "value2") -// - MSetNX([]string{"key1", "value1", "key2", "value2"}) -// - MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"}) -func (c cmdable) MSetNX(ctx context.Context, values ...interface{}) *BoolCmd { - args := make([]interface{}, 1, 1+len(values)) - args[0] = "msetnx" - args = appendArgs(args, values) - cmd := NewBoolCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -// Set Redis `SET key value [expiration]` command. -// Use expiration for `SETEx`-like behavior. -// -// Zero expiration means the key has no expiration time. -// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0, -// otherwise you will receive an error: (error) ERR syntax error. -func (c cmdable) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd { - args := make([]interface{}, 3, 5) - args[0] = "set" - args[1] = key - args[2] = value - if expiration > 0 { - if usePrecise(expiration) { - args = append(args, "px", formatMs(ctx, expiration)) - } else { - args = append(args, "ex", formatSec(ctx, expiration)) - } - } else if expiration == KeepTTL { - args = append(args, "keepttl") - } - - cmd := NewStatusCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -// SetArgs provides arguments for the SetArgs function. -type SetArgs struct { - // Mode can be `NX` or `XX` or empty. - Mode string - - // Zero `TTL` or `Expiration` means that the key has no expiration time. - TTL time.Duration - ExpireAt time.Time - - // When Get is true, the command returns the old value stored at key, or nil when key did not exist. - Get bool - - // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0, - // otherwise you will receive an error: (error) ERR syntax error. - KeepTTL bool -} - -// SetArgs supports all the options that the SET command supports. -// It is the alternative to the Set function when you want -// to have more control over the options. -func (c cmdable) SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd { - args := []interface{}{"set", key, value} - - if a.KeepTTL { - args = append(args, "keepttl") - } - - if !a.ExpireAt.IsZero() { - args = append(args, "exat", a.ExpireAt.Unix()) - } - if a.TTL > 0 { - if usePrecise(a.TTL) { - args = append(args, "px", formatMs(ctx, a.TTL)) - } else { - args = append(args, "ex", formatSec(ctx, a.TTL)) - } - } - - if a.Mode != "" { - args = append(args, a.Mode) - } - - if a.Get { - args = append(args, "get") - } - - cmd := NewStatusCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -// SetEx Redis `SETEx key expiration value` command. -func (c cmdable) SetEx(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd { - cmd := NewStatusCmd(ctx, "setex", key, formatSec(ctx, expiration), value) - _ = c(ctx, cmd) - return cmd -} - -// SetNX Redis `SET key value [expiration] NX` command. -// -// Zero expiration means the key has no expiration time. -// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0, -// otherwise you will receive an error: (error) ERR syntax error. -func (c cmdable) SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd { - var cmd *BoolCmd - switch expiration { - case 0: - // Use old `SETNX` to support old Redis versions. - cmd = NewBoolCmd(ctx, "setnx", key, value) - case KeepTTL: - cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "nx") - default: - if usePrecise(expiration) { - cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "nx") - } else { - cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "nx") - } - } - - _ = c(ctx, cmd) - return cmd -} - -// SetXX Redis `SET key value [expiration] XX` command. -// -// Zero expiration means the key has no expiration time. -// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0, -// otherwise you will receive an error: (error) ERR syntax error. -func (c cmdable) SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd { - var cmd *BoolCmd - switch expiration { - case 0: - cmd = NewBoolCmd(ctx, "set", key, value, "xx") - case KeepTTL: - cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "xx") - default: - if usePrecise(expiration) { - cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "xx") - } else { - cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "xx") - } - } - - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd { - cmd := NewIntCmd(ctx, "setrange", key, offset, value) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) StrLen(ctx context.Context, key string) *IntCmd { - cmd := NewIntCmd(ctx, "strlen", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) Copy(ctx context.Context, sourceKey, destKey string, db int, replace bool) *IntCmd { - args := []interface{}{"copy", sourceKey, destKey, "DB", db} - if replace { - args = append(args, "REPLACE") - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c cmdable) GetBit(ctx context.Context, key string, offset int64) *IntCmd { - cmd := NewIntCmd(ctx, "getbit", key, offset) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd { - cmd := NewIntCmd( - ctx, - "setbit", - key, - offset, - value, - ) - _ = c(ctx, cmd) - return cmd -} - -type BitCount struct { - Start, End int64 -} - -func (c cmdable) BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd { - args := []interface{}{"bitcount", key} - if bitCount != nil { - args = append( - args, - bitCount.Start, - bitCount.End, - ) - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) bitOp(ctx context.Context, op, destKey string, keys ...string) *IntCmd { - args := make([]interface{}, 3+len(keys)) - args[0] = "bitop" - args[1] = op - args[2] = destKey - for i, key := range keys { - args[3+i] = key - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd { - return c.bitOp(ctx, "and", destKey, keys...) -} - -func (c cmdable) BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd { - return c.bitOp(ctx, "or", destKey, keys...) -} - -func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd { - return c.bitOp(ctx, "xor", destKey, keys...) -} - -func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntCmd { - return c.bitOp(ctx, "not", destKey, key) -} - -func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd { - args := make([]interface{}, 3+len(pos)) - args[0] = "bitpos" - args[1] = key - args[2] = bit - switch len(pos) { - case 0: - case 1: - args[3] = pos[0] - case 2: - args[3] = pos[0] - args[4] = pos[1] - default: - panic("too many arguments") - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd { - a := make([]interface{}, 0, 2+len(args)) - a = append(a, "bitfield") - a = append(a, key) - a = append(a, args...) - cmd := NewIntSliceCmd(ctx, a...) - _ = c(ctx, cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c cmdable) Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd { - args := []interface{}{"scan", cursor} - if match != "" { - args = append(args, "match", match) - } - if count > 0 { - args = append(args, "count", count) - } - cmd := NewScanCmd(ctx, c, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *ScanCmd { - args := []interface{}{"scan", cursor} - if match != "" { - args = append(args, "match", match) - } - if count > 0 { - args = append(args, "count", count) - } - if keyType != "" { - args = append(args, "type", keyType) - } - cmd := NewScanCmd(ctx, c, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd { - args := []interface{}{"sscan", key, cursor} - if match != "" { - args = append(args, "match", match) - } - if count > 0 { - args = append(args, "count", count) - } - cmd := NewScanCmd(ctx, c, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd { - args := []interface{}{"hscan", key, cursor} - if match != "" { - args = append(args, "match", match) - } - if count > 0 { - args = append(args, "count", count) - } - cmd := NewScanCmd(ctx, c, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd { - args := []interface{}{"zscan", key, cursor} - if match != "" { - args = append(args, "match", match) - } - if count > 0 { - args = append(args, "count", count) - } - cmd := NewScanCmd(ctx, c, args...) - _ = c(ctx, cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c cmdable) HDel(ctx context.Context, key string, fields ...string) *IntCmd { - args := make([]interface{}, 2+len(fields)) - args[0] = "hdel" - args[1] = key - for i, field := range fields { - args[2+i] = field - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) HExists(ctx context.Context, key, field string) *BoolCmd { - cmd := NewBoolCmd(ctx, "hexists", key, field) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) HGet(ctx context.Context, key, field string) *StringCmd { - cmd := NewStringCmd(ctx, "hget", key, field) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) HGetAll(ctx context.Context, key string) *MapStringStringCmd { - cmd := NewMapStringStringCmd(ctx, "hgetall", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd { - cmd := NewIntCmd(ctx, "hincrby", key, field, incr) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd { - cmd := NewFloatCmd(ctx, "hincrbyfloat", key, field, incr) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) HKeys(ctx context.Context, key string) *StringSliceCmd { - cmd := NewStringSliceCmd(ctx, "hkeys", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) HLen(ctx context.Context, key string) *IntCmd { - cmd := NewIntCmd(ctx, "hlen", key) - _ = c(ctx, cmd) - return cmd -} - -// HMGet returns the values for the specified fields in the hash stored at key. -// It returns an interface{} to distinguish between empty string and nil value. -func (c cmdable) HMGet(ctx context.Context, key string, fields ...string) *SliceCmd { - args := make([]interface{}, 2+len(fields)) - args[0] = "hmget" - args[1] = key - for i, field := range fields { - args[2+i] = field - } - cmd := NewSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -// HSet accepts values in following formats: -// - HSet("myhash", "key1", "value1", "key2", "value2") -// - HSet("myhash", []string{"key1", "value1", "key2", "value2"}) -// - HSet("myhash", map[string]interface{}{"key1": "value1", "key2": "value2"}) -// -// Note that it requires Redis v4 for multiple field/value pairs support. -func (c cmdable) HSet(ctx context.Context, key string, values ...interface{}) *IntCmd { - args := make([]interface{}, 2, 2+len(values)) - args[0] = "hset" - args[1] = key - args = appendArgs(args, values) - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -// HMSet is a deprecated version of HSet left for compatibility with Redis 3. -func (c cmdable) HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd { - args := make([]interface{}, 2, 2+len(values)) - args[0] = "hmset" - args[1] = key - args = appendArgs(args, values) - cmd := NewBoolCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd { - cmd := NewBoolCmd(ctx, "hsetnx", key, field, value) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) HVals(ctx context.Context, key string) *StringSliceCmd { - cmd := NewStringSliceCmd(ctx, "hvals", key) - _ = c(ctx, cmd) - return cmd -} - -// HRandField redis-server version >= 6.2.0. -func (c cmdable) HRandField(ctx context.Context, key string, count int) *StringSliceCmd { - cmd := NewStringSliceCmd(ctx, "hrandfield", key, count) - _ = c(ctx, cmd) - return cmd -} - -// HRandFieldWithValues redis-server version >= 6.2.0. -func (c cmdable) HRandFieldWithValues(ctx context.Context, key string, count int) *KeyValueSliceCmd { - cmd := NewKeyValueSliceCmd(ctx, "hrandfield", key, count, "withvalues") - _ = c(ctx, cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c cmdable) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd { - args := make([]interface{}, 1+len(keys)+1) - args[0] = "blpop" - for i, key := range keys { - args[1+i] = key - } - args[len(args)-1] = formatSec(ctx, timeout) - cmd := NewStringSliceCmd(ctx, args...) - cmd.setReadTimeout(timeout) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd { - args := make([]interface{}, 1+len(keys)+1) - args[0] = "brpop" - for i, key := range keys { - args[1+i] = key - } - args[len(keys)+1] = formatSec(ctx, timeout) - cmd := NewStringSliceCmd(ctx, args...) - cmd.setReadTimeout(timeout) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd { - cmd := NewStringCmd( - ctx, - "brpoplpush", - source, - destination, - formatSec(ctx, timeout), - ) - cmd.setReadTimeout(timeout) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LIndex(ctx context.Context, key string, index int64) *StringCmd { - cmd := NewStringCmd(ctx, "lindex", key, index) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd { - cmd := NewIntCmd(ctx, "linsert", key, op, pivot, value) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd { - cmd := NewIntCmd(ctx, "linsert", key, "before", pivot, value) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd { - cmd := NewIntCmd(ctx, "linsert", key, "after", pivot, value) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LLen(ctx context.Context, key string) *IntCmd { - cmd := NewIntCmd(ctx, "llen", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LPop(ctx context.Context, key string) *StringCmd { - cmd := NewStringCmd(ctx, "lpop", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LPopCount(ctx context.Context, key string, count int) *StringSliceCmd { - cmd := NewStringSliceCmd(ctx, "lpop", key, count) - _ = c(ctx, cmd) - return cmd -} - -type LPosArgs struct { - Rank, MaxLen int64 -} - -func (c cmdable) LPos(ctx context.Context, key string, value string, a LPosArgs) *IntCmd { - args := []interface{}{"lpos", key, value} - if a.Rank != 0 { - args = append(args, "rank", a.Rank) - } - if a.MaxLen != 0 { - args = append(args, "maxlen", a.MaxLen) - } - - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LPosCount(ctx context.Context, key string, value string, count int64, a LPosArgs) *IntSliceCmd { - args := []interface{}{"lpos", key, value, "count", count} - if a.Rank != 0 { - args = append(args, "rank", a.Rank) - } - if a.MaxLen != 0 { - args = append(args, "maxlen", a.MaxLen) - } - cmd := NewIntSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LPush(ctx context.Context, key string, values ...interface{}) *IntCmd { - args := make([]interface{}, 2, 2+len(values)) - args[0] = "lpush" - args[1] = key - args = appendArgs(args, values) - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd { - args := make([]interface{}, 2, 2+len(values)) - args[0] = "lpushx" - args[1] = key - args = appendArgs(args, values) - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd { - cmd := NewStringSliceCmd( - ctx, - "lrange", - key, - start, - stop, - ) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd { - cmd := NewIntCmd(ctx, "lrem", key, count, value) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd { - cmd := NewStatusCmd(ctx, "lset", key, index, value) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd { - cmd := NewStatusCmd( - ctx, - "ltrim", - key, - start, - stop, - ) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) RPop(ctx context.Context, key string) *StringCmd { - cmd := NewStringCmd(ctx, "rpop", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) RPopCount(ctx context.Context, key string, count int) *StringSliceCmd { - cmd := NewStringSliceCmd(ctx, "rpop", key, count) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) RPopLPush(ctx context.Context, source, destination string) *StringCmd { - cmd := NewStringCmd(ctx, "rpoplpush", source, destination) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) RPush(ctx context.Context, key string, values ...interface{}) *IntCmd { - args := make([]interface{}, 2, 2+len(values)) - args[0] = "rpush" - args[1] = key - args = appendArgs(args, values) - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd { - args := make([]interface{}, 2, 2+len(values)) - args[0] = "rpushx" - args[1] = key - args = appendArgs(args, values) - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) LMove(ctx context.Context, source, destination, srcpos, destpos string) *StringCmd { - cmd := NewStringCmd(ctx, "lmove", source, destination, srcpos, destpos) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BLMove( - ctx context.Context, source, destination, srcpos, destpos string, timeout time.Duration, -) *StringCmd { - cmd := NewStringCmd(ctx, "blmove", source, destination, srcpos, destpos, formatSec(ctx, timeout)) - cmd.setReadTimeout(timeout) - _ = c(ctx, cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c cmdable) SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd { - args := make([]interface{}, 2, 2+len(members)) - args[0] = "sadd" - args[1] = key - args = appendArgs(args, members) - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SCard(ctx context.Context, key string) *IntCmd { - cmd := NewIntCmd(ctx, "scard", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SDiff(ctx context.Context, keys ...string) *StringSliceCmd { - args := make([]interface{}, 1+len(keys)) - args[0] = "sdiff" - for i, key := range keys { - args[1+i] = key - } - cmd := NewStringSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd { - args := make([]interface{}, 2+len(keys)) - args[0] = "sdiffstore" - args[1] = destination - for i, key := range keys { - args[2+i] = key - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SInter(ctx context.Context, keys ...string) *StringSliceCmd { - args := make([]interface{}, 1+len(keys)) - args[0] = "sinter" - for i, key := range keys { - args[1+i] = key - } - cmd := NewStringSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd { - args := make([]interface{}, 2+len(keys)) - args[0] = "sinterstore" - args[1] = destination - for i, key := range keys { - args[2+i] = key - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd { - cmd := NewBoolCmd(ctx, "sismember", key, member) - _ = c(ctx, cmd) - return cmd -} - -// SMIsMember Redis `SMISMEMBER key member [member ...]` command. -func (c cmdable) SMIsMember(ctx context.Context, key string, members ...interface{}) *BoolSliceCmd { - args := make([]interface{}, 2, 2+len(members)) - args[0] = "smismember" - args[1] = key - args = appendArgs(args, members) - cmd := NewBoolSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -// SMembers Redis `SMEMBERS key` command output as a slice. -func (c cmdable) SMembers(ctx context.Context, key string) *StringSliceCmd { - cmd := NewStringSliceCmd(ctx, "smembers", key) - _ = c(ctx, cmd) - return cmd -} - -// SMembersMap Redis `SMEMBERS key` command output as a map. -func (c cmdable) SMembersMap(ctx context.Context, key string) *StringStructMapCmd { - cmd := NewStringStructMapCmd(ctx, "smembers", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd { - cmd := NewBoolCmd(ctx, "smove", source, destination, member) - _ = c(ctx, cmd) - return cmd -} - -// SPop Redis `SPOP key` command. -func (c cmdable) SPop(ctx context.Context, key string) *StringCmd { - cmd := NewStringCmd(ctx, "spop", key) - _ = c(ctx, cmd) - return cmd -} - -// SPopN Redis `SPOP key count` command. -func (c cmdable) SPopN(ctx context.Context, key string, count int64) *StringSliceCmd { - cmd := NewStringSliceCmd(ctx, "spop", key, count) - _ = c(ctx, cmd) - return cmd -} - -// SRandMember Redis `SRANDMEMBER key` command. -func (c cmdable) SRandMember(ctx context.Context, key string) *StringCmd { - cmd := NewStringCmd(ctx, "srandmember", key) - _ = c(ctx, cmd) - return cmd -} - -// SRandMemberN Redis `SRANDMEMBER key count` command. -func (c cmdable) SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd { - cmd := NewStringSliceCmd(ctx, "srandmember", key, count) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SRem(ctx context.Context, key string, members ...interface{}) *IntCmd { - args := make([]interface{}, 2, 2+len(members)) - args[0] = "srem" - args[1] = key - args = appendArgs(args, members) - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SUnion(ctx context.Context, keys ...string) *StringSliceCmd { - args := make([]interface{}, 1+len(keys)) - args[0] = "sunion" - for i, key := range keys { - args[1+i] = key - } - cmd := NewStringSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd { - args := make([]interface{}, 2+len(keys)) - args[0] = "sunionstore" - args[1] = destination - for i, key := range keys { - args[2+i] = key - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -// XAddArgs accepts values in the following formats: -// - XAddArgs.Values = []interface{}{"key1", "value1", "key2", "value2"} -// - XAddArgs.Values = []string("key1", "value1", "key2", "value2") -// - XAddArgs.Values = map[string]interface{}{"key1": "value1", "key2": "value2"} -// -// Note that map will not preserve the order of key-value pairs. -// MaxLen/MaxLenApprox and MinID are in conflict, only one of them can be used. -type XAddArgs struct { - Stream string - NoMkStream bool - MaxLen int64 // MAXLEN N - MinID string - // Approx causes MaxLen and MinID to use "~" matcher (instead of "="). - Approx bool - Limit int64 - ID string - Values interface{} -} - -// XAdd a.Limit has a bug, please confirm it and use it. -// issue: https://github.com/redis/redis/issues/9046 -func (c cmdable) XAdd(ctx context.Context, a *XAddArgs) *StringCmd { - args := make([]interface{}, 0, 11) - args = append(args, "xadd", a.Stream) - if a.NoMkStream { - args = append(args, "nomkstream") - } - switch { - case a.MaxLen > 0: - if a.Approx { - args = append(args, "maxlen", "~", a.MaxLen) - } else { - args = append(args, "maxlen", a.MaxLen) - } - case a.MinID != "": - if a.Approx { - args = append(args, "minid", "~", a.MinID) - } else { - args = append(args, "minid", a.MinID) - } - } - if a.Limit > 0 { - args = append(args, "limit", a.Limit) - } - if a.ID != "" { - args = append(args, a.ID) - } else { - args = append(args, "*") - } - args = appendArg(args, a.Values) - - cmd := NewStringCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XDel(ctx context.Context, stream string, ids ...string) *IntCmd { - args := []interface{}{"xdel", stream} - for _, id := range ids { - args = append(args, id) - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XLen(ctx context.Context, stream string) *IntCmd { - cmd := NewIntCmd(ctx, "xlen", stream) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd { - cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd { - cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop, "count", count) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XRevRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd { - cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XRevRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd { - cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop, "count", count) - _ = c(ctx, cmd) - return cmd -} - -type XReadArgs struct { - Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2 - Count int64 - Block time.Duration -} - -func (c cmdable) XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd { - args := make([]interface{}, 0, 6+len(a.Streams)) - args = append(args, "xread") - - keyPos := int8(1) - if a.Count > 0 { - args = append(args, "count") - args = append(args, a.Count) - keyPos += 2 - } - if a.Block >= 0 { - args = append(args, "block") - args = append(args, int64(a.Block/time.Millisecond)) - keyPos += 2 - } - args = append(args, "streams") - keyPos++ - for _, s := range a.Streams { - args = append(args, s) - } - - cmd := NewXStreamSliceCmd(ctx, args...) - if a.Block >= 0 { - cmd.setReadTimeout(a.Block) - } - cmd.SetFirstKeyPos(keyPos) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd { - return c.XRead(ctx, &XReadArgs{ - Streams: streams, - Block: -1, - }) -} - -func (c cmdable) XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd { - cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd { - cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start, "mkstream") - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd { - cmd := NewStatusCmd(ctx, "xgroup", "setid", stream, group, start) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XGroupDestroy(ctx context.Context, stream, group string) *IntCmd { - cmd := NewIntCmd(ctx, "xgroup", "destroy", stream, group) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XGroupCreateConsumer(ctx context.Context, stream, group, consumer string) *IntCmd { - cmd := NewIntCmd(ctx, "xgroup", "createconsumer", stream, group, consumer) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd { - cmd := NewIntCmd(ctx, "xgroup", "delconsumer", stream, group, consumer) - _ = c(ctx, cmd) - return cmd -} - -type XReadGroupArgs struct { - Group string - Consumer string - Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2 - Count int64 - Block time.Duration - NoAck bool -} - -func (c cmdable) XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd { - args := make([]interface{}, 0, 10+len(a.Streams)) - args = append(args, "xreadgroup", "group", a.Group, a.Consumer) - - keyPos := int8(4) - if a.Count > 0 { - args = append(args, "count", a.Count) - keyPos += 2 - } - if a.Block >= 0 { - args = append(args, "block", int64(a.Block/time.Millisecond)) - keyPos += 2 - } - if a.NoAck { - args = append(args, "noack") - keyPos++ - } - args = append(args, "streams") - keyPos++ - for _, s := range a.Streams { - args = append(args, s) - } - - cmd := NewXStreamSliceCmd(ctx, args...) - if a.Block >= 0 { - cmd.setReadTimeout(a.Block) - } - cmd.SetFirstKeyPos(keyPos) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd { - args := []interface{}{"xack", stream, group} - for _, id := range ids { - args = append(args, id) - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XPending(ctx context.Context, stream, group string) *XPendingCmd { - cmd := NewXPendingCmd(ctx, "xpending", stream, group) - _ = c(ctx, cmd) - return cmd -} - -type XPendingExtArgs struct { - Stream string - Group string - Idle time.Duration - Start string - End string - Count int64 - Consumer string -} - -func (c cmdable) XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd { - args := make([]interface{}, 0, 9) - args = append(args, "xpending", a.Stream, a.Group) - if a.Idle != 0 { - args = append(args, "idle", formatMs(ctx, a.Idle)) - } - args = append(args, a.Start, a.End, a.Count) - if a.Consumer != "" { - args = append(args, a.Consumer) - } - cmd := NewXPendingExtCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -type XAutoClaimArgs struct { - Stream string - Group string - MinIdle time.Duration - Start string - Count int64 - Consumer string -} - -func (c cmdable) XAutoClaim(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimCmd { - args := xAutoClaimArgs(ctx, a) - cmd := NewXAutoClaimCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XAutoClaimJustID(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimJustIDCmd { - args := xAutoClaimArgs(ctx, a) - args = append(args, "justid") - cmd := NewXAutoClaimJustIDCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func xAutoClaimArgs(ctx context.Context, a *XAutoClaimArgs) []interface{} { - args := make([]interface{}, 0, 8) - args = append(args, "xautoclaim", a.Stream, a.Group, a.Consumer, formatMs(ctx, a.MinIdle), a.Start) - if a.Count > 0 { - args = append(args, "count", a.Count) - } - return args -} - -type XClaimArgs struct { - Stream string - Group string - Consumer string - MinIdle time.Duration - Messages []string -} - -func (c cmdable) XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd { - args := xClaimArgs(a) - cmd := NewXMessageSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd { - args := xClaimArgs(a) - args = append(args, "justid") - cmd := NewStringSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func xClaimArgs(a *XClaimArgs) []interface{} { - args := make([]interface{}, 0, 5+len(a.Messages)) - args = append(args, - "xclaim", - a.Stream, - a.Group, a.Consumer, - int64(a.MinIdle/time.Millisecond)) - for _, id := range a.Messages { - args = append(args, id) - } - return args -} - -// xTrim If approx is true, add the "~" parameter, otherwise it is the default "=" (redis default). -// example: -// XTRIM key MAXLEN/MINID threshold LIMIT limit. -// XTRIM key MAXLEN/MINID ~ threshold LIMIT limit. -// The redis-server version is lower than 6.2, please set limit to 0. -func (c cmdable) xTrim( - ctx context.Context, key, strategy string, - approx bool, threshold interface{}, limit int64, -) *IntCmd { - args := make([]interface{}, 0, 7) - args = append(args, "xtrim", key, strategy) - if approx { - args = append(args, "~") - } - args = append(args, threshold) - if limit > 0 { - args = append(args, "limit", limit) - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -// XTrimMaxLen No `~` rules are used, `limit` cannot be used. -// cmd: XTRIM key MAXLEN maxLen -func (c cmdable) XTrimMaxLen(ctx context.Context, key string, maxLen int64) *IntCmd { - return c.xTrim(ctx, key, "maxlen", false, maxLen, 0) -} - -// XTrimMaxLenApprox LIMIT has a bug, please confirm it and use it. -// issue: https://github.com/redis/redis/issues/9046 -// cmd: XTRIM key MAXLEN ~ maxLen LIMIT limit -func (c cmdable) XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *IntCmd { - return c.xTrim(ctx, key, "maxlen", true, maxLen, limit) -} - -// XTrimMinID No `~` rules are used, `limit` cannot be used. -// cmd: XTRIM key MINID minID -func (c cmdable) XTrimMinID(ctx context.Context, key string, minID string) *IntCmd { - return c.xTrim(ctx, key, "minid", false, minID, 0) -} - -// XTrimMinIDApprox LIMIT has a bug, please confirm it and use it. -// issue: https://github.com/redis/redis/issues/9046 -// cmd: XTRIM key MINID ~ minID LIMIT limit -func (c cmdable) XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *IntCmd { - return c.xTrim(ctx, key, "minid", true, minID, limit) -} - -func (c cmdable) XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd { - cmd := NewXInfoConsumersCmd(ctx, key, group) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd { - cmd := NewXInfoGroupsCmd(ctx, key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) XInfoStream(ctx context.Context, key string) *XInfoStreamCmd { - cmd := NewXInfoStreamCmd(ctx, key) - _ = c(ctx, cmd) - return cmd -} - -// XInfoStreamFull XINFO STREAM FULL [COUNT count] -// redis-server >= 6.0. -func (c cmdable) XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd { - args := make([]interface{}, 0, 6) - args = append(args, "xinfo", "stream", key, "full") - if count > 0 { - args = append(args, "count", count) - } - cmd := NewXInfoStreamFullCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -// Z represents sorted set member. -type Z struct { - Score float64 - Member interface{} -} - -// ZWithKey represents sorted set member including the name of the key where it was popped. -type ZWithKey struct { - Z - Key string -} - -// ZStore is used as an arg to ZInter/ZInterStore and ZUnion/ZUnionStore. -type ZStore struct { - Keys []string - Weights []float64 - // Can be SUM, MIN or MAX. - Aggregate string -} - -func (z ZStore) len() (n int) { - n = len(z.Keys) - if len(z.Weights) > 0 { - n += 1 + len(z.Weights) - } - if z.Aggregate != "" { - n += 2 - } - return n -} - -func (z ZStore) appendArgs(args []interface{}) []interface{} { - for _, key := range z.Keys { - args = append(args, key) - } - if len(z.Weights) > 0 { - args = append(args, "weights") - for _, weights := range z.Weights { - args = append(args, weights) - } - } - if z.Aggregate != "" { - args = append(args, "aggregate", z.Aggregate) - } - return args -} - -// BZPopMax Redis `BZPOPMAX key [key ...] timeout` command. -func (c cmdable) BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd { - args := make([]interface{}, 1+len(keys)+1) - args[0] = "bzpopmax" - for i, key := range keys { - args[1+i] = key - } - args[len(args)-1] = formatSec(ctx, timeout) - cmd := NewZWithKeyCmd(ctx, args...) - cmd.setReadTimeout(timeout) - _ = c(ctx, cmd) - return cmd -} - -// BZPopMin Redis `BZPOPMIN key [key ...] timeout` command. -func (c cmdable) BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd { - args := make([]interface{}, 1+len(keys)+1) - args[0] = "bzpopmin" - for i, key := range keys { - args[1+i] = key - } - args[len(args)-1] = formatSec(ctx, timeout) - cmd := NewZWithKeyCmd(ctx, args...) - cmd.setReadTimeout(timeout) - _ = c(ctx, cmd) - return cmd -} - -// ZAddArgs WARN: The GT, LT and NX options are mutually exclusive. -type ZAddArgs struct { - NX bool - XX bool - LT bool - GT bool - Ch bool - Members []Z -} - -func (c cmdable) zAddArgs(key string, args ZAddArgs, incr bool) []interface{} { - a := make([]interface{}, 0, 6+2*len(args.Members)) - a = append(a, "zadd", key) - - // The GT, LT and NX options are mutually exclusive. - if args.NX { - a = append(a, "nx") - } else { - if args.XX { - a = append(a, "xx") - } - if args.GT { - a = append(a, "gt") - } else if args.LT { - a = append(a, "lt") - } - } - if args.Ch { - a = append(a, "ch") - } - if incr { - a = append(a, "incr") - } - for _, m := range args.Members { - a = append(a, m.Score) - a = append(a, m.Member) - } - return a -} - -func (c cmdable) ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd { - cmd := NewIntCmd(ctx, c.zAddArgs(key, args, false)...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd { - cmd := NewFloatCmd(ctx, c.zAddArgs(key, args, true)...) - _ = c(ctx, cmd) - return cmd -} - -// ZAdd Redis `ZADD key score member [score member ...]` command. -func (c cmdable) ZAdd(ctx context.Context, key string, members ...Z) *IntCmd { - return c.ZAddArgs(ctx, key, ZAddArgs{ - Members: members, - }) -} - -// ZAddNX Redis `ZADD key NX score member [score member ...]` command. -func (c cmdable) ZAddNX(ctx context.Context, key string, members ...Z) *IntCmd { - return c.ZAddArgs(ctx, key, ZAddArgs{ - NX: true, - Members: members, - }) -} - -// ZAddXX Redis `ZADD key XX score member [score member ...]` command. -func (c cmdable) ZAddXX(ctx context.Context, key string, members ...Z) *IntCmd { - return c.ZAddArgs(ctx, key, ZAddArgs{ - XX: true, - Members: members, - }) -} - -func (c cmdable) ZCard(ctx context.Context, key string) *IntCmd { - cmd := NewIntCmd(ctx, "zcard", key) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZCount(ctx context.Context, key, min, max string) *IntCmd { - cmd := NewIntCmd(ctx, "zcount", key, min, max) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZLexCount(ctx context.Context, key, min, max string) *IntCmd { - cmd := NewIntCmd(ctx, "zlexcount", key, min, max) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd { - cmd := NewFloatCmd(ctx, "zincrby", key, increment, member) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd { - args := make([]interface{}, 0, 3+store.len()) - args = append(args, "zinterstore", destination, len(store.Keys)) - args = store.appendArgs(args) - cmd := NewIntCmd(ctx, args...) - cmd.SetFirstKeyPos(3) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZInter(ctx context.Context, store *ZStore) *StringSliceCmd { - args := make([]interface{}, 0, 2+store.len()) - args = append(args, "zinter", len(store.Keys)) - args = store.appendArgs(args) - cmd := NewStringSliceCmd(ctx, args...) - cmd.SetFirstKeyPos(2) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd { - args := make([]interface{}, 0, 3+store.len()) - args = append(args, "zinter", len(store.Keys)) - args = store.appendArgs(args) - args = append(args, "withscores") - cmd := NewZSliceCmd(ctx, args...) - cmd.SetFirstKeyPos(2) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd { - args := make([]interface{}, 2+len(members)) - args[0] = "zmscore" - args[1] = key - for i, member := range members { - args[2+i] = member - } - cmd := NewFloatSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd { - args := []interface{}{ - "zpopmax", - key, - } - - switch len(count) { - case 0: - break - case 1: - args = append(args, count[0]) - default: - panic("too many arguments") - } - - cmd := NewZSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd { - args := []interface{}{ - "zpopmin", - key, - } - - switch len(count) { - case 0: - break - case 1: - args = append(args, count[0]) - default: - panic("too many arguments") - } - - cmd := NewZSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -// ZRangeArgs is all the options of the ZRange command. -// In version> 6.2.0, you can replace the(cmd): -// ZREVRANGE, -// ZRANGEBYSCORE, -// ZREVRANGEBYSCORE, -// ZRANGEBYLEX, -// ZREVRANGEBYLEX. -// Please pay attention to your redis-server version. -// -// Rev, ByScore, ByLex and Offset+Count options require redis-server 6.2.0 and higher. -type ZRangeArgs struct { - Key string - - // When the ByScore option is provided, the open interval(exclusive) can be set. - // By default, the score intervals specified by and are closed (inclusive). - // It is similar to the deprecated(6.2.0+) ZRangeByScore command. - // For example: - // ZRangeArgs{ - // Key: "example-key", - // Start: "(3", - // Stop: 8, - // ByScore: true, - // } - // cmd: "ZRange example-key (3 8 ByScore" (3 < score <= 8). - // - // For the ByLex option, it is similar to the deprecated(6.2.0+) ZRangeByLex command. - // You can set the and options as follows: - // ZRangeArgs{ - // Key: "example-key", - // Start: "[abc", - // Stop: "(def", - // ByLex: true, - // } - // cmd: "ZRange example-key [abc (def ByLex" - // - // For normal cases (ByScore==false && ByLex==false), and should be set to the index range (int). - // You can read the documentation for more information: https://redis.io/commands/zrange - Start interface{} - Stop interface{} - - // The ByScore and ByLex options are mutually exclusive. - ByScore bool - ByLex bool - - Rev bool - - // limit offset count. - Offset int64 - Count int64 -} - -func (z ZRangeArgs) appendArgs(args []interface{}) []interface{} { - // For Rev+ByScore/ByLex, we need to adjust the position of and . - if z.Rev && (z.ByScore || z.ByLex) { - args = append(args, z.Key, z.Stop, z.Start) - } else { - args = append(args, z.Key, z.Start, z.Stop) - } - - if z.ByScore { - args = append(args, "byscore") - } else if z.ByLex { - args = append(args, "bylex") - } - if z.Rev { - args = append(args, "rev") - } - if z.Offset != 0 || z.Count != 0 { - args = append(args, "limit", z.Offset, z.Count) - } - return args -} - -func (c cmdable) ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd { - args := make([]interface{}, 0, 9) - args = append(args, "zrange") - args = z.appendArgs(args) - cmd := NewStringSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd { - args := make([]interface{}, 0, 10) - args = append(args, "zrange") - args = z.appendArgs(args) - args = append(args, "withscores") - cmd := NewZSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd { - return c.ZRangeArgs(ctx, ZRangeArgs{ - Key: key, - Start: start, - Stop: stop, - }) -} - -func (c cmdable) ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd { - return c.ZRangeArgsWithScores(ctx, ZRangeArgs{ - Key: key, - Start: start, - Stop: stop, - }) -} - -type ZRangeBy struct { - Min, Max string - Offset, Count int64 -} - -func (c cmdable) zRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy, withScores bool) *StringSliceCmd { - args := []interface{}{zcmd, key, opt.Min, opt.Max} - if withScores { - args = append(args, "withscores") - } - if opt.Offset != 0 || opt.Count != 0 { - args = append( - args, - "limit", - opt.Offset, - opt.Count, - ) - } - cmd := NewStringSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd { - return c.zRangeBy(ctx, "zrangebyscore", key, opt, false) -} - -func (c cmdable) ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd { - return c.zRangeBy(ctx, "zrangebylex", key, opt, false) -} - -func (c cmdable) ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd { - args := []interface{}{"zrangebyscore", key, opt.Min, opt.Max, "withscores"} - if opt.Offset != 0 || opt.Count != 0 { - args = append( - args, - "limit", - opt.Offset, - opt.Count, - ) - } - cmd := NewZSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd { - args := make([]interface{}, 0, 10) - args = append(args, "zrangestore", dst) - args = z.appendArgs(args) - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZRank(ctx context.Context, key, member string) *IntCmd { - cmd := NewIntCmd(ctx, "zrank", key, member) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd { - args := make([]interface{}, 2, 2+len(members)) - args[0] = "zrem" - args[1] = key - args = appendArgs(args, members) - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd { - cmd := NewIntCmd( - ctx, - "zremrangebyrank", - key, - start, - stop, - ) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd { - cmd := NewIntCmd(ctx, "zremrangebyscore", key, min, max) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd { - cmd := NewIntCmd(ctx, "zremrangebylex", key, min, max) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd { - cmd := NewStringSliceCmd(ctx, "zrevrange", key, start, stop) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd { - cmd := NewZSliceCmd(ctx, "zrevrange", key, start, stop, "withscores") - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) zRevRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy) *StringSliceCmd { - args := []interface{}{zcmd, key, opt.Max, opt.Min} - if opt.Offset != 0 || opt.Count != 0 { - args = append( - args, - "limit", - opt.Offset, - opt.Count, - ) - } - cmd := NewStringSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd { - return c.zRevRangeBy(ctx, "zrevrangebyscore", key, opt) -} - -func (c cmdable) ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd { - return c.zRevRangeBy(ctx, "zrevrangebylex", key, opt) -} - -func (c cmdable) ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd { - args := []interface{}{"zrevrangebyscore", key, opt.Max, opt.Min, "withscores"} - if opt.Offset != 0 || opt.Count != 0 { - args = append( - args, - "limit", - opt.Offset, - opt.Count, - ) - } - cmd := NewZSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZRevRank(ctx context.Context, key, member string) *IntCmd { - cmd := NewIntCmd(ctx, "zrevrank", key, member) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZScore(ctx context.Context, key, member string) *FloatCmd { - cmd := NewFloatCmd(ctx, "zscore", key, member) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZUnion(ctx context.Context, store ZStore) *StringSliceCmd { - args := make([]interface{}, 0, 2+store.len()) - args = append(args, "zunion", len(store.Keys)) - args = store.appendArgs(args) - cmd := NewStringSliceCmd(ctx, args...) - cmd.SetFirstKeyPos(2) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd { - args := make([]interface{}, 0, 3+store.len()) - args = append(args, "zunion", len(store.Keys)) - args = store.appendArgs(args) - args = append(args, "withscores") - cmd := NewZSliceCmd(ctx, args...) - cmd.SetFirstKeyPos(2) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd { - args := make([]interface{}, 0, 3+store.len()) - args = append(args, "zunionstore", dest, len(store.Keys)) - args = store.appendArgs(args) - cmd := NewIntCmd(ctx, args...) - cmd.SetFirstKeyPos(3) - _ = c(ctx, cmd) - return cmd -} - -// ZRandMember redis-server version >= 6.2.0. -func (c cmdable) ZRandMember(ctx context.Context, key string, count int) *StringSliceCmd { - cmd := NewStringSliceCmd(ctx, "zrandmember", key, count) - _ = c(ctx, cmd) - return cmd -} - -// ZRandMemberWithScores redis-server version >= 6.2.0. -func (c cmdable) ZRandMemberWithScores(ctx context.Context, key string, count int) *ZSliceCmd { - cmd := NewZSliceCmd(ctx, "zrandmember", key, count, "withscores") - _ = c(ctx, cmd) - return cmd -} - -// ZDiff redis-server version >= 6.2.0. -func (c cmdable) ZDiff(ctx context.Context, keys ...string) *StringSliceCmd { - args := make([]interface{}, 2+len(keys)) - args[0] = "zdiff" - args[1] = len(keys) - for i, key := range keys { - args[i+2] = key - } - - cmd := NewStringSliceCmd(ctx, args...) - cmd.SetFirstKeyPos(2) - _ = c(ctx, cmd) - return cmd -} - -// ZDiffWithScores redis-server version >= 6.2.0. -func (c cmdable) ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd { - args := make([]interface{}, 3+len(keys)) - args[0] = "zdiff" - args[1] = len(keys) - for i, key := range keys { - args[i+2] = key - } - args[len(keys)+2] = "withscores" - - cmd := NewZSliceCmd(ctx, args...) - cmd.SetFirstKeyPos(2) - _ = c(ctx, cmd) - return cmd -} - -// ZDiffStore redis-server version >=6.2.0. -func (c cmdable) ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd { - args := make([]interface{}, 0, 3+len(keys)) - args = append(args, "zdiffstore", destination, len(keys)) - for _, key := range keys { - args = append(args, key) - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c cmdable) PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd { - args := make([]interface{}, 2, 2+len(els)) - args[0] = "pfadd" - args[1] = key - args = appendArgs(args, els) - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) PFCount(ctx context.Context, keys ...string) *IntCmd { - args := make([]interface{}, 1+len(keys)) - args[0] = "pfcount" - for i, key := range keys { - args[1+i] = key - } - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd { - args := make([]interface{}, 2+len(keys)) - args[0] = "pfmerge" - args[1] = dest - for i, key := range keys { - args[2+i] = key - } - cmd := NewStatusCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c cmdable) BgRewriteAOF(ctx context.Context) *StatusCmd { - cmd := NewStatusCmd(ctx, "bgrewriteaof") - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BgSave(ctx context.Context) *StatusCmd { - cmd := NewStatusCmd(ctx, "bgsave") - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) ClientKill(ctx context.Context, ipPort string) *StatusCmd { - cmd := NewStatusCmd(ctx, "client", "kill", ipPort) - _ = c(ctx, cmd) - return cmd -} - -// ClientKillByFilter is new style syntax, while the ClientKill is old -// -// CLIENT KILL