- update vendor

master
李光春 9 months ago
parent 0e505abfd7
commit 1099e35ff9

@ -4,18 +4,18 @@ go 1.20
require ( require (
github.com/MercuryEngineering/CookieMonster v0.0.0-20180304172713-1584578b3403 github.com/MercuryEngineering/CookieMonster v0.0.0-20180304172713-1584578b3403
github.com/aliyun/aliyun-oss-go-sdk v2.2.8+incompatible github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible
github.com/allegro/bigcache/v3 v3.1.0 github.com/allegro/bigcache/v3 v3.1.0
github.com/baidubce/bce-sdk-go v0.9.154 github.com/baidubce/bce-sdk-go v0.9.156
github.com/basgys/goxml2json v1.1.0 github.com/basgys/goxml2json v1.1.0
github.com/bytedance/sonic v1.10.0-rc3 github.com/bytedance/sonic v1.10.0
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.9.1
github.com/go-playground/locales v0.14.1 github.com/go-playground/locales v0.14.1
github.com/go-playground/universal-translator v0.18.1 github.com/go-playground/universal-translator v0.18.1
github.com/go-playground/validator/v10 v10.14.1 github.com/go-playground/validator/v10 v10.15.1
github.com/go-sql-driver/mysql v1.7.1 github.com/go-sql-driver/mysql v1.7.1
github.com/goccy/go-json v0.10.2 github.com/goccy/go-json v0.10.2
github.com/gogf/gf/v2 v2.5.1 github.com/gogf/gf/v2 v2.5.2
github.com/json-iterator/go v1.1.12 github.com/json-iterator/go v1.1.12
github.com/lib/pq v1.10.9 github.com/lib/pq v1.10.9
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
@ -23,7 +23,7 @@ require (
github.com/natefinch/lumberjack v2.0.0+incompatible github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/oschwald/geoip2-golang v1.9.0 github.com/oschwald/geoip2-golang v1.9.0
github.com/qiniu/go-sdk/v7 v7.17.0 github.com/qiniu/go-sdk/v7 v7.17.0
github.com/redis/go-redis/v9 v9.0.5 github.com/redis/go-redis/v9 v9.1.0
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/saracen/go7z v0.0.0-20191010121135-9c09b6bd7fda github.com/saracen/go7z v0.0.0-20191010121135-9c09b6bd7fda
github.com/shirou/gopsutil v3.21.11+incompatible github.com/shirou/gopsutil v3.21.11+incompatible
@ -32,14 +32,14 @@ require (
go.mongodb.org/mongo-driver v1.12.1 go.mongodb.org/mongo-driver v1.12.1
go.uber.org/zap v1.25.0 go.uber.org/zap v1.25.0
golang.org/x/crypto v0.12.0 golang.org/x/crypto v0.12.0
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
golang.org/x/text v0.12.0 golang.org/x/text v0.12.0
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gorm.io/datatypes v1.2.0 gorm.io/datatypes v1.2.0
gorm.io/driver/mysql v1.5.1 gorm.io/driver/mysql v1.5.1
gorm.io/driver/postgres v1.5.2 gorm.io/driver/postgres v1.5.2
gorm.io/gen v0.3.23 gorm.io/gen v0.3.23
gorm.io/gorm v1.25.2 gorm.io/gorm v1.25.4
xorm.io/builder v0.3.13 xorm.io/builder v0.3.13
xorm.io/xorm v1.3.2 xorm.io/xorm v1.3.2
) )
@ -50,7 +50,6 @@ require (
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/chenzhuoyu/iasm v0.9.0 // indirect
github.com/clbanning/mxj v1.8.4 // indirect github.com/clbanning/mxj v1.8.4 // indirect
github.com/clbanning/mxj/v2 v2.5.7 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fatih/color v1.15.0 // indirect github.com/fatih/color v1.15.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
@ -58,12 +57,12 @@ require (
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.3.0 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.4.2 // indirect github.com/jackc/pgx/v5 v5.4.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/compress v1.16.7 // indirect
@ -82,7 +81,7 @@ require (
github.com/saracen/go7z-fixtures v0.0.0-20190623165746-aa6b8fba1d2f // indirect github.com/saracen/go7z-fixtures v0.0.0-20190623165746-aa6b8fba1d2f // indirect
github.com/saracen/solidblock v0.0.0-20190426153529-45df20abab6f // indirect github.com/saracen/solidblock v0.0.0-20190426153529-45df20abab6f // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect github.com/tklauser/numcpus v0.6.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect github.com/ugorji/go/codec v1.2.11 // indirect
@ -103,12 +102,12 @@ require (
golang.org/x/sync v0.3.0 // indirect golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.11.0 // indirect golang.org/x/sys v0.11.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.11.1 // indirect golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect
google.golang.org/protobuf v1.31.0 // indirect google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/hints v1.1.2 // indirect gorm.io/hints v1.1.2 // indirect
gorm.io/plugin/dbresolver v1.4.2 // indirect gorm.io/plugin/dbresolver v1.4.7 // indirect
) )

@ -4,8 +4,7 @@ gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGq
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE= gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/MercuryEngineering/CookieMonster v0.0.0-20180304172713-1584578b3403 h1:EtZwYyLbkEcIt+B//6sujwRCnHuTEK3qiSypAX5aJeM= github.com/MercuryEngineering/CookieMonster v0.0.0-20180304172713-1584578b3403 h1:EtZwYyLbkEcIt+B//6sujwRCnHuTEK3qiSypAX5aJeM=
@ -19,8 +18,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/aliyun/aliyun-oss-go-sdk v2.2.8+incompatible h1:6JF1bjhT0WN2srEmijfOFtVWwV91KZ6dJY1/JbdtGrI= github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible h1:Sg/2xHwDrioHpxTN6WMiwbXTpUEinBpHsN7mG21Rc2k=
github.com/aliyun/aliyun-oss-go-sdk v2.2.8+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk= github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk=
github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I= github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
@ -32,8 +31,8 @@ github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6l
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/baidubce/bce-sdk-go v0.9.154 h1:MKGCBV7EpDoQDwpn8X6L/SiEcii7twwWTBd241e4f5I= github.com/baidubce/bce-sdk-go v0.9.156 h1:f++WfptxGmSp5acsjl4kUxHpWDDccoFqkIrQKxvp/Sw=
github.com/baidubce/bce-sdk-go v0.9.154/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= github.com/baidubce/bce-sdk-go v0.9.156/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
github.com/basgys/goxml2json v1.1.0 h1:4ln5i4rseYfXNd86lGEB+Vi652IsIXIvggKM/BhUKVw= github.com/basgys/goxml2json v1.1.0 h1:4ln5i4rseYfXNd86lGEB+Vi652IsIXIvggKM/BhUKVw=
github.com/basgys/goxml2json v1.1.0/go.mod h1:wH7a5Np/Q4QoECFIU8zTQlZwZkrilY0itPfecMw41Dw= github.com/basgys/goxml2json v1.1.0/go.mod h1:wH7a5Np/Q4QoECFIU8zTQlZwZkrilY0itPfecMw41Dw=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
@ -43,12 +42,12 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao= github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0=
github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
github.com/bytedance/sonic v1.10.0-rc3 h1:uNSnscRapXTwUgTyOF0GVljYD08p9X/Lbr9MweSV3V0= github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk=
github.com/bytedance/sonic v1.10.0-rc3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/bytedance/sonic v1.10.0/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@ -63,9 +62,7 @@ github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I= github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I=
github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
github.com/clbanning/mxj/v2 v2.5.7 h1:7q5lvUpaPF/WOkqgIDiwjBJaznaLCCBd78pi8ZyAnE0=
github.com/clbanning/mxj/v2 v2.5.7/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
@ -96,13 +93,11 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
@ -119,13 +114,13 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
@ -137,8 +132,8 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk= github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk=
github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= github.com/go-playground/validator/v10 v10.15.1 h1:BSe8uhN+xQ4r5guV/ywQI4gO59C2raYcGffYWZEjZzM=
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-playground/validator/v10 v10.15.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
@ -150,8 +145,8 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogf/gf/v2 v2.5.1 h1:mkmqWrKTsuLRnv4OL1CS9voPMqfSx/DSY7JJnd/HnfA= github.com/gogf/gf/v2 v2.5.2 h1:fACJE7DJH6iTGHGhgiNY1uuZIZtr2IqQkJ52E+wBnt8=
github.com/gogf/gf/v2 v2.5.1/go.mod h1:9XLWIkCQmaWIugHag4AEOtex0LlVeUHsUxqjAC8f6ew= github.com/gogf/gf/v2 v2.5.2/go.mod h1:7yf5qp0BznfsYx7Sw49m3mQvBsHpwAjJk3Q9ZnKoUEc=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@ -179,7 +174,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
@ -196,9 +190,7 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0= github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@ -272,8 +264,8 @@ github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc= github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc=
github.com/jackc/pgx/v4 v4.12.0/go.mod h1:fE547h6VulLPA3kySjfnSG/e2D861g/50JlVUa/ub60= github.com/jackc/pgx/v4 v4.12.0/go.mod h1:fE547h6VulLPA3kySjfnSG/e2D861g/50JlVUa/ub60=
github.com/jackc/pgx/v5 v5.4.2 h1:u1gmGDwbdRUZiwisBm/Ky2M14uQyUP65bG8+20nnyrg= github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
github.com/jackc/pgx/v5 v5.4.2/go.mod h1:q6iHT8uDNXWiFNOlRqJzBTaSH3+2xCXkokxHZC5qWFY= github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
@ -330,12 +322,10 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 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.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.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
@ -345,13 +335,11 @@ 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.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.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.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
@ -399,7 +387,6 @@ github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtb
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@ -454,10 +441,11 @@ github.com/qiniu/go-sdk/v7 v7.17.0 h1:sF05b0NFdlUEz1SnJStrOn+PVUPu76lYCoHZCZyNYg
github.com/qiniu/go-sdk/v7 v7.17.0/go.mod h1:nqoYCNo53ZlGA521RvRethvxUDvXKt4gtYXOwye868w= github.com/qiniu/go-sdk/v7 v7.17.0/go.mod h1:nqoYCNo53ZlGA521RvRethvxUDvXKt4gtYXOwye868w=
github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs= github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o= github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY=
github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@ -523,9 +511,8 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0=
github.com/tencentyun/cos-go-sdk-v5 v0.7.42 h1:Up1704BJjI5orycXKjpVpvuOInt9GC5pqY4knyE9Uds= github.com/tencentyun/cos-go-sdk-v5 v0.7.42 h1:Up1704BJjI5orycXKjpVpvuOInt9GC5pqY4knyE9Uds=
github.com/tencentyun/cos-go-sdk-v5 v0.7.42/go.mod h1:LUFnaqRmGk6pEHOaRmdn2dCZR2j0cSsM5xowWFPTPao= github.com/tencentyun/cos-go-sdk-v5 v0.7.42/go.mod h1:LUFnaqRmGk6pEHOaRmdn2dCZR2j0cSsM5xowWFPTPao=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@ -548,7 +535,6 @@ github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7Jul
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
@ -561,15 +547,12 @@ go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU=
go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE=
go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4=
go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@ -614,8 +597,8 @@ golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b h1:r+vk0EmXNmekl0S0BascoeeoHk/L7wmaW2QF90K+kYI= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -624,7 +607,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
@ -646,7 +628,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
@ -661,7 +642,6 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
@ -691,20 +671,16 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/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-20210902050250-f475640dd07b/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-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -721,7 +697,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
@ -748,10 +723,9 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.11.1 h1:ojD5zOW8+7dOGzdnNgersm8aPfcDjhMp12UfG93NIMc= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E=
golang.org/x/tools v0.11.1/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -825,12 +799,13 @@ gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho=
gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw=
gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/hints v1.1.2 h1:b5j0kwk5p4+3BtDtYqqfY+ATSxjj+6ptPgVveuynn9o= gorm.io/hints v1.1.2 h1:b5j0kwk5p4+3BtDtYqqfY+ATSxjj+6ptPgVveuynn9o=
gorm.io/hints v1.1.2/go.mod h1:/ARdpUHAtyEMCh5NNi3tI7FsGh+Cj/MIUlvNxCNCFWg= gorm.io/hints v1.1.2/go.mod h1:/ARdpUHAtyEMCh5NNi3tI7FsGh+Cj/MIUlvNxCNCFWg=
gorm.io/plugin/dbresolver v1.4.2 h1:IeLSH20ayxbo4rN6HMIQ0ccdsh/fkLK23pp6ivZrqBI= gorm.io/plugin/dbresolver v1.4.7 h1:ZwtwmJQxTx9us7o6zEHFvH1q4OeEo1pooU7efmnunJA=
gorm.io/plugin/dbresolver v1.4.2/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0= gorm.io/plugin/dbresolver v1.4.7/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

@ -1,5 +1,5 @@
package go_library package go_library
func Version() string { func Version() string {
return "1.0.158" return "1.0.159"
} }

@ -2,6 +2,7 @@ package oss
import ( import (
"bytes" "bytes"
"context"
"crypto/md5" "crypto/md5"
"encoding/base64" "encoding/base64"
"encoding/xml" "encoding/xml"
@ -29,11 +30,11 @@ type Bucket struct {
// objectKey the object key in UTF-8 encoding. The length must be between 1 and 1023, and cannot start with "/" or "\". // objectKey the object key in UTF-8 encoding. The length must be between 1 and 1023, and cannot start with "/" or "\".
// reader io.Reader instance for reading the data for uploading // reader io.Reader instance for reading the data for uploading
// options the options for uploading the object. The valid options here are CacheControl, ContentDisposition, ContentEncoding // options the options for uploading the object. The valid options here are CacheControl, ContentDisposition, ContentEncoding
// Expires, ServerSideEncryption, ObjectACL and Meta. Refer to the link below for more details.
// https://www.alibabacloud.com/help/en/object-storage-service/latest/putobject
// //
// error it's nil if no error, otherwise it's an error object. // Expires, ServerSideEncryption, ObjectACL and Meta. Refer to the link below for more details.
// https://www.alibabacloud.com/help/en/object-storage-service/latest/putobject
// //
// error it's nil if no error, otherwise it's an error object.
func (bucket Bucket) PutObject(objectKey string, reader io.Reader, options ...Option) error { func (bucket Bucket) PutObject(objectKey string, reader io.Reader, options ...Option) error {
opts := AddContentType(options, objectKey) opts := AddContentType(options, objectKey)
@ -57,7 +58,6 @@ func (bucket Bucket) PutObject(objectKey string, reader io.Reader, options ...Op
// options the options for uploading the object. Refer to the parameter options in PutObject for more details. // options the options for uploading the object. Refer to the parameter options in PutObject for more details.
// //
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) PutObjectFromFile(objectKey, filePath string, options ...Option) error { func (bucket Bucket) PutObjectFromFile(objectKey, filePath string, options ...Option) error {
fd, err := os.Open(filePath) fd, err := os.Open(filePath)
if err != nil { if err != nil {
@ -87,7 +87,6 @@ func (bucket Bucket) PutObjectFromFile(objectKey, filePath string, options ...Op
// //
// Response the response from OSS. // Response the response from OSS.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DoPutObject(request *PutObjectRequest, options []Option) (*Response, error) { func (bucket Bucket) DoPutObject(request *PutObjectRequest, options []Option) (*Response, error) {
isOptSet, _, _ := IsOptionSet(options, HTTPHeaderContentType) isOptSet, _, _ := IsOptionSet(options, HTTPHeaderContentType)
if !isOptSet { if !isOptSet {
@ -118,12 +117,12 @@ func (bucket Bucket) DoPutObject(request *PutObjectRequest, options []Option) (*
// //
// objectKey the object key. // objectKey the object key.
// options the options for downloading the object. The valid values are: Range, IfModifiedSince, IfUnmodifiedSince, IfMatch, // options the options for downloading the object. The valid values are: Range, IfModifiedSince, IfUnmodifiedSince, IfMatch,
// IfNoneMatch, AcceptEncoding. For more details, please check out: //
// https://www.alibabacloud.com/help/en/object-storage-service/latest/getobject // IfNoneMatch, AcceptEncoding. For more details, please check out:
// https://www.alibabacloud.com/help/en/object-storage-service/latest/getobject
// //
// io.ReadCloser reader instance for reading data from response. It must be called close() after the usage and only valid when error is nil. // io.ReadCloser reader instance for reading data from response. It must be called close() after the usage and only valid when error is nil.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObject(objectKey string, options ...Option) (io.ReadCloser, error) { func (bucket Bucket) GetObject(objectKey string, options ...Option) (io.ReadCloser, error) {
result, err := bucket.DoGetObject(&GetObjectRequest{objectKey}, options) result, err := bucket.DoGetObject(&GetObjectRequest{objectKey}, options)
if err != nil { if err != nil {
@ -140,7 +139,6 @@ func (bucket Bucket) GetObject(objectKey string, options ...Option) (io.ReadClos
// options the options for downloading the object. Refer to the parameter options in method GetObject for more details. // options the options for downloading the object. Refer to the parameter options in method GetObject for more details.
// //
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Option) error { func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Option) error {
tempFilePath := filePath + TempFileSuffix tempFilePath := filePath + TempFileSuffix
@ -190,7 +188,6 @@ func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Opti
// //
// GetObjectResult the result instance of getting the object. // GetObjectResult the result instance of getting the object.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DoGetObject(request *GetObjectRequest, options []Option) (*GetObjectResult, error) { func (bucket Bucket) DoGetObject(request *GetObjectRequest, options []Option) (*GetObjectResult, error) {
params, _ := GetRawParams(options) params, _ := GetRawParams(options)
resp, err := bucket.do("GET", request.ObjectKey, params, options, nil, nil) resp, err := bucket.do("GET", request.ObjectKey, params, options, nil, nil)
@ -225,13 +222,13 @@ func (bucket Bucket) DoGetObject(request *GetObjectRequest, options []Option) (*
// srcObjectKey the source object to copy. // srcObjectKey the source object to copy.
// destObjectKey the target object to copy. // destObjectKey the target object to copy.
// options options for copying an object. You can specify the conditions of copy. The valid conditions are CopySourceIfMatch, // options options for copying an object. You can specify the conditions of copy. The valid conditions are CopySourceIfMatch,
// CopySourceIfNoneMatch, CopySourceIfModifiedSince, CopySourceIfUnmodifiedSince, MetadataDirective.
// Also you can specify the target object's attributes, such as CacheControl, ContentDisposition, ContentEncoding, Expires,
// ServerSideEncryption, ObjectACL, Meta. Refer to the link below for more details :
// https://www.alibabacloud.com/help/en/object-storage-service/latest/copyobject
// //
// error it's nil if no error, otherwise it's an error object. // CopySourceIfNoneMatch, CopySourceIfModifiedSince, CopySourceIfUnmodifiedSince, MetadataDirective.
// Also you can specify the target object's attributes, such as CacheControl, ContentDisposition, ContentEncoding, Expires,
// ServerSideEncryption, ObjectACL, Meta. Refer to the link below for more details :
// https://www.alibabacloud.com/help/en/object-storage-service/latest/copyobject
// //
// error it's nil if no error, otherwise it's an error object.
func (bucket Bucket) CopyObject(srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) { func (bucket Bucket) CopyObject(srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) {
var out CopyObjectResult var out CopyObjectResult
@ -264,12 +261,10 @@ func (bucket Bucket) CopyObject(srcObjectKey, destObjectKey string, options ...O
// options copy options, check out parameter options in function CopyObject for more details. // options copy options, check out parameter options in function CopyObject for more details.
// //
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) CopyObjectTo(destBucketName, destObjectKey, srcObjectKey string, options ...Option) (CopyObjectResult, error) { func (bucket Bucket) CopyObjectTo(destBucketName, destObjectKey, srcObjectKey string, options ...Option) (CopyObjectResult, error) {
return bucket.copy(srcObjectKey, destBucketName, destObjectKey, options...) return bucket.copy(srcObjectKey, destBucketName, destObjectKey, options...)
} }
//
// CopyObjectFrom copies the object to another bucket. // CopyObjectFrom copies the object to another bucket.
// //
// srcBucketName source bucket name. // srcBucketName source bucket name.
@ -278,7 +273,6 @@ func (bucket Bucket) CopyObjectTo(destBucketName, destObjectKey, srcObjectKey st
// options copy options. Check out parameter options in function CopyObject. // options copy options. Check out parameter options in function CopyObject.
// //
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) CopyObjectFrom(srcBucketName, srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) { func (bucket Bucket) CopyObjectFrom(srcBucketName, srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) {
destBucketName := bucket.BucketName destBucketName := bucket.BucketName
var out CopyObjectResult var out CopyObjectResult
@ -309,7 +303,11 @@ func (bucket Bucket) copy(srcObjectKey, destBucketName, destObjectKey string, op
return out, err return out, err
} }
params := map[string]interface{}{} params := map[string]interface{}{}
resp, err := bucket.Client.Conn.Do("PUT", destBucketName, destObjectKey, params, headers, nil, 0, nil)
ctxArg, _ := FindOption(options, contextArg, nil)
ctx, _ := ctxArg.(context.Context)
resp, err := bucket.Client.Conn.DoWithContext(ctx, "PUT", destBucketName, destObjectKey, params, headers, nil, 0, nil)
// get response header // get response header
respHeader, _ := FindOption(options, responseHeader, nil) respHeader, _ := FindOption(options, responseHeader, nil)
@ -340,11 +338,11 @@ func (bucket Bucket) copy(srcObjectKey, destBucketName, destObjectKey string, op
// reader io.Reader. The read instance for reading the data to append. // reader io.Reader. The read instance for reading the data to append.
// appendPosition the start position to append. // appendPosition the start position to append.
// destObjectProperties the options for the first appending, such as CacheControl, ContentDisposition, ContentEncoding, // destObjectProperties the options for the first appending, such as CacheControl, ContentDisposition, ContentEncoding,
// Expires, ServerSideEncryption, ObjectACL. //
// Expires, ServerSideEncryption, ObjectACL.
// //
// int64 the next append position, it's valid when error is nil. // int64 the next append position, it's valid when error is nil.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) AppendObject(objectKey string, reader io.Reader, appendPosition int64, options ...Option) (int64, error) { func (bucket Bucket) AppendObject(objectKey string, reader io.Reader, appendPosition int64, options ...Option) (int64, error) {
request := &AppendObjectRequest{ request := &AppendObjectRequest{
ObjectKey: objectKey, ObjectKey: objectKey,
@ -367,7 +365,6 @@ func (bucket Bucket) AppendObject(objectKey string, reader io.Reader, appendPosi
// //
// AppendObjectResult the result object for appending object. // AppendObjectResult the result object for appending object.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Option) (*AppendObjectResult, error) { func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Option) (*AppendObjectResult, error) {
params := map[string]interface{}{} params := map[string]interface{}{}
params["append"] = nil params["append"] = nil
@ -386,7 +383,11 @@ func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Opti
listener := GetProgressListener(options) listener := GetProgressListener(options)
handleOptions(headers, opts) handleOptions(headers, opts)
resp, err := bucket.Client.Conn.Do("POST", bucket.BucketName, request.ObjectKey, params, headers,
ctxArg, _ := FindOption(options, contextArg, nil)
ctx, _ := ctxArg.(context.Context)
resp, err := bucket.Client.Conn.DoWithContext(ctx, "POST", bucket.BucketName, request.ObjectKey, params, headers,
request.Reader, initCRC, listener) request.Reader, initCRC, listener)
// get response header // get response header
@ -424,7 +425,6 @@ func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Opti
// objectKey the object key to delete. // objectKey the object key to delete.
// //
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DeleteObject(objectKey string, options ...Option) error { func (bucket Bucket) DeleteObject(objectKey string, options ...Option) error {
params, _ := GetRawParams(options) params, _ := GetRawParams(options)
resp, err := bucket.do("DELETE", objectKey, params, options, nil, nil) resp, err := bucket.do("DELETE", objectKey, params, options, nil, nil)
@ -439,11 +439,11 @@ func (bucket Bucket) DeleteObject(objectKey string, options ...Option) error {
// //
// objectKeys the object keys to delete. // objectKeys the object keys to delete.
// options the options for deleting objects. // options the options for deleting objects.
// Supported option is DeleteObjectsQuiet which means it will not return error even deletion failed (not recommended). By default it's not used. //
// Supported option is DeleteObjectsQuiet which means it will not return error even deletion failed (not recommended). By default it's not used.
// //
// DeleteObjectsResult the result object. // DeleteObjectsResult the result object.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DeleteObjects(objectKeys []string, options ...Option) (DeleteObjectsResult, error) { func (bucket Bucket) DeleteObjects(objectKeys []string, options ...Option) (DeleteObjectsResult, error) {
out := DeleteObjectsResult{} out := DeleteObjectsResult{}
dxml := deleteXML{} dxml := deleteXML{}
@ -475,11 +475,11 @@ func (bucket Bucket) DeleteObjects(objectKeys []string, options ...Option) (Dele
// //
// objectVersions the object keys and versions to delete. // objectVersions the object keys and versions to delete.
// options the options for deleting objects. // options the options for deleting objects.
// Supported option is DeleteObjectsQuiet which means it will not return error even deletion failed (not recommended). By default it's not used. //
// Supported option is DeleteObjectsQuiet which means it will not return error even deletion failed (not recommended). By default it's not used.
// //
// DeleteObjectVersionsResult the result object. // DeleteObjectVersionsResult the result object.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DeleteObjectVersions(objectVersions []DeleteObject, options ...Option) (DeleteObjectVersionsResult, error) { func (bucket Bucket) DeleteObjectVersions(objectVersions []DeleteObject, options ...Option) (DeleteObjectVersionsResult, error) {
out := DeleteObjectVersionsResult{} out := DeleteObjectVersionsResult{}
dxml := deleteXML{} dxml := deleteXML{}
@ -506,7 +506,6 @@ func (bucket Bucket) DeleteObjectVersions(objectVersions []DeleteObject, options
// //
// string the result response body. // string the result response body.
// error it's nil if no error, otherwise it's an error. // error it's nil if no error, otherwise it's an error.
//
func (bucket Bucket) DeleteMultipleObjectsXml(xmlData string, options ...Option) (string, error) { func (bucket Bucket) DeleteMultipleObjectsXml(xmlData string, options ...Option) (string, error) {
buffer := new(bytes.Buffer) buffer := new(bytes.Buffer)
bs := []byte(xmlData) bs := []byte(xmlData)
@ -534,7 +533,6 @@ func (bucket Bucket) DeleteMultipleObjectsXml(xmlData string, options ...Option)
// bool flag of object's existence (true:exists; false:non-exist) when error is nil. // bool flag of object's existence (true:exists; false:non-exist) when error is nil.
// //
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) IsObjectExist(objectKey string, options ...Option) (bool, error) { func (bucket Bucket) IsObjectExist(objectKey string, options ...Option) (bool, error) {
_, err := bucket.GetObjectMeta(objectKey, options...) _, err := bucket.GetObjectMeta(objectKey, options...)
if err == nil { if err == nil {
@ -554,23 +552,23 @@ func (bucket Bucket) IsObjectExist(objectKey string, options ...Option) (bool, e
// ListObjects lists the objects under the current bucket. // ListObjects lists the objects under the current bucket.
// //
// options it contains all the filters for listing objects. // options it contains all the filters for listing objects.
// It could specify a prefix filter on object keys, the max keys count to return and the object key marker and the delimiter for grouping object names.
// The key marker means the returned objects' key must be greater than it in lexicographic order.
// //
// For example, if the bucket has 8 objects, my-object-1, my-object-11, my-object-2, my-object-21, // It could specify a prefix filter on object keys, the max keys count to return and the object key marker and the delimiter for grouping object names.
// my-object-22, my-object-3, my-object-31, my-object-32. If the prefix is my-object-2 (no other filters), then it returns // The key marker means the returned objects' key must be greater than it in lexicographic order.
// my-object-2, my-object-21, my-object-22 three objects. If the marker is my-object-22 (no other filters), then it returns
// my-object-3, my-object-31, my-object-32 three objects. If the max keys is 5, then it returns 5 objects.
// The three filters could be used together to achieve filter and paging functionality.
// If the prefix is the folder name, then it could list all files under this folder (including the files under its subfolders).
// But if the delimiter is specified with '/', then it only returns that folder's files (no subfolder's files). The direct subfolders are in the commonPrefixes properties.
// For example, if the bucket has three objects fun/test.jpg, fun/movie/001.avi, fun/movie/007.avi. And if the prefix is "fun/", then it returns all three objects.
// But if the delimiter is '/', then only "fun/test.jpg" is returned as files and fun/movie/ is returned as common prefix.
// //
// For common usage scenario, check out sample/list_object.go. // For example, if the bucket has 8 objects, my-object-1, my-object-11, my-object-2, my-object-21,
// my-object-22, my-object-3, my-object-31, my-object-32. If the prefix is my-object-2 (no other filters), then it returns
// my-object-2, my-object-21, my-object-22 three objects. If the marker is my-object-22 (no other filters), then it returns
// my-object-3, my-object-31, my-object-32 three objects. If the max keys is 5, then it returns 5 objects.
// The three filters could be used together to achieve filter and paging functionality.
// If the prefix is the folder name, then it could list all files under this folder (including the files under its subfolders).
// But if the delimiter is specified with '/', then it only returns that folder's files (no subfolder's files). The direct subfolders are in the commonPrefixes properties.
// For example, if the bucket has three objects fun/test.jpg, fun/movie/001.avi, fun/movie/007.avi. And if the prefix is "fun/", then it returns all three objects.
// But if the delimiter is '/', then only "fun/test.jpg" is returned as files and fun/movie/ is returned as common prefix.
// //
// ListObjectsResult the return value after operation succeeds (only valid when error is nil). // For common usage scenario, check out sample/list_object.go.
// //
// ListObjectsResult the return value after operation succeeds (only valid when error is nil).
func (bucket Bucket) ListObjects(options ...Option) (ListObjectsResult, error) { func (bucket Bucket) ListObjects(options ...Option) (ListObjectsResult, error) {
var out ListObjectsResult var out ListObjectsResult
@ -653,10 +651,10 @@ func (bucket Bucket) ListObjectVersions(options ...Option) (ListObjectVersionsRe
// //
// objectKey object // objectKey object
// options options for setting the metadata. The valid options are CacheControl, ContentDisposition, ContentEncoding, Expires, // options options for setting the metadata. The valid options are CacheControl, ContentDisposition, ContentEncoding, Expires,
// ServerSideEncryption, and custom metadata.
// //
// error it's nil if no error, otherwise it's an error object. // ServerSideEncryption, and custom metadata.
// //
// error it's nil if no error, otherwise it's an error object.
func (bucket Bucket) SetObjectMeta(objectKey string, options ...Option) error { func (bucket Bucket) SetObjectMeta(objectKey string, options ...Option) error {
options = append(options, MetadataDirective(MetaReplace)) options = append(options, MetadataDirective(MetaReplace))
_, err := bucket.CopyObject(objectKey, objectKey, options...) _, err := bucket.CopyObject(objectKey, objectKey, options...)
@ -667,11 +665,11 @@ func (bucket Bucket) SetObjectMeta(objectKey string, options ...Option) error {
// //
// objectKey object key. // objectKey object key.
// options the constraints of the object. Only when the object meets the requirements this method will return the metadata. Otherwise returns error. Valid options are IfModifiedSince, IfUnmodifiedSince, // options the constraints of the object. Only when the object meets the requirements this method will return the metadata. Otherwise returns error. Valid options are IfModifiedSince, IfUnmodifiedSince,
// IfMatch, IfNoneMatch. For more details check out https://www.alibabacloud.com/help/en/object-storage-service/latest/headobject //
// IfMatch, IfNoneMatch. For more details check out https://www.alibabacloud.com/help/en/object-storage-service/latest/headobject
// //
// http.Header object meta when error is nil. // http.Header object meta when error is nil.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObjectDetailedMeta(objectKey string, options ...Option) (http.Header, error) { func (bucket Bucket) GetObjectDetailedMeta(objectKey string, options ...Option) (http.Header, error) {
params, _ := GetRawParams(options) params, _ := GetRawParams(options)
resp, err := bucket.do("HEAD", objectKey, params, options, nil, nil) resp, err := bucket.do("HEAD", objectKey, params, options, nil, nil)
@ -692,7 +690,6 @@ func (bucket Bucket) GetObjectDetailedMeta(objectKey string, options ...Option)
// //
// http.Header the object's metadata, valid when error is nil. // http.Header the object's metadata, valid when error is nil.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObjectMeta(objectKey string, options ...Option) (http.Header, error) { func (bucket Bucket) GetObjectMeta(objectKey string, options ...Option) (http.Header, error) {
params, _ := GetRawParams(options) params, _ := GetRawParams(options)
params["objectMeta"] = nil params["objectMeta"] = nil
@ -721,7 +718,6 @@ func (bucket Bucket) GetObjectMeta(objectKey string, options ...Option) (http.He
// objectAcl object ACL. Valid options are PrivateACL, PublicReadACL, PublicReadWriteACL. // objectAcl object ACL. Valid options are PrivateACL, PublicReadACL, PublicReadWriteACL.
// //
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) SetObjectACL(objectKey string, objectACL ACLType, options ...Option) error { func (bucket Bucket) SetObjectACL(objectKey string, objectACL ACLType, options ...Option) error {
options = append(options, ObjectACL(objectACL)) options = append(options, ObjectACL(objectACL))
params, _ := GetRawParams(options) params, _ := GetRawParams(options)
@ -740,7 +736,6 @@ func (bucket Bucket) SetObjectACL(objectKey string, objectACL ACLType, options .
// //
// GetObjectACLResult the result object when error is nil. GetObjectACLResult.Acl is the object ACL. // GetObjectACLResult the result object when error is nil. GetObjectACLResult.Acl is the object ACL.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObjectACL(objectKey string, options ...Option) (GetObjectACLResult, error) { func (bucket Bucket) GetObjectACL(objectKey string, options ...Option) (GetObjectACLResult, error) {
var out GetObjectACLResult var out GetObjectACLResult
params, _ := GetRawParams(options) params, _ := GetRawParams(options)
@ -767,7 +762,6 @@ func (bucket Bucket) GetObjectACL(objectKey string, options ...Option) (GetObjec
// targetObjectKey the target object key to point to. // targetObjectKey the target object key to point to.
// //
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) PutSymlink(symObjectKey string, targetObjectKey string, options ...Option) error { func (bucket Bucket) PutSymlink(symObjectKey string, targetObjectKey string, options ...Option) error {
options = append(options, symlinkTarget(url.QueryEscape(targetObjectKey))) options = append(options, symlinkTarget(url.QueryEscape(targetObjectKey)))
params, _ := GetRawParams(options) params, _ := GetRawParams(options)
@ -786,8 +780,8 @@ func (bucket Bucket) PutSymlink(symObjectKey string, targetObjectKey string, opt
// objectKey the symlink object's key. // objectKey the symlink object's key.
// //
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
// When error is nil, the target file key is in the X-Oss-Symlink-Target header of the returned object.
// //
// When error is nil, the target file key is in the X-Oss-Symlink-Target header of the returned object.
func (bucket Bucket) GetSymlink(objectKey string, options ...Option) (http.Header, error) { func (bucket Bucket) GetSymlink(objectKey string, options ...Option) (http.Header, error) {
params, _ := GetRawParams(options) params, _ := GetRawParams(options)
params["symlink"] = nil params["symlink"] = nil
@ -817,7 +811,6 @@ func (bucket Bucket) GetSymlink(objectKey string, options ...Option) (http.Heade
// objectKey object key to restore. // objectKey object key to restore.
// //
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) RestoreObject(objectKey string, options ...Option) error { func (bucket Bucket) RestoreObject(objectKey string, options ...Option) error {
params, _ := GetRawParams(options) params, _ := GetRawParams(options)
params["restore"] = nil params["restore"] = nil
@ -888,7 +881,6 @@ func (bucket Bucket) RestoreObjectXML(objectKey, configXML string, options ...Op
// //
// string returns the signed URL, when error is nil. // string returns the signed URL, when error is nil.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) SignURL(objectKey string, method HTTPMethod, expiredInSec int64, options ...Option) (string, error) { func (bucket Bucket) SignURL(objectKey string, method HTTPMethod, expiredInSec int64, options ...Option) (string, error) {
err := CheckObjectName(objectKey) err := CheckObjectName(objectKey)
if err != nil { if err != nil {
@ -920,11 +912,11 @@ func (bucket Bucket) SignURL(objectKey string, method HTTPMethod, expiredInSec i
// signedURL signed URL. // signedURL signed URL.
// reader io.Reader the read instance for reading the data for the upload. // reader io.Reader the read instance for reading the data for the upload.
// options the options for uploading the data. The valid options are CacheControl, ContentDisposition, ContentEncoding, // options the options for uploading the data. The valid options are CacheControl, ContentDisposition, ContentEncoding,
// Expires, ServerSideEncryption, ObjectACL and custom metadata. Check out the following link for details:
// https://www.alibabacloud.com/help/en/object-storage-service/latest/putobject
// //
// error it's nil if no error, otherwise it's an error object. // Expires, ServerSideEncryption, ObjectACL and custom metadata. Check out the following link for details:
// https://www.alibabacloud.com/help/en/object-storage-service/latest/putobject
// //
// error it's nil if no error, otherwise it's an error object.
func (bucket Bucket) PutObjectWithURL(signedURL string, reader io.Reader, options ...Option) error { func (bucket Bucket) PutObjectWithURL(signedURL string, reader io.Reader, options ...Option) error {
resp, err := bucket.DoPutObjectWithURL(signedURL, reader, options) resp, err := bucket.DoPutObjectWithURL(signedURL, reader, options)
if err != nil { if err != nil {
@ -943,7 +935,6 @@ func (bucket Bucket) PutObjectWithURL(signedURL string, reader io.Reader, option
// options options for uploading, same as the options in PutObject function. // options options for uploading, same as the options in PutObject function.
// //
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) PutObjectFromFileWithURL(signedURL, filePath string, options ...Option) error { func (bucket Bucket) PutObjectFromFileWithURL(signedURL, filePath string, options ...Option) error {
fd, err := os.Open(filePath) fd, err := os.Open(filePath)
if err != nil { if err != nil {
@ -968,7 +959,6 @@ func (bucket Bucket) PutObjectFromFileWithURL(signedURL, filePath string, option
// //
// Response the response object which contains the HTTP response. // Response the response object which contains the HTTP response.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DoPutObjectWithURL(signedURL string, reader io.Reader, options []Option) (*Response, error) { func (bucket Bucket) DoPutObjectWithURL(signedURL string, reader io.Reader, options []Option) (*Response, error) {
listener := GetProgressListener(options) listener := GetProgressListener(options)
@ -994,12 +984,12 @@ func (bucket Bucket) DoPutObjectWithURL(signedURL string, reader io.Reader, opti
// //
// signedURL the signed URL. // signedURL the signed URL.
// options options for downloading the object. Valid options are IfModifiedSince, IfUnmodifiedSince, IfMatch, // options options for downloading the object. Valid options are IfModifiedSince, IfUnmodifiedSince, IfMatch,
// IfNoneMatch, AcceptEncoding. For more information, check out the following link: //
// https://www.alibabacloud.com/help/en/object-storage-service/latest/getobject // IfNoneMatch, AcceptEncoding. For more information, check out the following link:
// https://www.alibabacloud.com/help/en/object-storage-service/latest/getobject
// //
// io.ReadCloser the reader object for getting the data from response. It needs be closed after the usage. It's only valid when error is nil. // io.ReadCloser the reader object for getting the data from response. It needs be closed after the usage. It's only valid when error is nil.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObjectWithURL(signedURL string, options ...Option) (io.ReadCloser, error) { func (bucket Bucket) GetObjectWithURL(signedURL string, options ...Option) (io.ReadCloser, error) {
result, err := bucket.DoGetObjectWithURL(signedURL, options) result, err := bucket.DoGetObjectWithURL(signedURL, options)
if err != nil { if err != nil {
@ -1015,7 +1005,6 @@ func (bucket Bucket) GetObjectWithURL(signedURL string, options ...Option) (io.R
// options the options for downloading object. Check out the parameter options in function GetObject for the reference. // options the options for downloading object. Check out the parameter options in function GetObject for the reference.
// //
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObjectToFileWithURL(signedURL, filePath string, options ...Option) error { func (bucket Bucket) GetObjectToFileWithURL(signedURL, filePath string, options ...Option) error {
tempFilePath := filePath + TempFileSuffix tempFilePath := filePath + TempFileSuffix
@ -1066,7 +1055,6 @@ func (bucket Bucket) GetObjectToFileWithURL(signedURL, filePath string, options
// //
// GetObjectResult the result object when the error is nil. // GetObjectResult the result object when the error is nil.
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DoGetObjectWithURL(signedURL string, options []Option) (*GetObjectResult, error) { func (bucket Bucket) DoGetObjectWithURL(signedURL string, options []Option) (*GetObjectResult, error) {
params, _ := GetRawParams(options) params, _ := GetRawParams(options)
resp, err := bucket.doURL("GET", signedURL, params, options, nil, nil) resp, err := bucket.doURL("GET", signedURL, params, options, nil, nil)
@ -1096,18 +1084,15 @@ func (bucket Bucket) DoGetObjectWithURL(signedURL string, options []Option) (*Ge
return result, nil return result, nil
} }
//
// ProcessObject apply process on the specified image file. // ProcessObject apply process on the specified image file.
// //
// The supported process includes resize, rotate, crop, watermark, format, // The supported process includes resize, rotate, crop, watermark, format,
// udf, customized style, etc. // udf, customized style, etc.
// //
//
// objectKey object key to process. // objectKey object key to process.
// process process string, such as "image/resize,w_100|sys/saveas,o_dGVzdC5qcGc,b_dGVzdA" // process process string, such as "image/resize,w_100|sys/saveas,o_dGVzdC5qcGc,b_dGVzdA"
// //
// error it's nil if no error, otherwise it's an error object. // error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) ProcessObject(objectKey string, process string, options ...Option) (ProcessObjectResult, error) { func (bucket Bucket) ProcessObject(objectKey string, process string, options ...Option) (ProcessObjectResult, error) {
var out ProcessObjectResult var out ProcessObjectResult
params, _ := GetRawParams(options) params, _ := GetRawParams(options)
@ -1160,7 +1145,6 @@ func (bucket Bucket) AsyncProcessObject(objectKey string, asyncProcess string, o
// tagging tagging to be added // tagging tagging to be added
// //
// error nil if success, otherwise error // error nil if success, otherwise error
//
func (bucket Bucket) PutObjectTagging(objectKey string, tagging Tagging, options ...Option) error { func (bucket Bucket) PutObjectTagging(objectKey string, tagging Tagging, options ...Option) error {
bs, err := xml.Marshal(tagging) bs, err := xml.Marshal(tagging)
if err != nil { if err != nil {
@ -1204,13 +1188,11 @@ func (bucket Bucket) GetObjectTagging(objectKey string, options ...Option) (GetO
return out, err return out, err
} }
//
// DeleteObjectTagging delete object taggging // DeleteObjectTagging delete object taggging
// //
// objectKey object key to delete tagging // objectKey object key to delete tagging
// //
// error nil if success, otherwise error // error nil if success, otherwise error
//
func (bucket Bucket) DeleteObjectTagging(objectKey string, options ...Option) error { func (bucket Bucket) DeleteObjectTagging(objectKey string, options ...Option) error {
params, _ := GetRawParams(options) params, _ := GetRawParams(options)
params["tagging"] = nil params["tagging"] = nil
@ -1253,7 +1235,11 @@ func (bucket Bucket) doInner(method, objectName string, params map[string]interf
if len(bucket.BucketName) > 0 && err != nil { if len(bucket.BucketName) > 0 && err != nil {
return nil, err return nil, err
} }
resp, err := bucket.Client.Conn.Do(method, bucket.BucketName, objectName,
ctxArg, _ := FindOption(options, contextArg, nil)
ctx, _ := ctxArg.(context.Context)
resp, err := bucket.Client.Conn.DoWithContext(ctx, method, bucket.BucketName, objectName,
params, headers, data, 0, listener) params, headers, data, 0, listener)
// get response header // get response header
@ -1281,13 +1267,17 @@ func (bucket Bucket) do(method, objectName string, params map[string]interface{}
func (bucket Bucket) doURL(method HTTPMethod, signedURL string, params map[string]interface{}, options []Option, func (bucket Bucket) doURL(method HTTPMethod, signedURL string, params map[string]interface{}, options []Option,
data io.Reader, listener ProgressListener) (*Response, error) { data io.Reader, listener ProgressListener) (*Response, error) {
headers := make(map[string]string) headers := make(map[string]string)
err := handleOptions(headers, options) err := handleOptions(headers, options)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp, err := bucket.Client.Conn.DoURL(method, signedURL, headers, data, 0, listener) ctxArg, _ := FindOption(options, contextArg, nil)
ctx, _ := ctxArg.(context.Context)
resp, err := bucket.Client.Conn.DoURLWithContext(ctx, method, signedURL, headers, data, 0, listener)
// get response header // get response header
respHeader, _ := FindOption(options, responseHeader, nil) respHeader, _ := FindOption(options, responseHeader, nil)

@ -49,10 +49,6 @@ func New(endpoint, accessKeyID, accessKeySecret string, options ...ClientOption)
// URL parse // URL parse
url := &urlMaker{} url := &urlMaker{}
err := url.Init(config.Endpoint, config.IsCname, config.IsUseProxy)
if err != nil {
return nil, err
}
// HTTP connect // HTTP connect
conn := &Conn{config: config, url: url} conn := &Conn{config: config, url: url}
@ -68,6 +64,11 @@ func New(endpoint, accessKeyID, accessKeySecret string, options ...ClientOption)
option(client) option(client)
} }
err := url.InitExt(config.Endpoint, config.IsCname, config.IsUseProxy, config.IsPathStyle)
if err != nil {
return nil, err
}
if config.AuthVersion != AuthV1 && config.AuthVersion != AuthV2 && config.AuthVersion != AuthV4 { if config.AuthVersion != AuthV1 && config.AuthVersion != AuthV2 && config.AuthVersion != AuthV4 {
return nil, fmt.Errorf("Init client Error, invalid Auth version: %v", config.AuthVersion) return nil, fmt.Errorf("Init client Error, invalid Auth version: %v", config.AuthVersion)
} }
@ -2597,7 +2598,16 @@ func (client Client) LimitDownloadSpeed(downSpeed int) error {
func UseCname(isUseCname bool) ClientOption { func UseCname(isUseCname bool) ClientOption {
return func(client *Client) { return func(client *Client) {
client.Config.IsCname = isUseCname client.Config.IsCname = isUseCname
client.Conn.url.Init(client.Config.Endpoint, client.Config.IsCname, client.Config.IsUseProxy) }
}
// ForcePathStyle sets the flag of using Path Style. By default it's false.
//
// isPathStyle true: the endpoint has the Path Style, false: the endpoint does not have Path Style. Default is false.
//
func ForcePathStyle(isPathStyle bool) ClientOption {
return func(client *Client) {
client.Config.IsPathStyle = isPathStyle
} }
} }
@ -2694,7 +2704,6 @@ func Proxy(proxyHost string) ClientOption {
return func(client *Client) { return func(client *Client) {
client.Config.IsUseProxy = true client.Config.IsUseProxy = true
client.Config.ProxyHost = proxyHost client.Config.ProxyHost = proxyHost
client.Conn.url.Init(client.Config.Endpoint, client.Config.IsCname, client.Config.IsUseProxy)
} }
} }
@ -2711,7 +2720,6 @@ func AuthProxy(proxyHost, proxyUser, proxyPassword string) ClientOption {
client.Config.IsAuthProxy = true client.Config.IsAuthProxy = true
client.Config.ProxyUser = proxyUser client.Config.ProxyUser = proxyUser
client.Config.ProxyPassword = proxyPassword client.Config.ProxyPassword = proxyPassword
client.Conn.url.Init(client.Config.Endpoint, client.Config.IsCname, client.Config.IsUseProxy)
} }
} }

@ -146,6 +146,7 @@ type Config struct {
Timeout uint // Timeout in seconds. By default it's 60. Timeout uint // Timeout in seconds. By default it's 60.
SecurityToken string // STS Token SecurityToken string // STS Token
IsCname bool // If cname is in the endpoint. IsCname bool // If cname is in the endpoint.
IsPathStyle bool // If Path Style is in the endpoint.
HTTPTimeout HTTPTimeout // HTTP timeout HTTPTimeout HTTPTimeout // HTTP timeout
HTTPMaxConns HTTPMaxConns // Http max connections HTTPMaxConns HTTPMaxConns // Http max connections
IsUseProxy bool // Flag of using proxy. IsUseProxy bool // Flag of using proxy.
@ -256,6 +257,7 @@ func getDefaultOssConfig() *Config {
config.Timeout = 60 // Seconds config.Timeout = 60 // Seconds
config.SecurityToken = "" config.SecurityToken = ""
config.IsCname = false config.IsCname = false
config.IsPathStyle = false
config.HTTPTimeout.ConnectTimeout = time.Second * 30 // 30s config.HTTPTimeout.ConnectTimeout = time.Second * 30 // 30s
config.HTTPTimeout.ReadWriteTimeout = time.Second * 60 // 60s config.HTTPTimeout.ReadWriteTimeout = time.Second * 60 // 60s

@ -2,6 +2,7 @@ package oss
import ( import (
"bytes" "bytes"
"context"
"crypto/md5" "crypto/md5"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
@ -88,6 +89,12 @@ func (conn *Conn) init(config *Config, urlMaker *urlMaker, client *http.Client)
// Do sends request and returns the response // Do sends request and returns the response
func (conn Conn) Do(method, bucketName, objectName string, params map[string]interface{}, headers map[string]string, func (conn Conn) Do(method, bucketName, objectName string, params map[string]interface{}, headers map[string]string,
data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) {
return conn.DoWithContext(nil, method, bucketName, objectName, params, headers, data, initCRC, listener)
}
// DoWithContext sends request and returns the response with context
func (conn Conn) DoWithContext(ctx context.Context, method, bucketName, objectName string, params map[string]interface{}, headers map[string]string,
data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) { data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) {
urlParams := conn.getURLParams(params) urlParams := conn.getURLParams(params)
subResource := conn.getSubResource(params) subResource := conn.getSubResource(params)
@ -100,11 +107,17 @@ func (conn Conn) Do(method, bucketName, objectName string, params map[string]int
resource = conn.getResourceV4(bucketName, objectName, subResource) resource = conn.getResourceV4(bucketName, objectName, subResource)
} }
return conn.doRequest(method, uri, resource, headers, data, initCRC, listener) return conn.doRequest(ctx, method, uri, resource, headers, data, initCRC, listener)
} }
// DoURL sends the request with signed URL and returns the response result. // DoURL sends the request with signed URL and returns the response result.
func (conn Conn) DoURL(method HTTPMethod, signedURL string, headers map[string]string, func (conn Conn) DoURL(method HTTPMethod, signedURL string, headers map[string]string,
data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) {
return conn.DoURLWithContext(nil, method, signedURL, headers, data, initCRC, listener)
}
// DoURLWithContext sends the request with signed URL and context and returns the response result.
func (conn Conn) DoURLWithContext(ctx context.Context, method HTTPMethod, signedURL string, headers map[string]string,
data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) { data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) {
// Get URI from signedURL // Get URI from signedURL
uri, err := url.ParseRequestURI(signedURL) uri, err := url.ParseRequestURI(signedURL)
@ -123,6 +136,9 @@ func (conn Conn) DoURL(method HTTPMethod, signedURL string, headers map[string]s
Host: uri.Host, Host: uri.Host,
} }
if ctx != nil {
req = req.WithContext(ctx)
}
tracker := &readerTracker{completedBytes: 0} tracker := &readerTracker{completedBytes: 0}
fd, crc := conn.handleBody(req, data, initCRC, listener, tracker) fd, crc := conn.handleBody(req, data, initCRC, listener, tracker)
if fd != nil { if fd != nil {
@ -158,9 +174,10 @@ func (conn Conn) DoURL(method HTTPMethod, signedURL string, headers map[string]s
resp, err := conn.client.Do(req) resp, err := conn.client.Do(req)
if err != nil { if err != nil {
// Transfer failed // Transfer failed
conn.config.WriteLog(Debug, "[Resp:%p]http error:%s\n", req, err.Error())
event = newProgressEvent(TransferFailedEvent, tracker.completedBytes, req.ContentLength, 0) event = newProgressEvent(TransferFailedEvent, tracker.completedBytes, req.ContentLength, 0)
publishProgress(listener, event) publishProgress(listener, event)
conn.config.WriteLog(Debug, "[Resp:%p]http error:%s\n", req, err.Error())
return nil, err return nil, err
} }
@ -280,10 +297,12 @@ func (conn Conn) getResourceV4(bucketName, objectName, subResource string) strin
return fmt.Sprintf("/%s/%s", bucketName, subResource) return fmt.Sprintf("/%s/%s", bucketName, subResource)
} }
func (conn Conn) doRequest(method string, uri *url.URL, canonicalizedResource string, headers map[string]string, func (conn Conn) doRequest(ctx context.Context, method string, uri *url.URL, canonicalizedResource string, headers map[string]string,
data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) { data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) {
method = strings.ToUpper(method) method = strings.ToUpper(method)
req := &http.Request{ var req *http.Request
var err error
req = &http.Request{
Method: method, Method: method,
URL: uri, URL: uri,
Proto: "HTTP/1.1", Proto: "HTTP/1.1",
@ -292,7 +311,9 @@ func (conn Conn) doRequest(method string, uri *url.URL, canonicalizedResource st
Header: make(http.Header), Header: make(http.Header),
Host: uri.Host, Host: uri.Host,
} }
if ctx != nil {
req = req.WithContext(ctx)
}
tracker := &readerTracker{completedBytes: 0} tracker := &readerTracker{completedBytes: 0}
fd, crc := conn.handleBody(req, data, initCRC, listener, tracker) fd, crc := conn.handleBody(req, data, initCRC, listener, tracker)
if fd != nil { if fd != nil {
@ -341,10 +362,10 @@ func (conn Conn) doRequest(method string, uri *url.URL, canonicalizedResource st
resp, err := conn.client.Do(req) resp, err := conn.client.Do(req)
if err != nil { if err != nil {
conn.config.WriteLog(Debug, "[Resp:%p]http error:%s\n", req, err.Error())
// Transfer failed // Transfer failed
event = newProgressEvent(TransferFailedEvent, tracker.completedBytes, req.ContentLength, 0) event = newProgressEvent(TransferFailedEvent, tracker.completedBytes, req.ContentLength, 0)
publishProgress(listener, event) publishProgress(listener, event)
conn.config.WriteLog(Debug, "[Resp:%p]http error:%s\n", req, err.Error())
return nil, err return nil, err
} }
@ -787,9 +808,10 @@ func (c *timeoutConn) SetWriteDeadline(t time.Time) error {
// UrlMaker builds URL and resource // UrlMaker builds URL and resource
const ( const (
urlTypeCname = 1 urlTypeCname = 1
urlTypeIP = 2 urlTypeIP = 2
urlTypeAliyun = 3 urlTypeAliyun = 3
urlTypePathStyle = 4
) )
type urlMaker struct { type urlMaker struct {
@ -801,6 +823,11 @@ type urlMaker struct {
// Init parses endpoint // Init parses endpoint
func (um *urlMaker) Init(endpoint string, isCname bool, isProxy bool) error { func (um *urlMaker) Init(endpoint string, isCname bool, isProxy bool) error {
return um.InitExt(endpoint, isCname, isProxy, false)
}
// InitExt parses endpoint
func (um *urlMaker) InitExt(endpoint string, isCname bool, isProxy bool, isPathStyle bool) error {
if strings.HasPrefix(endpoint, "http://") { if strings.HasPrefix(endpoint, "http://") {
um.Scheme = "http" um.Scheme = "http"
um.NetLoc = endpoint[len("http://"):] um.NetLoc = endpoint[len("http://"):]
@ -833,6 +860,8 @@ func (um *urlMaker) Init(endpoint string, isCname bool, isProxy bool) error {
um.Type = urlTypeIP um.Type = urlTypeIP
} else if isCname { } else if isCname {
um.Type = urlTypeCname um.Type = urlTypeCname
} else if isPathStyle {
um.Type = urlTypePathStyle
} else { } else {
um.Type = urlTypeAliyun um.Type = urlTypeAliyun
} }
@ -881,7 +910,7 @@ func (um urlMaker) buildURL(bucket, object string) (string, string) {
if um.Type == urlTypeCname { if um.Type == urlTypeCname {
host = um.NetLoc host = um.NetLoc
path = "/" + object path = "/" + object
} else if um.Type == urlTypeIP { } else if um.Type == urlTypeIP || um.Type == urlTypePathStyle {
if bucket == "" { if bucket == "" {
host = um.NetLoc host = um.NetLoc
path = "/" path = "/"
@ -916,7 +945,7 @@ func (um urlMaker) buildURLV4(bucket, object string) (string, string) {
if um.Type == urlTypeCname { if um.Type == urlTypeCname {
host = um.NetLoc host = um.NetLoc
path = "/" + object path = "/" + object
} else if um.Type == urlTypeIP { } else if um.Type == urlTypeIP || um.Type == urlTypePathStyle {
if bucket == "" { if bucket == "" {
host = um.NetLoc host = um.NetLoc
path = "/" path = "/"

@ -81,7 +81,7 @@ const (
StorageDeepColdArchive StorageClassType = "DeepColdArchive" StorageDeepColdArchive StorageClassType = "DeepColdArchive"
) )
//RedundancyType bucket data Redundancy type // RedundancyType bucket data Redundancy type
type DataRedundancyType string type DataRedundancyType string
const ( const (
@ -92,7 +92,7 @@ const (
RedundancyZRS DataRedundancyType = "ZRS" RedundancyZRS DataRedundancyType = "ZRS"
) )
//ObjecthashFuncType // ObjecthashFuncType
type ObjecthashFuncType string type ObjecthashFuncType string
const ( const (
@ -111,7 +111,7 @@ const (
BucketOwner PayerType = "BucketOwner" BucketOwner PayerType = "BucketOwner"
) )
//RestoreMode the restore mode for coldArchive object // RestoreMode the restore mode for coldArchive object
type RestoreMode string type RestoreMode string
const ( const (
@ -245,7 +245,7 @@ const (
DefaultContentSha256 = "UNSIGNED-PAYLOAD" // for v4 signature DefaultContentSha256 = "UNSIGNED-PAYLOAD" // for v4 signature
Version = "v2.2.8" // Go SDK version Version = "v2.2.9" // Go SDK version
) )
// FrameType // FrameType

@ -1,6 +1,7 @@
package oss package oss
import ( import (
"context"
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
@ -12,9 +13,11 @@ import (
type optionType string type optionType string
const ( const (
optionParam optionType = "HTTPParameter" // URL parameter optionParam optionType = "HTTPParameter" // URL parameter
optionHTTP optionType = "HTTPHeader" // HTTP header optionHTTP optionType = "HTTPHeader" // HTTP header
optionArg optionType = "FuncArgument" // Function argument optionContext optionType = "HTTPContext" // context
optionArg optionType = "FuncArgument" // Function argument
) )
const ( const (
@ -27,6 +30,7 @@ const (
responseHeader = "x-response-header" responseHeader = "x-response-header"
redundancyType = "redundancy-type" redundancyType = "redundancy-type"
objectHashFunc = "object-hash-func" objectHashFunc = "object-hash-func"
contextArg = "x-context-arg"
) )
type ( type (
@ -448,6 +452,11 @@ func ObjectHashFunc(value ObjecthashFuncType) Option {
return addArg(objectHashFunc, value) return addArg(objectHashFunc, value)
} }
// WithContext returns an option that sets the context for requests.
func WithContext(ctx context.Context) Option {
return addArg(contextArg, ctx)
}
// Checkpoint configuration // Checkpoint configuration
type cpConfig struct { type cpConfig struct {
IsEnable bool IsEnable bool

@ -137,8 +137,8 @@ type LifecycleFilter struct {
// LifecycleFilterNot defines the rule's Filter Not propery // LifecycleFilterNot defines the rule's Filter Not propery
type LifecycleFilterNot struct { type LifecycleFilterNot struct {
XMLName xml.Name `xml:"Not"` XMLName xml.Name `xml:"Not"`
Prefix string `xml:"Prefix,omitempty"` //Object prefix applicable to this exclusion rule Prefix string `xml:"Prefix"` //Object prefix applicable to this exclusion rule
Tag *Tag `xml:"Tag,omitempty"` //the tags applicable to this exclusion rule Tag *Tag `xml:"Tag,omitempty"` //the tags applicable to this exclusion rule
} }
const iso8601DateFormat = "2006-01-02T15:04:05.000Z" const iso8601DateFormat = "2006-01-02T15:04:05.000Z"

@ -26,7 +26,7 @@ import (
// Constants and default values for the package bce // Constants and default values for the package bce
const ( const (
SDK_VERSION = "0.9.154" SDK_VERSION = "0.9.156"
URI_PREFIX = "/" // now support uri without prefix "v1" so just set root path URI_PREFIX = "/" // now support uri without prefix "v1" so just set root path
DEFAULT_DOMAIN = "baidubce.com" DEFAULT_DOMAIN = "baidubce.com"
DEFAULT_PROTOCOL = "http" DEFAULT_PROTOCOL = "http"

@ -1150,12 +1150,12 @@ func DeleteBucketMirror(cli bce.Client, bucket string) error {
} }
func PutBucketTag(cli bce.Client, bucket string, putBucketTagReq PutBucketTagReq) error { func PutBucketTag(cli bce.Client, bucket string, putBucketTagArgs *PutBucketTagArgs) error {
req := &bce.BceRequest{} req := &bce.BceRequest{}
req.SetUri(getBucketUri(bucket)) req.SetUri(getBucketUri(bucket))
req.SetMethod(http.PUT) req.SetMethod(http.PUT)
req.SetParam("tagging", "") req.SetParam("tagging", "")
reqByte, _ := json.Marshal(putBucketTagReq) reqByte, _ := json.Marshal(putBucketTagArgs)
body, err := bce.NewBodyFromString(string(reqByte)) body, err := bce.NewBodyFromString(string(reqByte))
if err != nil { if err != nil {
return err return err
@ -1172,7 +1172,7 @@ func PutBucketTag(cli bce.Client, bucket string, putBucketTagReq PutBucketTagReq
return nil return nil
} }
func GetBucketTag(cli bce.Client, bucket string) (*PutBucketTagReq, error) { func GetBucketTag(cli bce.Client, bucket string) (*PutBucketTagArgs, error) {
req := &bce.BceRequest{} req := &bce.BceRequest{}
req.SetUri(getBucketUri(bucket)) req.SetUri(getBucketUri(bucket))
req.SetMethod(http.GET) req.SetMethod(http.GET)
@ -1184,7 +1184,7 @@ func GetBucketTag(cli bce.Client, bucket string) (*PutBucketTagReq, error) {
if resp.IsFail() { if resp.IsFail() {
return nil, resp.ServiceError() return nil, resp.ServiceError()
} }
result := &PutBucketTagReq{} result := &PutBucketTagArgs{}
if err := resp.ParseJsonBody(result); err != nil { if err := resp.ParseJsonBody(result); err != nil {
return nil, err return nil, err
} }

@ -614,7 +614,7 @@ type PutBucketMirrorArgs struct {
} }
type PutBucketTagReq struct { type PutBucketTagArgs struct {
Tags []Tag `json:"tags"` Tags []Tag `json:"tags"`
} }

@ -2252,3 +2252,15 @@ func (c *Client) GetBucketMirror(bucket string) (*api.PutBucketMirrorArgs, error
func (c *Client) DeleteBucketMirror(bucket string) error { func (c *Client) DeleteBucketMirror(bucket string) error {
return api.DeleteBucketMirror(c, bucket) return api.DeleteBucketMirror(c, bucket)
} }
func (c *Client) PutBucketTag(bucket string, putBucketTagArgs *api.PutBucketTagArgs) error {
return api.PutBucketTag(c, bucket, putBucketTagArgs)
}
func (c *Client) GetBucketTag(bucket string) (*api.PutBucketTagArgs, error) {
return api.GetBucketTag(c, bucket)
}
func (c *Client) DeleteBucketTag(bucket string) error {
return api.DeleteBucketTag(c, bucket)
}

@ -5,7 +5,7 @@ English | [中文](README_ZH_CN.md)
A blazingly fast JSON serializing & deserializing library, accelerated by JIT (just-in-time compiling) and SIMD (single-instruction-multiple-data). A blazingly fast JSON serializing & deserializing library, accelerated by JIT (just-in-time compiling) and SIMD (single-instruction-multiple-data).
## Requirement ## Requirement
- Go 1.16~1.20 - Go 1.16~1.21
- Linux / MacOS / Windows(need go1.17 above) - Linux / MacOS / Windows(need go1.17 above)
- Amd64 ARCH - Amd64 ARCH

@ -1,4 +1,4 @@
// +build amd64,go1.16,!go1.21 // +build amd64,go1.16,!go1.22
/* /*
* Copyright 2022 ByteDance Inc. * Copyright 2022 ByteDance Inc.

@ -1,4 +1,4 @@
// +build !amd64 !go1.16 go1.21 // +build !amd64 !go1.16 go1.22
/* /*
* Copyright 2022 ByteDance Inc. * Copyright 2022 ByteDance Inc.

@ -82,26 +82,54 @@ type ObjectIterator struct {
Iterator Iterator
} }
func (self *ListIterator) next() *Node {
next_start:
if !self.HasNext() {
return nil
} else {
n := self.p.nodeAt(self.i)
self.i++
if !n.Exists() {
goto next_start
}
return n
}
}
// Next scans through children of underlying V_ARRAY, // Next scans through children of underlying V_ARRAY,
// copies each child to v, and returns .HasNext(). // copies each child to v, and returns .HasNext().
func (self *ListIterator) Next(v *Node) bool { func (self *ListIterator) Next(v *Node) bool {
if !self.HasNext() { n := self.next()
if n == nil {
return false return false
}
*v = *n
return true
}
func (self *ObjectIterator) next() *Pair {
next_start:
if !self.HasNext() {
return nil
} else { } else {
*v, self.i = *self.p.nodeAt(self.i), self.i + 1 n := self.p.pairAt(self.i)
return true self.i++
if !n.Value.Exists() {
goto next_start
}
return n
} }
} }
// Next scans through children of underlying V_OBJECT, // Next scans through children of underlying V_OBJECT,
// copies each child to v, and returns .HasNext(). // copies each child to v, and returns .HasNext().
func (self *ObjectIterator) Next(p *Pair) bool { func (self *ObjectIterator) Next(p *Pair) bool {
if !self.HasNext() { n := self.next()
if n == nil {
return false return false
} else {
*p, self.i = *self.p.pairAt(self.i), self.i + 1
return true
} }
*p = *n
return true
} }
// Sequence represents scanning path of single-layer nodes. // Sequence represents scanning path of single-layer nodes.
@ -129,30 +157,39 @@ type Scanner func(path Sequence, node *Node) bool
// //
// Especailly, if the node is not V_ARRAY or V_OBJECT, // Especailly, if the node is not V_ARRAY or V_OBJECT,
// the node itself will be returned and Sequence.Index == -1. // the node itself will be returned and Sequence.Index == -1.
//
// NOTICE: A unsetted node WON'T trigger sc, but its index still counts into Path.Index
func (self *Node) ForEach(sc Scanner) error { func (self *Node) ForEach(sc Scanner) error {
switch self.itype() { switch self.itype() {
case types.V_ARRAY: case types.V_ARRAY:
ns, err := self.unsafeArray() iter, err := self.Values()
if err != nil { if err != nil {
return err return err
} }
for i:=0; i<ns.Len(); i++ { v := iter.next()
if !sc(Sequence{i, nil}, ns.At(i)) { for v != nil {
return err if !sc(Sequence{iter.i-1, nil}, v) {
return nil
} }
v = iter.next()
} }
case types.V_OBJECT: case types.V_OBJECT:
ns, err := self.unsafeMap() iter, err := self.Properties()
if err != nil { if err != nil {
return err return err
} }
for i:=0; i<ns.Len(); i++ { v := iter.next()
if !sc(Sequence{i, &ns.At(i).Key}, &ns.At(i).Value) { for v != nil {
return err if !sc(Sequence{iter.i-1, &v.Key}, &v.Value) {
return nil
} }
v = iter.next()
} }
default: default:
if self.Check() != nil {
return self
}
sc(Sequence{-1, nil}, self) sc(Sequence{-1, nil}, self)
} }
return self.Check() return nil
} }

@ -82,9 +82,9 @@ func (self *Node) UnmarshalJSON(data []byte) (err error) {
// Type returns json type represented by the node // Type returns json type represented by the node
// It will be one of belows: // It will be one of belows:
// V_NONE = 0 (empty node) // V_NONE = 0 (empty node, key not exists)
// V_ERROR = 1 (error node) // V_ERROR = 1 (error node)
// V_NULL = 2 (json value `null`) // V_NULL = 2 (json value `null`, key exists)
// V_TRUE = 3 (json value `true`) // V_TRUE = 3 (json value `true`)
// V_FALSE = 4 (json value `false`) // V_FALSE = 4 (json value `false`)
// V_ARRAY = 5 (json value array) // V_ARRAY = 5 (json value array)
@ -102,7 +102,7 @@ func (self Node) itype() types.ValueType {
// Exists returns false only if the self is nil or empty node V_NONE // Exists returns false only if the self is nil or empty node V_NONE
func (self *Node) Exists() bool { func (self *Node) Exists() bool {
return self != nil && self.t != _V_NONE return self.Valid() && self.t != _V_NONE
} }
// Valid reports if self is NOT V_ERROR or nil // Valid reports if self is NOT V_ERROR or nil
@ -114,7 +114,7 @@ func (self *Node) Valid() bool {
} }
// Check checks if the node itself is valid, and return: // Check checks if the node itself is valid, and return:
// - ErrNotFound If the node is nil // - ErrNotExist If the node is nil
// - Its underlying error If the node is V_ERROR // - Its underlying error If the node is V_ERROR
func (self *Node) Check() error { func (self *Node) Check() error {
if self == nil { if self == nil {
@ -572,7 +572,7 @@ func (self *Node) SetAny(key string, val interface{}) (bool, error) {
return self.Set(key, NewAny(val)) return self.Set(key, NewAny(val))
} }
// Unset remove the node of given key under object parent, and reports if the key has existed. // Unset RESET the node of given key under object parent, and reports if the key has existed.
// WARN: After conducting `UnsetXX()`, the node's length WON'T change // WARN: After conducting `UnsetXX()`, the node's length WON'T change
func (self *Node) Unset(key string) (bool, error) { func (self *Node) Unset(key string) (bool, error) {
self.must(types.V_OBJECT, "an object") self.must(types.V_OBJECT, "an object")
@ -619,6 +619,9 @@ func (self *Node) UnsetByIndex(index int) (bool, error) {
if it == types.V_ARRAY { if it == types.V_ARRAY {
p = self.Index(index) p = self.Index(index)
}else if it == types.V_OBJECT { }else if it == types.V_OBJECT {
if err := self.checkRaw(); err != nil {
return false, err
}
pr := self.skipIndexPair(index) pr := self.skipIndexPair(index)
if pr == nil { if pr == nil {
return false, ErrNotExist return false, ErrNotExist
@ -818,15 +821,15 @@ func (self *Node) MapUseNode() (map[string]Node, error) {
// WARN: don't use it unless you know what you are doing // WARN: don't use it unless you know what you are doing
// //
// Deprecated: this API now returns copied nodes instead of directly reference, // Deprecated: this API now returns copied nodes instead of directly reference,
func (self *Node) UnsafeMap() ([]Pair, error) { // func (self *Node) UnsafeMap() ([]Pair, error) {
if err := self.should(types.V_OBJECT, "an object"); err != nil { // if err := self.should(types.V_OBJECT, "an object"); err != nil {
return nil, err // return nil, err
} // }
if err := self.skipAllKey(); err != nil { // if err := self.skipAllKey(); err != nil {
return nil, err // return nil, err
} // }
return self.toGenericObjectUsePair() // return self.toGenericObjectUsePair()
} // }
func (self *Node) unsafeMap() (*linkedPairs, error) { func (self *Node) unsafeMap() (*linkedPairs, error) {
if err := self.should(types.V_OBJECT, "an object"); err != nil { if err := self.should(types.V_OBJECT, "an object"); err != nil {
@ -932,15 +935,15 @@ func (self *Node) ArrayUseNode() ([]Node, error) {
// //
// Deprecated: this API now returns copied nodes instead of directly reference, // Deprecated: this API now returns copied nodes instead of directly reference,
// which has no difference with ArrayUseNode // which has no difference with ArrayUseNode
func (self *Node) UnsafeArray() ([]Node, error) { // func (self *Node) UnsafeArray() ([]Node, error) {
if err := self.should(types.V_ARRAY, "an array"); err != nil { // if err := self.should(types.V_ARRAY, "an array"); err != nil {
return nil, err // return nil, err
} // }
if err := self.skipAllIndex(); err != nil { // if err := self.skipAllIndex(); err != nil {
return nil, err // return nil, err
} // }
return self.toGenericArrayUseNode() // return self.toGenericArrayUseNode()
} // }
func (self *Node) unsafeArray() (*linkedNodes, error) { func (self *Node) unsafeArray() (*linkedNodes, error) {
if err := self.should(types.V_ARRAY, "an array"); err != nil { if err := self.should(types.V_ARRAY, "an array"); err != nil {

@ -34,7 +34,10 @@ const (
) )
var ( var (
// ErrNotExist means both key and value doesn't exist
ErrNotExist error = newError(_ERR_NOT_FOUND, "value not exists") ErrNotExist error = newError(_ERR_NOT_FOUND, "value not exists")
// ErrUnsupportType means API on the node is unsupported
ErrUnsupportType error = newError(_ERR_UNSUPPORT_TYPE, "unsupported type") ErrUnsupportType error = newError(_ERR_UNSUPPORT_TYPE, "unsupported type")
) )

@ -1,134 +0,0 @@
#!/usr/bin/env python3
# Copyright 2022 ByteDance Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import tempfile
import os
import subprocess
import argparse
gbench_prefix = "SONIC_NO_ASYNC_GC=1 go test -benchmem -run=none "
def run(cmd):
print(cmd)
if os.system(cmd):
print ("Failed to run cmd: %s"%(cmd))
exit(1)
def run_s(cmd):
print (cmd)
try:
res = os.popen(cmd)
except subprocess.CalledProcessError as e:
if e.returncode:
print (e.output)
exit(1)
return res.read()
def run_r(cmd):
print (cmd)
try:
cmds = cmd.split(' ')
data = subprocess.check_output(cmds, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
if e.returncode:
print (e.output)
exit(1)
return data.decode("utf-8")
def compare(args):
# detech current branch.
# result = run_r("git branch")
current_branch = run_s("git status | head -n1 | sed 's/On branch //'")
# for br in result.split('\n'):
# if br.startswith("* "):
# current_branch = br.lstrip('* ')
# break
if not current_branch:
print ("Failed to detech current branch")
return None
# get the current diff
(fd, diff) = tempfile.mkstemp()
run("git diff > %s"%diff)
# early return if currrent is main branch.
print ("Current branch: %s"%(current_branch))
if current_branch == "main":
print ("Cannot compare at the main branch.Please build a new branch")
return None
# benchmark current branch
(fd, target) = tempfile.mkstemp(".target.txt")
run("%s %s ./... 2>&1 | tee %s" %(gbench_prefix, args, target))
# trying to switch to the latest main branch
run("git checkout -- .")
if current_branch != "main":
run("git checkout main")
run("git pull --allow-unrelated-histories origin main")
# benchmark main branch
(fd, main) = tempfile.mkstemp(".main.txt")
run("%s %s ./... 2>&1 | tee %s" %(gbench_prefix, args, main))
# diff the result
# benchstat = "go get golang.org/x/perf/cmd/benchstat && go install golang.org/x/perf/cmd/benchstat"
run( "benchstat -sort=delta %s %s"%(main, target))
run("git checkout -- .")
# restore branch
if current_branch != "main":
run("git checkout %s"%(current_branch))
run("patch -p1 < %s" % (diff))
return target
def main():
argparser = argparse.ArgumentParser(description='Tools to test the performance. Example: ./bench.py -b Decoder_Generic_Sonic -c')
argparser.add_argument('-b', '--bench', dest='filter', required=False,
help='Specify the filter for golang benchmark')
argparser.add_argument('-c', '--compare', dest='compare', action='store_true', required=False,
help='Compare with the main benchmarking')
argparser.add_argument('-t', '--times', dest='times', required=False,
help='benchmark the times')
argparser.add_argument('-r', '--repeat_times', dest='count', required=False,
help='benchmark the count')
args = argparser.parse_args()
if args.filter:
gbench_args = "-bench=%s"%(args.filter)
else:
gbench_args = "-bench=."
if args.times:
gbench_args += " -benchtime=%s"%(args.times)
if args.count:
gbench_args += " -count=%s"%(args.count)
else:
gbench_args += " -count=10"
if args.compare:
target = compare(gbench_args)
else:
target = None
if not target:
(fd, target) = tempfile.mkstemp(".target.txt")
run("%s %s ./... 2>&1 | tee %s" %(gbench_prefix, gbench_args, target))
if __name__ == "__main__":
main()

@ -1,4 +1,4 @@
// +build !amd64 !go1.16 go1.21 // +build !amd64 !go1.16 go1.22
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.

@ -1,4 +1,4 @@
// +build amd64,go1.16,!go1.21 // +build amd64,go1.16,!go1.22
/* /*
* Copyright 2023 ByteDance Inc. * Copyright 2023 ByteDance Inc.

@ -1,5 +1,4 @@
//go:build !amd64 || !go1.16 || go1.21 // +build !amd64 !go1.16 go1.22
// +build !amd64 !go1.16 go1.21
/* /*
* Copyright 2023 ByteDance Inc. * Copyright 2023 ByteDance Inc.
@ -170,35 +169,13 @@ func Pretouch(vt reflect.Type, opts ...option.CompileOption) error {
return nil return nil
} }
type StreamDecoder struct { type StreamDecoder = json.Decoder
r io.Reader
buf []byte
scanp int
scanned int64
err error
Decoder
}
// NewStreamDecoder adapts to encoding/json.NewDecoder API. // NewStreamDecoder adapts to encoding/json.NewDecoder API.
// //
// NewStreamDecoder returns a new decoder that reads from r. // NewStreamDecoder returns a new decoder that reads from r.
func NewStreamDecoder(r io.Reader) *StreamDecoder { func NewStreamDecoder(r io.Reader) *StreamDecoder {
return &StreamDecoder{r : r} return json.NewDecoder(r)
}
// Decode decodes input stream into val with corresponding data.
// Redundantly bytes may be read and left in its buffer, and can be used at next call.
// Either io error from underlying io.Reader (except io.EOF)
// or syntax error from data will be recorded and stop subsequently decoding.
func (self *StreamDecoder) Decode(val interface{}) (err error) {
dec := json.NewDecoder(self.r)
if (self.f | uint64(OptionUseNumber)) != 0 {
dec.UseNumber()
}
if (self.f | uint64(OptionDisableUnknown)) != 0 {
dec.DisallowUnknownFields()
}
return dec.Decode(val)
} }
// SyntaxError represents json syntax error // SyntaxError represents json syntax error

@ -1,4 +1,4 @@
// +build amd64,go1.16,!go1.21 // +build amd64,go1.16,!go1.22
/* /*
* Copyright 2023 ByteDance Inc. * Copyright 2023 ByteDance Inc.

@ -1,4 +1,4 @@
// +build !amd64 !go1.16 go1.21 // +build !amd64 !go1.16 go1.22
/* /*
* Copyright 2023 ByteDance Inc. * Copyright 2023 ByteDance Inc.
@ -216,23 +216,12 @@ func Valid(data []byte) (ok bool, start int) {
} }
// StreamEncoder uses io.Writer as // StreamEncoder uses io.Writer as
type StreamEncoder struct { type StreamEncoder = json.Encoder
w io.Writer
Encoder
}
// NewStreamEncoder adapts to encoding/json.NewDecoder API. // NewStreamEncoder adapts to encoding/json.NewDecoder API.
// //
// NewStreamEncoder returns a new encoder that write to w. // NewStreamEncoder returns a new encoder that write to w.
func NewStreamEncoder(w io.Writer) *StreamEncoder { func NewStreamEncoder(w io.Writer) *StreamEncoder {
return &StreamEncoder{w: w} return json.NewEncoder(w)
} }
// Encode encodes interface{} as JSON to io.Writer
func (enc *StreamEncoder) Encode(val interface{}) (err error) {
jenc := json.NewEncoder(enc.w)
jenc.SetEscapeHTML((enc.Opts & EscapeHTML) != 0)
jenc.SetIndent(enc.prefix, enc.indent)
err = jenc.Encode(val)
return err
}

@ -0,0 +1,130 @@
// +build go1.16,!go1.17
// Copyright 2023 CloudWeGo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package decoder
import (
`strconv`
_ `unsafe`
`github.com/bytedance/sonic/internal/jit`
`github.com/bytedance/sonic/internal/rt`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
)
var _runtime_writeBarrier uintptr = rt.GcwbAddr()
//go:linkname gcWriteBarrierAX runtime.gcWriteBarrier
func gcWriteBarrierAX()
var (
_V_writeBarrier = jit.Imm(int64(_runtime_writeBarrier))
_F_gcWriteBarrierAX = jit.Func(gcWriteBarrierAX)
)
func (self *_Assembler) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
self.Emit("MOVQ", _V_writeBarrier, _R10)
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
self.Rjmp("CALL", _R10)
if saveDI {
self.load(_DI)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", _AX, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}
func (self *_Assembler) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool, saveAX bool) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _R10)
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveAX {
self.Emit("XCHGQ", ptr, _AX)
} else {
self.Emit("MOVQ", ptr, _AX)
}
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
self.Rjmp("CALL", _R10)
if saveDI {
self.load(_DI)
}
if saveAX {
self.Emit("XCHGQ", ptr, _AX)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}
func (self *_ValueDecoder) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
self.Emit("MOVQ", _V_writeBarrier, _R10)
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
self.Rjmp("CALL", _R10)
if saveDI {
self.load(_DI)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", _AX, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}
func (self *_ValueDecoder) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _R10)
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, _AX)
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
self.Rjmp("CALL", _R10)
if saveDI {
self.load(_DI)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}

@ -0,0 +1,126 @@
// +build go1.17,!go1.21
// Copyright 2023 CloudWeGo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package decoder
import (
`strconv`
`unsafe`
`github.com/bytedance/sonic/internal/jit`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
)
//go:linkname _runtime_writeBarrier runtime.writeBarrier
var _runtime_writeBarrier uintptr
//go:linkname gcWriteBarrierAX runtime.gcWriteBarrier
func gcWriteBarrierAX()
var (
_V_writeBarrier = jit.Imm(int64(uintptr(unsafe.Pointer(&_runtime_writeBarrier))))
_F_gcWriteBarrierAX = jit.Func(gcWriteBarrierAX)
)
func (self *_Assembler) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
self.Emit("MOVQ", _V_writeBarrier, _R9)
self.Emit("CMPL", jit.Ptr(_R9, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.call(_F_gcWriteBarrierAX)
if saveDI {
self.load(_DI)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", _AX, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}
func (self *_Assembler) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool, saveAX bool) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _R9)
self.Emit("CMPL", jit.Ptr(_R9, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveAX {
self.Emit("XCHGQ", ptr, _AX)
} else {
self.Emit("MOVQ", ptr, _AX)
}
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.call(_F_gcWriteBarrierAX)
if saveDI {
self.load(_DI)
}
if saveAX {
self.Emit("XCHGQ", ptr, _AX)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}
func (self *_ValueDecoder) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
self.Emit("MOVQ", _V_writeBarrier, _R9)
self.Emit("CMPL", jit.Ptr(_R9, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.call(_F_gcWriteBarrierAX)
if saveDI {
self.load(_DI)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", _AX, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}
func (self *_ValueDecoder) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _AX)
self.Emit("CMPL", jit.Ptr(_AX, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, _AX)
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.call(_F_gcWriteBarrierAX)
if saveDI {
self.load(_DI)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}

@ -0,0 +1,133 @@
// +build go1.21,!go1.22
// Copyright 2023 CloudWeGo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package decoder
import (
`strconv`
`unsafe`
`github.com/bytedance/sonic/internal/jit`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
)
//go:linkname _runtime_writeBarrier runtime.writeBarrier
var _runtime_writeBarrier uintptr
//go:nosplit
//go:linkname gcWriteBarrier2 runtime.gcWriteBarrier2
func gcWriteBarrier2()
// Notice: gcWriteBarrier must use R11 register!!
var _R11 = _IC
var (
_V_writeBarrier = jit.Imm(int64(uintptr(unsafe.Pointer(&_runtime_writeBarrier))))
_F_gcWriteBarrier2 = jit.Func(gcWriteBarrier2)
)
func (self *_Assembler) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
self.Emit("MOVQ", _V_writeBarrier, _R9)
self.Emit("CMPL", jit.Ptr(_R9, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveDI {
self.save(_DI, _R11)
} else {
self.save(_R11)
}
self.Emit("MOVQ", _F_gcWriteBarrier2, _R11)
self.Rjmp("CALL", _R11)
self.Emit("MOVQ", _AX, jit.Ptr(_R11, 0))
self.Emit("MOVQ", rec, _DI)
self.Emit("MOVQ", _DI, jit.Ptr(_R11, 8))
if saveDI {
self.load(_DI, _R11)
} else {
self.load(_R11)
}
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", _AX, rec)
}
func (self *_Assembler) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool, saveAX bool) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _R9)
self.Emit("CMPL", jit.Ptr(_R9, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveAX {
self.save(_AX, _R11)
} else {
self.save(_R11)
}
self.Emit("MOVQ", _F_gcWriteBarrier2, _R11)
self.Rjmp("CALL", _R11)
self.Emit("MOVQ", ptr, jit.Ptr(_R11, 0))
self.Emit("MOVQ", rec, _AX)
self.Emit("MOVQ", _AX, jit.Ptr(_R11, 8))
self.load(_R11)
if saveAX {
self.load(_AX, _R11)
} else {
self.load(_R11)
}
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
}
func (self *_ValueDecoder) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
self.Emit("MOVQ", _V_writeBarrier, _R9)
self.Emit("CMPL", jit.Ptr(_R9, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveDI {
self.save(_DI, _R11)
} else {
self.save(_R11)
}
self.Emit("MOVQ", _F_gcWriteBarrier2, _R11)
self.Rjmp("CALL", _R11)
self.Emit("MOVQ", _AX, jit.Ptr(_R11, 0))
self.Emit("MOVQ", rec, _DI)
self.Emit("MOVQ", _DI, jit.Ptr(_R11, 8))
if saveDI {
self.load(_DI, _R11)
} else {
self.load(_R11)
}
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", _AX, rec)
}
func (self *_ValueDecoder) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _AX)
self.Emit("CMPL", jit.Ptr(_AX, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.save(_R11)
self.Emit("MOVQ", _F_gcWriteBarrier2, _R11)
self.Rjmp("CALL", _R11)
self.Emit("MOVQ", ptr, jit.Ptr(_R11, 0))
self.Emit("MOVQ", rec, _AX)
self.Emit("MOVQ", _AX, jit.Ptr(_R11, 8))
self.load(_R11)
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
}

@ -1,5 +1,5 @@
//go:build go1.17 && !go1.21 //go:build go1.17 && !go1.22
// +build go1.17,!go1.21 // +build go1.17,!go1.22
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.
@ -24,7 +24,6 @@ import (
`fmt` `fmt`
`math` `math`
`reflect` `reflect`
`strconv`
`unsafe` `unsafe`
`github.com/bytedance/sonic/internal/caching` `github.com/bytedance/sonic/internal/caching`
@ -33,7 +32,6 @@ import (
`github.com/bytedance/sonic/internal/native/types` `github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt` `github.com/bytedance/sonic/internal/rt`
`github.com/twitchyliquid64/golang-asm/obj` `github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
) )
/** Register Allocations /** Register Allocations
@ -1929,62 +1927,3 @@ func (self *_Assembler) print_gc(i int, p1 *_Instr, p2 *_Instr) {
self.Emit("MOVQ", jit.Imm(int64(i)), _AX) // MOVQ $(i), (SP) self.Emit("MOVQ", jit.Imm(int64(i)), _AX) // MOVQ $(i), (SP)
self.call_go(_F_println) self.call_go(_F_println)
} }
//go:linkname _runtime_writeBarrier runtime.writeBarrier
var _runtime_writeBarrier uintptr
//go:linkname gcWriteBarrierAX runtime.gcWriteBarrier
func gcWriteBarrierAX()
var (
_V_writeBarrier = jit.Imm(int64(uintptr(unsafe.Pointer(&_runtime_writeBarrier))))
_F_gcWriteBarrierAX = jit.Func(gcWriteBarrierAX)
)
func (self *_Assembler) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
self.Emit("MOVQ", _V_writeBarrier, _R9)
self.Emit("CMPL", jit.Ptr(_R9, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.call(_F_gcWriteBarrierAX)
if saveDI {
self.load(_DI)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", _AX, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}
func (self *_Assembler) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool, saveAX bool) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _R9)
self.Emit("CMPL", jit.Ptr(_R9, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveAX {
self.Emit("XCHGQ", ptr, _AX)
} else {
self.Emit("MOVQ", ptr, _AX)
}
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.call(_F_gcWriteBarrierAX)
if saveDI {
self.load(_DI)
}
if saveAX {
self.Emit("XCHGQ", ptr, _AX)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}

@ -1,4 +1,4 @@
// +build go1.15,!go1.17 // +build go1.16,!go1.17
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.
@ -23,7 +23,6 @@ import (
`fmt` `fmt`
`math` `math`
`reflect` `reflect`
`strconv`
`unsafe` `unsafe`
`github.com/bytedance/sonic/internal/caching` `github.com/bytedance/sonic/internal/caching`
@ -32,7 +31,6 @@ import (
`github.com/bytedance/sonic/internal/native/types` `github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt` `github.com/bytedance/sonic/internal/rt`
`github.com/twitchyliquid64/golang-asm/obj` `github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
) )
/** Register Allocations /** Register Allocations
@ -1949,63 +1947,3 @@ func (self *_Assembler) print_gc(i int, p1 *_Instr, p2 *_Instr) {
self.Emit("MOVQ", jit.Imm(int64(i)), jit.Ptr(_SP, 0)) // MOVQ $(i), (SP) self.Emit("MOVQ", jit.Imm(int64(i)), jit.Ptr(_SP, 0)) // MOVQ $(i), (SP)
self.call_go(_F_println) self.call_go(_F_println)
} }
var _runtime_writeBarrier uintptr = rt.GcwbAddr()
//go:linkname gcWriteBarrierAX runtime.gcWriteBarrier
func gcWriteBarrierAX()
var (
_V_writeBarrier = jit.Imm(int64(_runtime_writeBarrier))
_F_gcWriteBarrierAX = jit.Func(gcWriteBarrierAX)
)
func (self *_Assembler) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
self.Emit("MOVQ", _V_writeBarrier, _R10)
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
self.Rjmp("CALL", _R10)
if saveDI {
self.load(_DI)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", _AX, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}
func (self *_Assembler) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool, saveAX bool) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _R10)
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveAX {
self.Emit("XCHGQ", ptr, _AX)
} else {
self.Emit("MOVQ", ptr, _AX)
}
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
self.Rjmp("CALL", _R10)
if saveDI {
self.load(_DI)
}
if saveAX {
self.Emit("XCHGQ", ptr, _AX)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}

@ -1,5 +1,4 @@
//go:build go1.17 && !go1.21 // +build go1.17,!go1.22
// +build go1.17,!go1.21
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.
@ -23,13 +22,11 @@ import (
`encoding/json` `encoding/json`
`fmt` `fmt`
`reflect` `reflect`
`strconv`
`github.com/bytedance/sonic/internal/jit` `github.com/bytedance/sonic/internal/jit`
`github.com/bytedance/sonic/internal/native` `github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types` `github.com/bytedance/sonic/internal/native/types`
`github.com/twitchyliquid64/golang-asm/obj` `github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
) )
/** Crucial Registers: /** Crucial Registers:
@ -286,7 +283,7 @@ func (self *_ValueDecoder) compile() {
self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX
self.Emit("MOVQ", _VAR_df, _R8) // MOVQ $df, R8 self.Emit("MOVQ", _VAR_df, _R8) // MOVQ $df, R8
self.Emit("BTSQ", jit.Imm(_F_allow_control), _R8) // ANDQ $1<<_F_allow_control, R8 self.Emit("BTSQ", jit.Imm(_F_allow_control), _R8) // ANDQ $1<<_F_allow_control, R8
self.callc(_F_value) // CALL value self.callc(_F_value) // CALL value
self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC
/* check for errors */ /* check for errors */
@ -720,46 +717,6 @@ func (self *_ValueDecoder) compile() {
} }
} }
func (self *_ValueDecoder) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
self.Emit("MOVQ", _V_writeBarrier, _R9)
self.Emit("CMPL", jit.Ptr(_R9, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.call(_F_gcWriteBarrierAX)
if saveDI {
self.load(_DI)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", _AX, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}
func (self *_ValueDecoder) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _AX)
self.Emit("CMPL", jit.Ptr(_AX, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, _AX)
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.call(_F_gcWriteBarrierAX)
if saveDI {
self.load(_DI)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}
/** Generic Decoder **/ /** Generic Decoder **/
var ( var (

@ -1,4 +1,4 @@
// +build go1.17,!go1.21 // +build go1.17,!go1.22
// //
// Copyright 2021 ByteDance Inc. // Copyright 2021 ByteDance Inc.

@ -1,4 +1,4 @@
// +build go1.15,!go1.17 // +build go1.16,!go1.17
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.
@ -22,13 +22,11 @@ import (
`encoding/json` `encoding/json`
`fmt` `fmt`
`reflect` `reflect`
`strconv`
`github.com/bytedance/sonic/internal/jit` `github.com/bytedance/sonic/internal/jit`
`github.com/bytedance/sonic/internal/native` `github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types` `github.com/bytedance/sonic/internal/native/types`
`github.com/twitchyliquid64/golang-asm/obj` `github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
) )
/** Crucial Registers: /** Crucial Registers:
@ -645,7 +643,8 @@ func (self *_ValueDecoder) compile() {
self.Emit("MOVQ", _R8, _VAR_cs_p) self.Emit("MOVQ", _R8, _VAR_cs_p)
self.Emit("MOVQ", _AX, _VAR_cs_n) self.Emit("MOVQ", _AX, _VAR_cs_n)
self.Emit("MOVQ", _DI, _VAR_cs_LR) self.Emit("MOVQ", _DI, _VAR_cs_LR)
self.Emit("MOVQ", _T_byte, jit.Ptr(_SP, 0)) self.Emit("MOVQ", _T_byte, _R8)
self.Emit("MOVQ", _R8, jit.Ptr(_SP, 0))
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 8)) self.Emit("MOVQ", _AX, jit.Ptr(_SP, 8))
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16)) self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16))
self.call_go(_F_makeslice) self.call_go(_F_makeslice)
@ -722,48 +721,6 @@ func (self *_ValueDecoder) compile() {
} }
} }
func (self *_ValueDecoder) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
self.Emit("MOVQ", _V_writeBarrier, _R10)
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
self.Rjmp("CALL", _R10)
if saveDI {
self.load(_DI)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", _AX, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}
func (self *_ValueDecoder) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _R10)
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, _AX)
if saveDI {
self.save(_DI)
}
self.Emit("LEAQ", rec, _DI)
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
self.Rjmp("CALL", _R10)
if saveDI {
self.load(_DI)
}
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}
/** Generic Decoder **/ /** Generic Decoder **/
var ( var (

@ -1,4 +1,4 @@
// +build go1.15,!go1.17 // +build go1.16,!go1.17
// //
// Copyright 2021 ByteDance Inc. // Copyright 2021 ByteDance Inc.

@ -1,4 +1,4 @@
// +build go1.15,!go1.20 // +build go1.16,!go1.20
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.

@ -82,23 +82,23 @@ func makemap_small() unsafe.Pointer
//go:linkname mapassign runtime.mapassign //go:linkname mapassign runtime.mapassign
//goland:noinspection GoUnusedParameter //goland:noinspection GoUnusedParameter
func mapassign(t *rt.GoType, h unsafe.Pointer, k unsafe.Pointer) unsafe.Pointer func mapassign(t *rt.GoMapType, h unsafe.Pointer, k unsafe.Pointer) unsafe.Pointer
//go:linkname mapassign_fast32 runtime.mapassign_fast32 //go:linkname mapassign_fast32 runtime.mapassign_fast32
//goland:noinspection GoUnusedParameter //goland:noinspection GoUnusedParameter
func mapassign_fast32(t *rt.GoType, h unsafe.Pointer, k uint32) unsafe.Pointer func mapassign_fast32(t *rt.GoMapType, h unsafe.Pointer, k uint32) unsafe.Pointer
//go:linkname mapassign_fast64 runtime.mapassign_fast64 //go:linkname mapassign_fast64 runtime.mapassign_fast64
//goland:noinspection GoUnusedParameter //goland:noinspection GoUnusedParameter
func mapassign_fast64(t *rt.GoType, h unsafe.Pointer, k uint64) unsafe.Pointer func mapassign_fast64(t *rt.GoMapType, h unsafe.Pointer, k uint64) unsafe.Pointer
//go:linkname mapassign_fast64ptr runtime.mapassign_fast64ptr //go:linkname mapassign_fast64ptr runtime.mapassign_fast64ptr
//goland:noinspection GoUnusedParameter //goland:noinspection GoUnusedParameter
func mapassign_fast64ptr(t *rt.GoType, h unsafe.Pointer, k unsafe.Pointer) unsafe.Pointer func mapassign_fast64ptr(t *rt.GoMapType, h unsafe.Pointer, k unsafe.Pointer) unsafe.Pointer
//go:linkname mapassign_faststr runtime.mapassign_faststr //go:linkname mapassign_faststr runtime.mapassign_faststr
//goland:noinspection GoUnusedParameter //goland:noinspection GoUnusedParameter
func mapassign_faststr(t *rt.GoType, h unsafe.Pointer, s string) unsafe.Pointer func mapassign_faststr(t *rt.GoMapType, h unsafe.Pointer, s string) unsafe.Pointer
//go:nosplit //go:nosplit
//go:linkname memclrHasPointers runtime.memclrHasPointers //go:linkname memclrHasPointers runtime.memclrHasPointers

@ -0,0 +1,51 @@
// +build go1.16,!go1.17
// Copyright 2023 CloudWeGo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package encoder
import (
`strconv`
`github.com/bytedance/sonic/internal/jit`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
)
var (
_V_writeBarrier = jit.Imm(int64(_runtime_writeBarrier))
_F_gcWriteBarrierAX = jit.Func(gcWriteBarrierAX)
)
func (self *_Assembler) WritePtr(i int, ptr obj.Addr, rec obj.Addr) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _R10)
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, _AX)
self.xsave(_DI)
self.Emit("LEAQ", rec, _DI)
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
self.Rjmp("CALL", _R10)
self.xload(_DI)
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}

@ -0,0 +1,51 @@
// +build go1.17,!go1.21
// Copyright 2023 CloudWeGo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package encoder
import (
`strconv`
`unsafe`
`github.com/bytedance/sonic/internal/jit`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
)
var (
_V_writeBarrier = jit.Imm(int64(uintptr(unsafe.Pointer(&_runtime_writeBarrier))))
_F_gcWriteBarrierAX = jit.Func(gcWriteBarrierAX)
)
func (self *_Assembler) WritePtr(i int, ptr obj.Addr, rec obj.Addr) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _BX)
self.Emit("CMPL", jit.Ptr(_BX, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.xsave(_DI)
self.Emit("MOVQ", ptr, _AX)
self.Emit("LEAQ", rec, _DI)
self.Emit("MOVQ", _F_gcWriteBarrierAX, _BX) // MOVQ ${fn}, AX
self.Rjmp("CALL", _BX)
self.xload(_DI)
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}

@ -0,0 +1,50 @@
// +build go1.21,!go1.22
// Copyright 2023 CloudWeGo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package encoder
import (
`strconv`
`unsafe`
`github.com/bytedance/sonic/internal/jit`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
)
var (
_V_writeBarrier = jit.Imm(int64(uintptr(unsafe.Pointer(&_runtime_writeBarrier))))
_F_gcWriteBarrier2 = jit.Func(gcWriteBarrier2)
)
func (self *_Assembler) WritePtr(i int, ptr obj.Addr, old obj.Addr) {
if old.Reg == x86.REG_AX || old.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _BX)
self.Emit("CMPL", jit.Ptr(_BX, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.xsave(_SP_q)
self.Emit("MOVQ", _F_gcWriteBarrier2, _BX) // MOVQ ${fn}, AX
self.Rjmp("CALL", _BX)
self.Emit("MOVQ", ptr, jit.Ptr(_SP_q, 0))
self.Emit("MOVQ", old, _AX)
self.Emit("MOVQ", _AX, jit.Ptr(_SP_q, 8))
self.xload(_SP_q)
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, old)
}

@ -1,5 +1,5 @@
//go:build go1.17 && !go1.21 //go:build go1.17 && !go1.22
// +build go1.17,!go1.21 // +build go1.17,!go1.22
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.
@ -435,8 +435,8 @@ func (self *_Assembler) save_state() {
self.Sjmp("JAE" , _LB_error_too_deep) // JA _error_too_deep self.Sjmp("JAE" , _LB_error_too_deep) // JA _error_too_deep
self.Emit("MOVQ", _SP_x, jit.Sib(_ST, _CX, 1, 8)) // MOVQ SP.x, 8(ST)(CX) self.Emit("MOVQ", _SP_x, jit.Sib(_ST, _CX, 1, 8)) // MOVQ SP.x, 8(ST)(CX)
self.Emit("MOVQ", _SP_f, jit.Sib(_ST, _CX, 1, 16)) // MOVQ SP.f, 16(ST)(CX) self.Emit("MOVQ", _SP_f, jit.Sib(_ST, _CX, 1, 16)) // MOVQ SP.f, 16(ST)(CX)
self.WriteRecNotAX(0, _SP_p, jit.Sib(_ST, _CX, 1, 24)) // MOVQ SP.p, 24(ST)(CX) self.WritePtr(0, _SP_p, jit.Sib(_ST, _CX, 1, 24)) // MOVQ SP.p, 24(ST)(CX)
self.WriteRecNotAX(1, _SP_q, jit.Sib(_ST, _CX, 1, 32)) // MOVQ SP.q, 32(ST)(CX) self.WritePtr(1, _SP_q, jit.Sib(_ST, _CX, 1, 32)) // MOVQ SP.q, 32(ST)(CX)
self.Emit("MOVQ", _R9, jit.Ptr(_ST, 0)) // MOVQ R9, (ST) self.Emit("MOVQ", _R9, jit.Ptr(_ST, 0)) // MOVQ R9, (ST)
} }
@ -1175,28 +1175,3 @@ func (self *_Assembler) print_gc(i int, p1 *_Instr, p2 *_Instr) {
self.Emit("MOVQ", jit.Imm(int64(i)), _AX) // MOVQ $(i), CX self.Emit("MOVQ", jit.Imm(int64(i)), _AX) // MOVQ $(i), CX
self.call_go(_F_println) self.call_go(_F_println)
} }
var (
_V_writeBarrier = jit.Imm(int64(uintptr(unsafe.Pointer(&_runtime_writeBarrier))))
_F_gcWriteBarrierAX = jit.Func(gcWriteBarrierAX)
)
func (self *_Assembler) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _BX)
self.Emit("CMPL", jit.Ptr(_BX, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.xsave(_DI)
self.Emit("MOVQ", ptr, _AX)
self.Emit("LEAQ", rec, _DI)
self.Emit("MOVQ", _F_gcWriteBarrierAX, _BX) // MOVQ ${fn}, AX
self.Rjmp("CALL", _BX)
self.xload(_DI)
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}

@ -1,4 +1,4 @@
// +build go1.15,!go1.17 // +build go1.16,!go1.17
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.
@ -421,8 +421,8 @@ func (self *_Assembler) save_state() {
self.Sjmp("JAE" , _LB_error_too_deep) // JA _error_too_deep self.Sjmp("JAE" , _LB_error_too_deep) // JA _error_too_deep
self.Emit("MOVQ", _SP_x, jit.Sib(_ST, _CX, 1, 8)) // MOVQ SP.x, 8(ST)(CX) self.Emit("MOVQ", _SP_x, jit.Sib(_ST, _CX, 1, 8)) // MOVQ SP.x, 8(ST)(CX)
self.Emit("MOVQ", _SP_f, jit.Sib(_ST, _CX, 1, 16)) // MOVQ SP.f, 16(ST)(CX) self.Emit("MOVQ", _SP_f, jit.Sib(_ST, _CX, 1, 16)) // MOVQ SP.f, 16(ST)(CX)
self.WriteRecNotAX(0, _SP_p, jit.Sib(_ST, _CX, 1, 24)) // MOVQ SP.p, 24(ST)(CX) self.WritePtr(0, _SP_p, jit.Sib(_ST, _CX, 1, 24)) // MOVQ SP.p, 24(ST)(CX)
self.WriteRecNotAX(1, _SP_q, jit.Sib(_ST, _CX, 1, 32)) // MOVQ SP.q, 32(ST)(CX) self.WritePtr(1, _SP_q, jit.Sib(_ST, _CX, 1, 32)) // MOVQ SP.q, 32(ST)(CX)
self.Emit("MOVQ", _R8, jit.Ptr(_ST, 0)) // MOVQ R8, (ST) self.Emit("MOVQ", _R8, jit.Ptr(_ST, 0)) // MOVQ R8, (ST)
} }
@ -579,7 +579,8 @@ var (
func (self *_Assembler) more_space() { func (self *_Assembler) more_space() {
self.Link(_LB_more_space) self.Link(_LB_more_space)
self.Emit("MOVQ", _T_byte, jit.Ptr(_SP, 0)) // MOVQ $_T_byte, (SP) self.Emit("MOVQ", _T_byte, _AX) // MOVQ $_T_byte, _AX
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ _AX, (SP)
self.Emit("MOVQ", _RP, jit.Ptr(_SP, 8)) // MOVQ RP, 8(SP) self.Emit("MOVQ", _RP, jit.Ptr(_SP, 8)) // MOVQ RP, 8(SP)
self.Emit("MOVQ", _RL, jit.Ptr(_SP, 16)) // MOVQ RL, 16(SP) self.Emit("MOVQ", _RL, jit.Ptr(_SP, 16)) // MOVQ RL, 16(SP)
self.Emit("MOVQ", _RC, jit.Ptr(_SP, 24)) // MOVQ RC, 24(SP) self.Emit("MOVQ", _RC, jit.Ptr(_SP, 24)) // MOVQ RC, 24(SP)
@ -1172,28 +1173,3 @@ func (self *_Assembler) print_gc(i int, p1 *_Instr, p2 *_Instr) {
self.Emit("MOVQ", jit.Imm(int64(i)), jit.Ptr(_SP, 0)) // MOVQ $(i), (SP) self.Emit("MOVQ", jit.Imm(int64(i)), jit.Ptr(_SP, 0)) // MOVQ $(i), (SP)
self.call_go(_F_println) self.call_go(_F_println)
} }
var (
_V_writeBarrier = jit.Imm(int64(_runtime_writeBarrier))
_F_gcWriteBarrierAX = jit.Func(gcWriteBarrierAX)
)
func (self *_Assembler) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr) {
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
panic("rec contains AX!")
}
self.Emit("MOVQ", _V_writeBarrier, _R10)
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, _AX)
self.xsave(_DI)
self.Emit("LEAQ", rec, _DI)
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
self.Rjmp("CALL", _R10)
self.xload(_DI)
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
self.Emit("MOVQ", ptr, rec)
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
}

@ -1,4 +1,4 @@
// +build go1.15,!go1.17 // +build go1.16,!go1.17
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.

@ -1,4 +1,4 @@
// +build go1.17,!go1.21 // +build go1.17,!go1.22
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.

@ -1,4 +1,4 @@
// +build go1.15,!go1.17 // +build go1.16,!go1.17
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.

@ -1,4 +1,4 @@
// +build go1.20 // +build go1.20,!go1.21
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.

@ -0,0 +1,66 @@
// +build go1.21
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package encoder
import (
`unsafe`
_ `github.com/chenzhuoyu/base64x`
`github.com/bytedance/sonic/internal/rt`
)
//go:linkname _subr__b64encode github.com/chenzhuoyu/base64x._subr__b64encode
var _subr__b64encode uintptr
//go:noescape
//go:linkname memmove runtime.memmove
//goland:noinspection GoUnusedParameter
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
//go:linkname growslice reflect.growslice
//goland:noinspection GoUnusedParameter
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
//go:linkname assertI2I runtime.assertI2I2
//goland:noinspection GoUnusedParameter
func assertI2I(inter *rt.GoType, i rt.GoIface) rt.GoIface
//go:linkname mapiternext runtime.mapiternext
//goland:noinspection GoUnusedParameter
func mapiternext(it *rt.GoMapIterator)
//go:linkname mapiterinit runtime.mapiterinit
//goland:noinspection GoUnusedParameter
func mapiterinit(t *rt.GoMapType, m *rt.GoMap, it *rt.GoMapIterator)
//go:linkname isValidNumber encoding/json.isValidNumber
//goland:noinspection GoUnusedParameter
func isValidNumber(s string) bool
//go:noescape
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
//goland:noinspection GoUnusedParameter
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
//go:linkname _runtime_writeBarrier runtime.writeBarrier
var _runtime_writeBarrier uintptr
//go:linkname gcWriteBarrier2 runtime.gcWriteBarrier2
func gcWriteBarrier2()

@ -1,3 +1,5 @@
// +build !go1.21
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.
* *

@ -0,0 +1,48 @@
// +build go1.21
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package resolver
import (
_ `encoding/json`
`reflect`
_ `unsafe`
)
type StdField struct {
name string
nameBytes []byte
nameNonEsc string
nameEscHTML string
tag bool
index []int
typ reflect.Type
omitEmpty bool
quoted bool
encoder func()
}
type StdStructFields struct {
list []StdField
nameIndex map[string]*StdField
byFoldedName map[string]*StdField
}
//go:noescape
//go:linkname typeFields encoding/json.typeFields
func typeFields(_ reflect.Type) StdStructFields

@ -0,0 +1,119 @@
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package loader
import (
`unsafe`
`github.com/bytedance/sonic/internal/rt`
)
const (
_Magic uint32 = 0xFFFFFFF1
)
type moduledata struct {
pcHeader *pcHeader
funcnametab []byte
cutab []uint32
filetab []byte
pctab []byte
pclntable []byte
ftab []funcTab
findfunctab uintptr
minpc, maxpc uintptr // first func address, last func address + last func size
text, etext uintptr // start/end of text, (etext-text) must be greater than MIN_FUNC
noptrdata, enoptrdata uintptr
data, edata uintptr
bss, ebss uintptr
noptrbss, enoptrbss uintptr
covctrs, ecovctrs uintptr
end, gcdata, gcbss uintptr
types, etypes uintptr
rodata uintptr
gofunc uintptr // go.func.* is actual funcinfo object in image
textsectmap []textSection // see runtime/symtab.go: textAddr()
typelinks []int32 // offsets from types
itablinks []*rt.GoItab
ptab []ptabEntry
pluginpath string
pkghashes []modulehash
// This slice records the initializing tasks that need to be
// done to start up the program. It is built by the linker.
inittasks []unsafe.Pointer
modulename string
modulehashes []modulehash
hasmain uint8 // 1 if module contains the main function, 0 otherwise
gcdatamask, gcbssmask bitVector
typemap map[int32]*rt.GoType // offset to *_rtype in previous module
bad bool // module failed to load and should be ignored
next *moduledata
}
type _func struct {
entryOff uint32 // start pc, as offset from moduledata.text/pcHeader.textStart
nameOff int32 // function name, as index into moduledata.funcnametab.
args int32 // in/out args size
deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
pcsp uint32
pcfile uint32
pcln uint32
npcdata uint32
cuOffset uint32 // runtime.cutab offset of this function's CU
startLine int32 // line number of start of function (func keyword/TEXT directive)
funcID uint8 // set for certain special runtime functions
flag uint8
_ [1]byte // pad
nfuncdata uint8 //
// The end of the struct is followed immediately by two variable-length
// arrays that reference the pcdata and funcdata locations for this
// function.
// pcdata contains the offset into moduledata.pctab for the start of
// that index's table. e.g.,
// &moduledata.pctab[_func.pcdata[_PCDATA_UnsafePoint]] is the start of
// the unsafe point table.
//
// An offset of 0 indicates that there is no table.
//
// pcdata [npcdata]uint32
// funcdata contains the offset past moduledata.gofunc which contains a
// pointer to that index's funcdata. e.g.,
// *(moduledata.gofunc + _func.funcdata[_FUNCDATA_ArgsPointerMaps]) is
// the argument pointer map.
//
// An offset of ^uint32(0) indicates that there is no entry.
//
// funcdata [nfuncdata]uint32
}

@ -1,5 +1,5 @@
// go:build go1.18 && !go1.21 // go:build go1.18 && !go1.22
// +build go1.18,!go1.21 // +build go1.18,!go1.22
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.

@ -1,5 +1,5 @@
//go:build go1.16 && !go1.21 //go:build go1.16 && !go1.22
// +build go1.16,!go1.21 // +build go1.16,!go1.22
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.

@ -1,4 +1,4 @@
// +build amd64,go1.16,!go1.21 // +build amd64,go1.16,!go1.22
/* /*
* Copyright 2021 ByteDance Inc. * Copyright 2021 ByteDance Inc.

@ -0,0 +1,13 @@
# Security Policy
## Supported Versions
Security updates are applied only to the latest release.
## Reporting a Vulnerability
If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
Please disclose it at [security advisory](https://github.com/go-ole/go-ole/security/advisories/new).
This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.

@ -6,14 +6,9 @@
version: "1.3.0.{build}-alpha-{branch}" version: "1.3.0.{build}-alpha-{branch}"
os: Windows Server 2012 R2 os: Visual Studio 2019
branches: build: off
only:
- master
- v1.2
- v1.1
- v1.0
skip_tags: true skip_tags: true
@ -21,20 +16,40 @@ clone_folder: c:\gopath\src\github.com\go-ole\go-ole
environment: environment:
GOPATH: c:\gopath GOPATH: c:\gopath
matrix: GOROOT: c:\go
- GOARCH: amd64 DOWNLOADPLATFORM: "x64"
GOVERSION: 1.5
GOROOT: c:\go
DOWNLOADPLATFORM: "x64"
install: before_test:
- choco install mingw
- SET PATH=c:\tools\mingw64\bin;%PATH%
# - Download COM Server # - Download COM Server
- ps: Start-FileDownload "https://github.com/go-ole/test-com-server/releases/download/v1.0.2/test-com-server-${env:DOWNLOADPLATFORM}.zip" - ps: Start-FileDownload "https://github.com/go-ole/test-com-server/releases/download/v1.0.2/test-com-server-${env:DOWNLOADPLATFORM}.zip"
- 7z e test-com-server-%DOWNLOADPLATFORM%.zip -oc:\gopath\src\github.com\go-ole\go-ole > NUL - 7z e test-com-server-%DOWNLOADPLATFORM%.zip -oc:\gopath\src\github.com\go-ole\go-ole > NUL
- c:\gopath\src\github.com\go-ole\go-ole\build\register-assembly.bat - c:\gopath\src\github.com\go-ole\go-ole\build\register-assembly.bat
# - set
test_script:
- go test -v -cover ./...
# go vet has false positives on unsafe.Pointer with windows/sys. Disabling since it is recommended to use go test instead.
# - go vet ./...
branches:
only:
- master
- v1.2
- v1.1
- v1.0
matrix:
allow_failures:
- environment:
GOROOT: C:\go-x86
DOWNLOADPLATFORM: "x86"
- environment:
GOROOT: C:\go118
DOWNLOADPLATFORM: "x64"
- environment:
GOROOT: C:\go118-x86
DOWNLOADPLATFORM: "x86"
install:
- go version - go version
- go env - go env
- go get -u golang.org/x/tools/cmd/cover - go get -u golang.org/x/tools/cmd/cover
@ -45,10 +60,9 @@ build_script:
- cd c:\gopath\src\github.com\go-ole\go-ole - cd c:\gopath\src\github.com\go-ole\go-ole
- go get -v -t ./... - go get -v -t ./...
- go build - go build
- go test -v -cover ./...
# disable automatic tests # disable automatic tests
test: off test: on
# disable deployment # disable deployment
deploy: off deploy: off

@ -11,6 +11,7 @@ import (
var ( var (
procCoInitialize = modole32.NewProc("CoInitialize") procCoInitialize = modole32.NewProc("CoInitialize")
procCoInitializeEx = modole32.NewProc("CoInitializeEx") procCoInitializeEx = modole32.NewProc("CoInitializeEx")
procCoInitializeSecurity = modole32.NewProc("CoInitializeSecurity")
procCoUninitialize = modole32.NewProc("CoUninitialize") procCoUninitialize = modole32.NewProc("CoUninitialize")
procCoCreateInstance = modole32.NewProc("CoCreateInstance") procCoCreateInstance = modole32.NewProc("CoCreateInstance")
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
@ -37,6 +38,9 @@ var (
procDispatchMessageW = moduser32.NewProc("DispatchMessageW") procDispatchMessageW = moduser32.NewProc("DispatchMessageW")
) )
// This is to enable calling COM Security initialization multiple times
var bSecurityInit bool = false
// coInitialize initializes COM library on current thread. // coInitialize initializes COM library on current thread.
// //
// MSDN documentation suggests that this function should not be called. Call // MSDN documentation suggests that this function should not be called. Call
@ -68,6 +72,35 @@ func coInitializeEx(coinit uint32) (err error) {
return return
} }
// coInitializeSecurity: Registers security and sets the default security values
// for the process.
func coInitializeSecurity(cAuthSvc int32,
dwAuthnLevel uint32,
dwImpLevel uint32,
dwCapabilities uint32) (err error) {
// Check COM Security initialization has done previously
if !bSecurityInit {
// https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializesecurity
hr, _, _ := procCoInitializeSecurity.Call(
uintptr(0), // Allow *all* VSS writers to communicate back!
uintptr(cAuthSvc), // Default COM authentication service
uintptr(0), // Default COM authorization service
uintptr(0), // Reserved parameter
uintptr(dwAuthnLevel), // Strongest COM authentication level
uintptr(dwImpLevel), // Minimal impersonation abilities
uintptr(0), // Default COM authentication settings
uintptr(dwCapabilities), // Cloaking
uintptr(0)) // eserved parameter
if hr != 0 {
err = NewError(hr)
} else {
// COM Security initialization done make global flag true.
bSecurityInit = true
}
}
return
}
// CoInitialize initializes COM library on current thread. // CoInitialize initializes COM library on current thread.
// //
// MSDN documentation suggests that this function should not be called. Call // MSDN documentation suggests that this function should not be called. Call
@ -96,6 +129,15 @@ func CoUninitialize() {
procCoUninitialize.Call() procCoUninitialize.Call()
} }
// CoInitializeSecurity: Registers security and sets the default security values
// for the process.
func CoInitializeSecurity(cAuthSvc int32,
dwAuthnLevel uint32,
dwImpLevel uint32,
dwCapabilities uint32) (err error) {
return coInitializeSecurity(cAuthSvc, dwAuthnLevel, dwImpLevel, dwCapabilities)
}
// CoTaskMemFree frees memory pointer. // CoTaskMemFree frees memory pointer.
func CoTaskMemFree(memptr uintptr) { func CoTaskMemFree(memptr uintptr) {
procCoTaskMemFree.Call(memptr) procCoTaskMemFree.Call(memptr)

@ -1,3 +1,4 @@
//go:build windows
// +build windows // +build windows
package ole package ole
@ -92,7 +93,7 @@ func invoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{}
case int8: case int8:
vargs[n] = NewVariant(VT_I1, int64(v.(int8))) vargs[n] = NewVariant(VT_I1, int64(v.(int8)))
case *int8: case *int8:
vargs[n] = NewVariant(VT_I1|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint8))))) vargs[n] = NewVariant(VT_I1|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*int8)))))
case int16: case int16:
vargs[n] = NewVariant(VT_I2, int64(v.(int16))) vargs[n] = NewVariant(VT_I2, int64(v.(int16)))
case *int16: case *int16:

@ -99,7 +99,7 @@ func (v *VARIANT) Value() interface{} {
case VT_DISPATCH: case VT_DISPATCH:
return v.ToIDispatch() return v.ToIDispatch()
case VT_BOOL: case VT_BOOL:
return v.Val != 0 return (v.Val & 0xffff) != 0
} }
return nil return nil
} }

@ -1,7 +1,7 @@
Package validator Package validator
================= =================
<img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v10/logo.png">[![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) <img align="right" src="logo.png">[![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.14.1-green.svg) ![Project status](https://img.shields.io/badge/version-10.15.0-green.svg)
[![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) [![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) [![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) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator)
@ -158,6 +158,7 @@ Baked-in Validations
| credit_card | Credit Card Number | | credit_card | Credit Card Number |
| mongodb | MongoDB ObjectID | | mongodb | MongoDB ObjectID |
| cron | Cron | | cron | Cron |
| spicedb | SpiceDb ObjectID/Permission/Type |
| datetime | Datetime | | datetime | Datetime |
| e164 | e164 formatted phone number | | e164 | e164 formatted phone number |
| email | E-mail String | email | E-mail String

@ -230,6 +230,7 @@ var (
"luhn_checksum": hasLuhnChecksum, "luhn_checksum": hasLuhnChecksum,
"mongodb": isMongoDB, "mongodb": isMongoDB,
"cron": isCron, "cron": isCron,
"spicedb": isSpiceDB,
} }
) )
@ -1294,8 +1295,13 @@ func isEq(fl FieldLevel) bool {
return field.Uint() == p return field.Uint() == p
case reflect.Float32, reflect.Float64: case reflect.Float32:
p := asFloat(param) p := asFloat32(param)
return field.Float() == p
case reflect.Float64:
p := asFloat64(param)
return field.Float() == p return field.Float() == p
@ -1561,6 +1567,10 @@ func isFilePath(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
// Not valid if it is a directory.
if isDir(fl) {
return false
}
// If it exists, it obviously is valid. // If it exists, it obviously is valid.
// This is done first to avoid code duplication and unnecessary additional logic. // This is done first to avoid code duplication and unnecessary additional logic.
if exists = isFile(fl); exists { if exists = isFile(fl); exists {
@ -1710,7 +1720,7 @@ func hasValue(fl FieldLevel) bool {
if fl.(*validate).fldIsPointer && field.Interface() != nil { if fl.(*validate).fldIsPointer && field.Interface() != nil {
return true return true
} }
return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface() return field.IsValid() && !field.IsZero()
} }
} }
@ -1734,7 +1744,7 @@ func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue boo
if nullable && field.Interface() != nil { if nullable && field.Interface() != nil {
return false return false
} }
return field.IsValid() && field.Interface() == reflect.Zero(field.Type()).Interface() return field.IsValid() && field.IsZero()
} }
} }
@ -1755,8 +1765,11 @@ func requireCheckFieldValue(
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() == asUint(value) return field.Uint() == asUint(value)
case reflect.Float32, reflect.Float64: case reflect.Float32:
return field.Float() == asFloat(value) return field.Float() == asFloat32(value)
case reflect.Float64:
return field.Float() == asFloat64(value)
case reflect.Slice, reflect.Map, reflect.Array: case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) == asInt(value) return int64(field.Len()) == asInt(value)
@ -2055,8 +2068,13 @@ func isGte(fl FieldLevel) bool {
return field.Uint() >= p return field.Uint() >= p
case reflect.Float32, reflect.Float64: case reflect.Float32:
p := asFloat(param) p := asFloat32(param)
return field.Float() >= p
case reflect.Float64:
p := asFloat64(param)
return field.Float() >= p return field.Float() >= p
@ -2101,10 +2119,16 @@ func isGt(fl FieldLevel) bool {
return field.Uint() > p return field.Uint() > p
case reflect.Float32, reflect.Float64: case reflect.Float32:
p := asFloat(param) p := asFloat32(param)
return field.Float() > p
case reflect.Float64:
p := asFloat64(param)
return field.Float() > p return field.Float() > p
case reflect.Struct: case reflect.Struct:
if field.Type().ConvertibleTo(timeType) { if field.Type().ConvertibleTo(timeType) {
@ -2143,8 +2167,13 @@ func hasLengthOf(fl FieldLevel) bool {
return field.Uint() == p return field.Uint() == p
case reflect.Float32, reflect.Float64: case reflect.Float32:
p := asFloat(param) p := asFloat32(param)
return field.Float() == p
case reflect.Float64:
p := asFloat64(param)
return field.Float() == p return field.Float() == p
} }
@ -2276,8 +2305,13 @@ func isLte(fl FieldLevel) bool {
return field.Uint() <= p return field.Uint() <= p
case reflect.Float32, reflect.Float64: case reflect.Float32:
p := asFloat(param) p := asFloat32(param)
return field.Float() <= p
case reflect.Float64:
p := asFloat64(param)
return field.Float() <= p return field.Float() <= p
@ -2322,8 +2356,13 @@ func isLt(fl FieldLevel) bool {
return field.Uint() < p return field.Uint() < p
case reflect.Float32, reflect.Float64: case reflect.Float32:
p := asFloat(param) p := asFloat32(param)
return field.Float() < p
case reflect.Float64:
p := asFloat64(param)
return field.Float() < p return field.Float() < p
@ -2808,6 +2847,23 @@ func isMongoDB(fl FieldLevel) bool {
return mongodbRegex.MatchString(val) return mongodbRegex.MatchString(val)
} }
// isSpiceDB is the validation function for validating if the current field's value is valid for use with Authzed SpiceDB in the indicated way
func isSpiceDB(fl FieldLevel) bool {
val := fl.Field().String()
param := fl.Param()
switch param {
case "permission":
return spicedbPermissionRegex.MatchString(val)
case "type":
return spicedbTypeRegex.MatchString(val)
case "id", "":
return spicedbIDRegex.MatchString(val)
}
panic("Unrecognized parameter: " + param)
}
// isCreditCard is the validation function for validating if the current field's value is a valid credit card number // isCreditCard is the validation function for validating if the current field's value is a valid credit card number
func isCreditCard(fl FieldLevel) bool { func isCreditCard(fl FieldLevel) bool {
val := fl.Field().String() val := fl.Field().String()

@ -20,6 +20,7 @@ const (
typeOr typeOr
typeKeys typeKeys
typeEndKeys typeEndKeys
typeNestedStructLevel
) )
const ( const (
@ -152,7 +153,7 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
// and so only struct level caching can be used instead of combined with Field tag caching // and so only struct level caching can be used instead of combined with Field tag caching
if len(tag) > 0 { if len(tag) > 0 {
ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, "", false) ctag, _ = v.parseFieldTagsRecursive(tag, fld, "", false)
} else { } else {
// even if field doesn't have validations need cTag for traversing to potential inner/nested // even if field doesn't have validations need cTag for traversing to potential inner/nested
// elements of the field. // elements of the field.
@ -171,7 +172,7 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
return cs return cs
} }
func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias string, hasAlias bool) (firstCtag *cTag, current *cTag) { func (v *Validate) parseFieldTagsRecursive(tag string, field reflect.StructField, alias string, hasAlias bool) (firstCtag *cTag, current *cTag) {
var t string var t string
noAlias := len(alias) == 0 noAlias := len(alias) == 0
tags := strings.Split(tag, tagSeparator) tags := strings.Split(tag, tagSeparator)
@ -185,9 +186,9 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s
// check map for alias and process new tags, otherwise process as usual // check map for alias and process new tags, otherwise process as usual
if tagsVal, found := v.aliases[t]; found { if tagsVal, found := v.aliases[t]; found {
if i == 0 { if i == 0 {
firstCtag, current = v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) firstCtag, current = v.parseFieldTagsRecursive(tagsVal, field, t, true)
} else { } else {
next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) next, curr := v.parseFieldTagsRecursive(tagsVal, field, t, true)
current.next, current = next, curr current.next, current = next, curr
} }
@ -235,7 +236,7 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s
} }
} }
current.keys, _ = v.parseFieldTagsRecursive(string(b[:len(b)-1]), fieldName, "", false) current.keys, _ = v.parseFieldTagsRecursive(string(b[:len(b)-1]), field, "", false)
continue continue
case endKeysTag: case endKeysTag:
@ -284,14 +285,18 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s
current.tag = vals[0] current.tag = vals[0]
if len(current.tag) == 0 { if len(current.tag) == 0 {
panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, fieldName))) panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, field.Name)))
} }
if wrapper, ok := v.validations[current.tag]; ok { if wrapper, ok := v.validations[current.tag]; ok {
current.fn = wrapper.fn current.fn = wrapper.fn
current.runValidationWhenNil = wrapper.runValidatinOnNil current.runValidationWhenNil = wrapper.runValidatinOnNil
} else { } else {
panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, current.tag, fieldName))) panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, current.tag, field.Name)))
}
if current.typeof == typeDefault && isNestedStructOrStructPtr(field) {
current.typeof = typeNestedStructLevel
} }
if len(orVals) > 1 { if len(orVals) > 1 {
@ -319,7 +324,7 @@ func (v *Validate) fetchCacheTag(tag string) *cTag {
// isn't parsed again. // isn't parsed again.
ctag, found = v.tagCache.Get(tag) ctag, found = v.tagCache.Get(tag)
if !found { if !found {
ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false) ctag, _ = v.parseFieldTagsRecursive(tag, reflect.StructField{}, "", false)
v.tagCache.Set(tag, ctag) v.tagCache.Set(tag, ctag)
} }
} }

@ -247,7 +247,7 @@ Example #2
This validates that the value is not the data types default zero value. 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 For numbers ensures value is not zero. For strings ensures value is
not "". For slices, maps, pointers, interfaces, channels and functions not "". For slices, maps, pointers, interfaces, channels and functions
ensures the value is not nil. ensures the value is not nil. For structs ensures value is not the zero value.
Usage: required Usage: required
@ -256,7 +256,7 @@ ensures the value is not nil.
The field under validation must be present and not empty only if all 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 the other specified fields are equal to the value following the specified
field. For strings ensures value is not "". For slices, maps, pointers, field. For strings ensures value is not "". For slices, maps, pointers,
interfaces, channels and functions ensures the value is not nil. interfaces, channels and functions ensures the value is not nil. For structs ensures value is not the zero value.
Usage: required_if Usage: required_if
@ -273,7 +273,7 @@ Examples:
The field under validation must be present and not empty unless all The field under validation must be present and not empty unless all
the other specified fields are equal to the value following the specified the other specified fields are equal to the value following the specified
field. For strings ensures value is not "". For slices, maps, pointers, field. For strings ensures value is not "". For slices, maps, pointers,
interfaces, channels and functions ensures the value is not nil. interfaces, channels and functions ensures the value is not nil. For structs ensures value is not the zero value.
Usage: required_unless Usage: required_unless
@ -290,7 +290,7 @@ Examples:
The field under validation must be present and not empty only if any 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 of the other specified fields are present. For strings ensures value is
not "". For slices, maps, pointers, interfaces, channels and functions not "". For slices, maps, pointers, interfaces, channels and functions
ensures the value is not nil. ensures the value is not nil. For structs ensures value is not the zero value.
Usage: required_with Usage: required_with
@ -307,7 +307,7 @@ Examples:
The field under validation must be present and not empty only if 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 of the other specified fields are present. For strings ensures value is
not "". For slices, maps, pointers, interfaces, channels and functions not "". For slices, maps, pointers, interfaces, channels and functions
ensures the value is not nil. ensures the value is not nil. For structs ensures value is not the zero value.
Usage: required_with_all Usage: required_with_all
@ -321,7 +321,7 @@ Example:
The field under validation must be present and not empty only when any 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 of the other specified fields are not present. For strings ensures value is
not "". For slices, maps, pointers, interfaces, channels and functions not "". For slices, maps, pointers, interfaces, channels and functions
ensures the value is not nil. ensures the value is not nil. For structs ensures value is not the zero value.
Usage: required_without Usage: required_without
@ -338,7 +338,7 @@ Examples:
The field under validation must be present and not empty only when 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 of the other specified fields are not present. For strings ensures value is
not "". For slices, maps, pointers, interfaces, channels and functions not "". For slices, maps, pointers, interfaces, channels and functions
ensures the value is not nil. ensures the value is not nil. For structs ensures value is not the zero value.
Usage: required_without_all Usage: required_without_all
@ -352,7 +352,7 @@ Example:
The field under validation must not be present or not empty only if all 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 the other specified fields are equal to the value following the specified
field. For strings ensures value is not "". For slices, maps, pointers, field. For strings ensures value is not "". For slices, maps, pointers,
interfaces, channels and functions ensures the value is not nil. interfaces, channels and functions ensures the value is not nil. For structs ensures value is not the zero value.
Usage: excluded_if Usage: excluded_if
@ -369,7 +369,7 @@ Examples:
The field under validation must not be present or empty unless all The field under validation must not be present or empty unless all
the other specified fields are equal to the value following the specified the other specified fields are equal to the value following the specified
field. For strings ensures value is not "". For slices, maps, pointers, field. For strings ensures value is not "". For slices, maps, pointers,
interfaces, channels and functions ensures the value is not nil. interfaces, channels and functions ensures the value is not nil. For structs ensures value is not the zero value.
Usage: excluded_unless Usage: excluded_unless
@ -879,8 +879,6 @@ This is done using os.Stat and github.com/gabriel-vasile/mimetype
Usage: image Usage: image
# URL String
# File Path # File Path
This validates that a string value contains a valid file path but does not This validates that a string value contains a valid file path but does not
@ -1384,6 +1382,12 @@ This validates that a string value contains a valid cron expression.
Usage: cron Usage: cron
# SpiceDb ObjectID/Permission/Object Type
This validates that a string is valid for use with SpiceDb for the indicated purpose. If no purpose is given, a purpose of 'id' is assumed.
Usage: spicedb=id|permission|type
# Alias Validators and Tags # Alias Validators and Tags
Alias Validators and Tags Alias Validators and Tags

@ -68,6 +68,9 @@ const (
cveRegexString = `^CVE-(1999|2\d{3})-(0[^0]\d{2}|0\d[^0]\d{1}|0\d{2}[^0]|[1-9]{1}\d{3,})$` // CVE Format Id https://cve.mitre.org/cve/identifiers/syntaxchange.html cveRegexString = `^CVE-(1999|2\d{3})-(0[^0]\d{2}|0\d[^0]\d{1}|0\d{2}[^0]|[1-9]{1}\d{3,})$` // CVE Format Id https://cve.mitre.org/cve/identifiers/syntaxchange.html
mongodbRegexString = "^[a-f\\d]{24}$" mongodbRegexString = "^[a-f\\d]{24}$"
cronRegexString = `(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})` cronRegexString = `(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})`
spicedbIDRegexString = `^(([a-zA-Z0-9/_|\-=+]{1,})|\*)$`
spicedbPermissionRegexString = "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$"
spicedbTypeRegexString = "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$"
) )
var ( var (
@ -134,4 +137,7 @@ var (
cveRegex = regexp.MustCompile(cveRegexString) cveRegex = regexp.MustCompile(cveRegexString)
mongodbRegex = regexp.MustCompile(mongodbRegexString) mongodbRegex = regexp.MustCompile(mongodbRegexString)
cronRegex = regexp.MustCompile(cronRegexString) cronRegex = regexp.MustCompile(cronRegexString)
spicedbIDRegex = regexp.MustCompile(spicedbIDRegexString)
spicedbPermissionRegex = regexp.MustCompile(spicedbPermissionRegexString)
spicedbTypeRegex = regexp.MustCompile(spicedbTypeRegexString)
) )

@ -261,13 +261,19 @@ func asUint(param string) uint64 {
return i return i
} }
// asFloat returns the parameter as a float64 // asFloat64 returns the parameter as a float64
// or panics if it can't convert // or panics if it can't convert
func asFloat(param string) float64 { func asFloat64(param string) float64 {
i, err := strconv.ParseFloat(param, 64) i, err := strconv.ParseFloat(param, 64)
panicIf(err) panicIf(err)
return i
}
// asFloat64 returns the parameter as a float64
// or panics if it can't convert
func asFloat32(param string) float64 {
i, err := strconv.ParseFloat(param, 32)
panicIf(err)
return i return i
} }
@ -286,3 +292,11 @@ func panicIf(err error) {
panic(err.Error()) panic(err.Error())
} }
} }
func isNestedStructOrStructPtr(v reflect.StructField) bool {
if v.Type == nil {
return false
}
kind := v.Type.Kind()
return kind == reflect.Struct || kind == reflect.Ptr && v.Type.Elem().Kind() == reflect.Struct
}

@ -170,7 +170,7 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
if ct.typeof == typeStructOnly { if ct.typeof == typeStructOnly {
goto CONTINUE goto CONTINUE
} else if ct.typeof == typeIsDefault { } else if ct.typeof == typeIsDefault || ct.typeof == typeNestedStructLevel {
// set Field Level fields // set Field Level fields
v.slflParent = parent v.slflParent = parent
v.flField = current v.flField = current

@ -10,7 +10,6 @@ import (
"crypto/md5" "crypto/md5"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"strconv" "strconv"
@ -22,7 +21,7 @@ import (
// It uses ghash.BKDRHash+BASE36 algorithm to calculate the unique version of the binary. // It uses ghash.BKDRHash+BASE36 algorithm to calculate the unique version of the binary.
func BinVersion() string { func BinVersion() string {
if binaryVersion == "" { if binaryVersion == "" {
binaryContent, _ := ioutil.ReadFile(selfPath) binaryContent, _ := os.ReadFile(selfPath)
binaryVersion = strconv.FormatInt( binaryVersion = strconv.FormatInt(
int64(ghash.BKDR(binaryContent)), int64(ghash.BKDR(binaryContent)),
36, 36,

@ -46,6 +46,7 @@ var (
CodeNotFound = localCode{65, "Not Found", nil} // Resource does not exist. CodeNotFound = localCode{65, "Not Found", nil} // Resource does not exist.
CodeInvalidRequest = localCode{66, "Invalid Request", nil} // Invalid request. CodeInvalidRequest = localCode{66, "Invalid Request", nil} // Invalid request.
CodeNecessaryPackageNotImport = localCode{67, "Necessary Package Not Import", nil} // It needs necessary package import. CodeNecessaryPackageNotImport = localCode{67, "Necessary Package Not Import", nil} // It needs necessary package import.
CodeInternalPanic = localCode{68, "Internal Panic", nil} // An panic occurred internally.
CodeBusinessValidationFailed = localCode{300, "Business Validation Failed", nil} // Business validation failed. CodeBusinessValidationFailed = localCode{300, "Business Validation Failed", nil} // Business validation failed.
) )

@ -37,7 +37,11 @@ type iTime interface {
// IsEmpty checks whether given `value` empty. // IsEmpty checks whether given `value` empty.
// It returns true if `value` is in: 0, nil, false, "", len(slice/map/chan) == 0, // It returns true if `value` is in: 0, nil, false, "", len(slice/map/chan) == 0,
// or else it returns false. // or else it returns false.
func IsEmpty(value interface{}) bool { //
// The parameter `traceSource` is used for tracing to the source variable if given `value` is type of pointer
// that also points to a pointer. It returns true if the source is empty when `traceSource` is true.
// Note that it might use reflect feature which affects performance a little.
func IsEmpty(value interface{}, traceSource ...bool) bool {
if value == nil { if value == nil {
return true return true
} }
@ -88,38 +92,39 @@ func IsEmpty(value interface{}) bool {
return len(result) == 0 return len(result) == 0
default: default:
// =========================
// Common interfaces checks.
// =========================
if f, ok := value.(iTime); ok {
if f == (*time.Time)(nil) {
return true
}
return f.IsZero()
}
if f, ok := value.(iString); ok {
if f == nil {
return true
}
return f.String() == ""
}
if f, ok := value.(iInterfaces); ok {
if f == nil {
return true
}
return len(f.Interfaces()) == 0
}
if f, ok := value.(iMapStrAny); ok {
if f == nil {
return true
}
return len(f.MapStrAny()) == 0
}
// Finally, using reflect. // Finally, using reflect.
var rv reflect.Value var rv reflect.Value
if v, ok := value.(reflect.Value); ok { if v, ok := value.(reflect.Value); ok {
rv = v rv = v
} else { } else {
// =========================
// Common interfaces checks.
// =========================
if f, ok := value.(iTime); ok {
if f == (*time.Time)(nil) {
return true
}
return f.IsZero()
}
if f, ok := value.(iString); ok {
if f == nil {
return true
}
return f.String() == ""
}
if f, ok := value.(iInterfaces); ok {
if f == nil {
return true
}
return len(f.Interfaces()) == 0
}
if f, ok := value.(iMapStrAny); ok {
if f == nil {
return true
}
return len(f.MapStrAny()) == 0
}
rv = reflect.ValueOf(value) rv = reflect.ValueOf(value)
} }
@ -169,21 +174,27 @@ func IsEmpty(value interface{}) bool {
reflect.Array: reflect.Array:
return rv.Len() == 0 return rv.Len() == 0
case reflect.Ptr:
if len(traceSource) > 0 && traceSource[0] {
return IsEmpty(rv.Elem())
}
return rv.IsNil()
case case
reflect.Func, reflect.Func,
reflect.Ptr,
reflect.Interface, reflect.Interface,
reflect.UnsafePointer: reflect.UnsafePointer:
if rv.IsNil() { return rv.IsNil()
return true
} case reflect.Invalid:
return true
} }
} }
return false return false
} }
// IsNil checks whether given `value` is nil, especially for interface{} type value. // IsNil checks whether given `value` is nil, especially for interface{} type value.
// Parameter `traceSource` is used for tracing to the source variable if given `value` is type of pinter // Parameter `traceSource` is used for tracing to the source variable if given `value` is type of pointer
// that also points to a pointer. It returns nil if the source is nil when `traceSource` is true. // that also points to a pointer. It returns nil if the source is nil when `traceSource` is true.
// Note that it might use reflect feature which affects performance a little. // Note that it might use reflect feature which affects performance a little.
func IsNil(value interface{}, traceSource ...bool) bool { func IsNil(value interface{}, traceSource ...bool) bool {

@ -9,7 +9,6 @@ package gfile
import ( import (
"bufio" "bufio"
"io" "io"
"io/ioutil"
"os" "os"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
@ -29,7 +28,7 @@ func GetContents(path string) string {
// GetBytes returns the file content of `path` as []byte. // GetBytes returns the file content of `path` as []byte.
// It returns nil if it fails reading. // It returns nil if it fails reading.
func GetBytes(path string) []byte { func GetBytes(path string) []byte {
data, err := ioutil.ReadFile(path) data, err := os.ReadFile(path)
if err != nil { if err != nil {
return nil return nil
} }

@ -8,7 +8,6 @@ package gfile
import ( import (
"io" "io"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -113,7 +112,7 @@ func CopyDir(src string, dst string) (err error) {
return return
} }
} }
entries, err := ioutil.ReadDir(src) entries, err := os.ReadDir(src)
if err != nil { if err != nil {
err = gerror.Wrapf(err, `read directory failed for path "%s"`, src) err = gerror.Wrapf(err, `read directory failed for path "%s"`, src)
return return
@ -127,7 +126,7 @@ func CopyDir(src string, dst string) (err error) {
} }
} else { } else {
// Skip symlinks. // Skip symlinks.
if entry.Mode()&os.ModeSymlink != 0 { if entry.Type()&os.ModeSymlink != 0 {
continue continue
} }
if err = CopyFile(srcPath, dstPath); err != nil { if err = CopyFile(srcPath, dstPath); err != nil {

@ -62,7 +62,7 @@ func newFilePool(p *Pool, path string, flag int, perm os.FileMode, ttl time.Dura
// File retrieves file item from the file pointer pool and returns it. It creates one if // File retrieves file item from the file pointer pool and returns it. It creates one if
// the file pointer pool is empty. // the file pointer pool is empty.
// Note that it should be closed when it will never be used. When it's closed, it is not // Note that it should be closed when it will never be used. When it's closed, it is not
// really closed the underlying file pointer but put back to the file pinter pool. // really closed the underlying file pointer but put back to the file pointer pool.
func (p *Pool) File() (*File, error) { func (p *Pool) File() (*File, error) {
if v, err := p.pool.Get(); err != nil { if v, err := p.pool.Get(); err != nil {
return nil, err return nil, err

@ -8,6 +8,8 @@ package gfsnotify
import ( import (
"context" "context"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/container/glist" "github.com/gogf/gf/v2/container/glist"
"github.com/gogf/gf/v2/internal/intlog" "github.com/gogf/gf/v2/internal/intlog"
@ -127,6 +129,9 @@ func (w *Watcher) eventLoop() {
case callbackExitEventPanicStr: case callbackExitEventPanicStr:
w.RemoveCallback(callback.Id) w.RemoveCallback(callback.Id)
default: default:
if e, ok := err.(error); ok {
panic(gerror.WrapCode(gcode.CodeInternalPanic, e))
}
panic(err) panic(err)
} }
} }

@ -7,8 +7,9 @@
package gmlock package gmlock
import ( import (
"sync"
"github.com/gogf/gf/v2/container/gmap" "github.com/gogf/gf/v2/container/gmap"
"github.com/gogf/gf/v2/os/gmutex"
) )
// Locker is a memory based locker. // Locker is a memory based locker.
@ -42,7 +43,7 @@ func (l *Locker) TryLock(key string) bool {
// Unlock unlocks the writing lock of the `key`. // Unlock unlocks the writing lock of the `key`.
func (l *Locker) Unlock(key string) { func (l *Locker) Unlock(key string) {
if v := l.m.Get(key); v != nil { if v := l.m.Get(key); v != nil {
v.(*gmutex.Mutex).Unlock() v.(*sync.RWMutex).Unlock()
} }
} }
@ -62,7 +63,7 @@ func (l *Locker) TryRLock(key string) bool {
// RUnlock unlocks the reading lock of the `key`. // RUnlock unlocks the reading lock of the `key`.
func (l *Locker) RUnlock(key string) { func (l *Locker) RUnlock(key string) {
if v := l.m.Get(key); v != nil { if v := l.m.Get(key); v != nil {
v.(*gmutex.Mutex).RUnlock() v.(*sync.RWMutex).RUnlock()
} }
} }
@ -126,8 +127,8 @@ func (l *Locker) Clear() {
// getOrNewMutex returns the mutex of given `key` if it exists, // getOrNewMutex returns the mutex of given `key` if it exists,
// or else creates and returns a new one. // or else creates and returns a new one.
func (l *Locker) getOrNewMutex(key string) *gmutex.Mutex { func (l *Locker) getOrNewMutex(key string) *sync.RWMutex {
return l.m.GetOrSetFuncLock(key, func() interface{} { return l.m.GetOrSetFuncLock(key, func() interface{} {
return gmutex.New() return &sync.RWMutex{}
}).(*gmutex.Mutex) }).(*sync.RWMutex)
} }

@ -1,224 +0,0 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package gmutex implements graceful concurrent-safe mutex with more rich features.
package gmutex
import (
"math"
"runtime"
"github.com/gogf/gf/v2/container/gtype"
)
// Mutex is a high level Mutex, which implements more rich features for mutex.
type Mutex struct {
state *gtype.Int32 // Indicates the state of mutex. -1: writing locked; > 1 reading locked.
writer *gtype.Int32 // Pending writer count.
reader *gtype.Int32 // Pending reader count.
writing chan struct{} // Channel for writer blocking.
reading chan struct{} // Channel for reader blocking.
}
// New creates and returns a new mutex.
func New() *Mutex {
return &Mutex{
state: gtype.NewInt32(),
writer: gtype.NewInt32(),
reader: gtype.NewInt32(),
writing: make(chan struct{}, 1),
reading: make(chan struct{}, math.MaxInt32),
}
}
// Lock locks the mutex for writing purpose.
// If the mutex is already locked by another goroutine for reading or writing,
// it blocks until the lock is available.
func (m *Mutex) Lock() {
for {
// Using CAS operation to get the writing lock atomically.
if m.state.Cas(0, -1) {
return
}
// It or else blocks to wait for the next chance.
m.writer.Add(1)
<-m.writing
}
}
// Unlock unlocks writing lock on the mutex.
// It is safe to be called multiple times even there's no locks.
func (m *Mutex) Unlock() {
if m.state.Cas(-1, 0) {
// Note that there might be more than one goroutines can enter this block.
var n int32
// Writing lock unlocks, then first check the blocked readers.
// If there are readers blocked, it unlocks them with preemption.
for {
if n = m.reader.Val(); n > 0 {
if m.reader.Cas(n, 0) {
for ; n > 0; n-- {
m.reading <- struct{}{}
}
break
} else {
runtime.Gosched()
}
} else {
break
}
}
// It then also kindly feeds the pending writers with one chance.
if n = m.writer.Val(); n > 0 {
if m.writer.Cas(n, n-1) {
m.writing <- struct{}{}
}
}
}
}
// TryLock tries locking the mutex for writing purpose.
// It returns true immediately if success, or if there's a write/reading lock on the mutex,
// it returns false immediately.
func (m *Mutex) TryLock() bool {
return m.state.Cas(0, -1)
}
// RLock locks mutex for reading purpose.
// If the mutex is already locked for writing,
// it blocks until the lock is available.
func (m *Mutex) RLock() {
var n int32
for {
if n = m.state.Val(); n >= 0 {
// If there's no writing lock currently, then do the reading lock checks.
if m.state.Cas(n, n+1) {
return
} else {
runtime.Gosched()
}
} else {
// It or else pends the reader.
m.reader.Add(1)
<-m.reading
}
}
}
// RUnlock unlocks the reading lock on the mutex.
// It is safe to be called multiple times even there's no locks.
func (m *Mutex) RUnlock() {
var n int32
for {
if n = m.state.Val(); n >= 1 {
if m.state.Cas(n, n-1) {
break
} else {
runtime.Gosched()
}
} else {
break
}
}
// Reading lock unlocks, it then only check the blocked writers.
// Note that it is not necessary to check the pending readers here.
// `n == 1` means the state of mutex comes down to zero.
if n == 1 {
if n = m.writer.Val(); n > 0 {
if m.writer.Cas(n, n-1) {
m.writing <- struct{}{}
}
}
}
}
// TryRLock tries locking the mutex for reading purpose.
// It returns true immediately if success, or if there's a writing lock on the mutex,
// it returns false immediately.
func (m *Mutex) TryRLock() bool {
var n int32
for {
if n = m.state.Val(); n >= 0 {
if m.state.Cas(n, n+1) {
return true
} else {
runtime.Gosched()
}
} else {
return false
}
}
}
// IsLocked checks whether the mutex is locked with writing or reading lock.
// Note that the result might be changed after it's called,
// so it cannot be the criterion for atomic operations.
func (m *Mutex) IsLocked() bool {
return m.state.Val() != 0
}
// IsWLocked checks whether the mutex is locked by writing lock.
// Note that the result might be changed after it's called,
// so it cannot be the criterion for atomic operations.
func (m *Mutex) IsWLocked() bool {
return m.state.Val() < 0
}
// IsRLocked checks whether the mutex is locked by reading lock.
// Note that the result might be changed after it's called,
// so it cannot be the criterion for atomic operations.
func (m *Mutex) IsRLocked() bool {
return m.state.Val() > 0
}
// LockFunc locks the mutex for writing with given callback function `f`.
// If there's a write/reading lock the mutex, it will blocks until the lock is released.
//
// It releases the lock after `f` is executed.
func (m *Mutex) LockFunc(f func()) {
m.Lock()
defer m.Unlock()
f()
}
// RLockFunc locks the mutex for reading with given callback function `f`.
// If there's a writing lock the mutex, it will blocks until the lock is released.
//
// It releases the lock after `f` is executed.
func (m *Mutex) RLockFunc(f func()) {
m.RLock()
defer m.RUnlock()
f()
}
// TryLockFunc tries locking the mutex for writing with given callback function `f`.
// it returns true immediately if success, or if there's a write/reading lock on the mutex,
// it returns false immediately.
//
// It releases the lock after `f` is executed.
func (m *Mutex) TryLockFunc(f func()) (result bool) {
if m.TryLock() {
result = true
defer m.Unlock()
f()
}
return
}
// TryRLockFunc tries locking the mutex for reading with given callback function `f`.
// It returns true immediately if success, or if there's a writing lock on the mutex,
// it returns false immediately.
//
// It releases the lock after `f` is executed.
func (m *Mutex) TryRLockFunc(f func()) (result bool) {
if m.TryRLock() {
result = true
defer m.RUnlock()
f()
}
return
}

@ -155,7 +155,7 @@ func (p *Pool) AddWithRecover(ctx context.Context, userFunc Func, recoverFunc Re
if v, ok := exception.(error); ok && gerror.HasStack(v) { if v, ok := exception.(error); ok && gerror.HasStack(v) {
recoverFunc(ctx, v) recoverFunc(ctx, v)
} else { } else {
recoverFunc(ctx, gerror.Newf(`%+v`, exception)) recoverFunc(ctx, gerror.NewCodef(gcode.CodeInternalPanic, "%+v", exception))
} }
} }
} }

@ -17,35 +17,35 @@ import (
var ( var (
// Refer: http://php.net/manual/en/function.date.php // Refer: http://php.net/manual/en/function.date.php
formats = map[byte]string{ formats = map[byte]string{
'd': "02", // Day: Day of the month, 2 digits with leading zeros. Eg: 01 to 31. 'd': "02", // Day: Day of the month, 2 digits with leading zeros. Eg: 01 to 31.
'D': "Mon", // Day: A textual representation of a day, three letters. Eg: Mon through Sun. 'D': "Mon", // Day: A textual representation of a day, three letters. Eg: Mon through Sun.
'w': "Monday", // Day: Numeric representation of the day of the week. Eg: 0 (for Sunday) through 6 (for Saturday). 'w': "Monday", // Day: Numeric representation of the day of the week. Eg: 0 (for Sunday) through 6 (for Saturday).
'N': "Monday", // Day: ISO-8601 numeric representation of the day of the week. Eg: 1 (for Monday) through 7 (for Sunday). 'N': "Monday", // Day: ISO-8601 numeric representation of the day of the week. Eg: 1 (for Monday) through 7 (for Sunday).
'j': "=j=02", // Day: Day of the month without leading zeros. Eg: 1 to 31. 'j': "=j=02", // Day: Day of the month without leading zeros. Eg: 1 to 31.
'S': "02", // Day: English ordinal suffix for the day of the month, 2 characters. Eg: st, nd, rd or th. Works well with j. 'S': "02", // Day: English ordinal suffix for the day of the month, 2 characters. Eg: st, nd, rd or th. Works well with j.
'l': "Monday", // Day: A full textual representation of the day of the week. Eg: Sunday through Saturday. 'l': "Monday", // Day: A full textual representation of the day of the week. Eg: Sunday through Saturday.
'z': "", // Day: The day of the year (starting from 0). Eg: 0 through 365. 'z': "", // Day: The day of the year (starting from 0). Eg: 0 through 365.
'W': "", // Week: ISO-8601 week number of year, weeks starting on Monday. Eg: 42 (the 42nd week in the year). 'W': "", // Week: ISO-8601 week number of year, weeks starting on Monday. Eg: 42 (the 42nd week in the year).
'F': "January", // Month: A full textual representation of a month, such as January or March. Eg: January through December. 'F': "January", // Month: A full textual representation of a month, such as January or March. Eg: January through December.
'm': "01", // Month: Numeric representation of a month, with leading zeros. Eg: 01 through 12. 'm': "01", // Month: Numeric representation of a month, with leading zeros. Eg: 01 through 12.
'M': "Jan", // Month: A short textual representation of a month, three letters. Eg: Jan through Dec. 'M': "Jan", // Month: A short textual representation of a month, three letters. Eg: Jan through Dec.
'n': "1", // Month: Numeric representation of a month, without leading zeros. Eg: 1 through 12. 'n': "1", // Month: Numeric representation of a month, without leading zeros. Eg: 1 through 12.
't': "", // Month: Number of days in the given month. Eg: 28 through 31. 't': "", // Month: Number of days in the given month. Eg: 28 through 31.
'Y': "2006", // Year: A full numeric representation of a year, 4 digits. Eg: 1999 or 2003. 'Y': "2006", // Year: A full numeric representation of a year, 4 digits. Eg: 1999 or 2003.
'y': "06", // Year: A two digit representation of a year. Eg: 99 or 03. 'y': "06", // Year: A two-digit representation of a year. Eg: 99 or 03.
'a': "pm", // Time: Lowercase Ante meridiem and Post meridiem. Eg: am or pm. 'a': "pm", // Time: Lowercase Ante meridiem and Post meridiem. Eg: am or pm.
'A': "PM", // Time: Uppercase Ante meridiem and Post meridiem. Eg: AM or PM. 'A': "PM", // Time: Uppercase Ante meridiem and Post meridiem. Eg: AM or PM.
'g': "3", // Time: 12-hour format of an hour without leading zeros. Eg: 1 through 12. 'g': "3", // Time: 12-hour format of an hour without leading zeros. Eg: 1 through 12.
'G': "=G=15", // Time: 24-hour format of an hour without leading zeros. Eg: 0 through 23. 'G': "=G=15", // Time: 24-hour format of an hour without leading zeros. Eg: 0 through 23.
'h': "03", // Time: 12-hour format of an hour with leading zeros. Eg: 01 through 12. 'h': "03", // Time: 12-hour format of an hour with leading zeros. Eg: 01 through 12.
'H': "15", // Time: 24-hour format of an hour with leading zeros. Eg: 00 through 23. 'H': "15", // Time: 24-hour format of an hour with leading zeros. Eg: 00 through 23.
'i': "04", // Time: Minutes with leading zeros. Eg: 00 to 59. 'i': "04", // Time: Minutes with leading zeros. Eg: 00 to 59.
's': "05", // Time: Seconds with leading zeros. Eg: 00 through 59. 's': "05", // Time: Seconds with leading zeros. Eg: 00 through 59.
'u': "=u=.000", // Time: Milliseconds. Eg: 234, 678. 'u': "=u=.000", // Time: Milliseconds. Eg: 234, 678.
'U': "", // Time: Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT). 'U': "", // Time: Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT).
'O': "-0700", // Zone: Difference to Greenwich time (GMT) in hours. Eg: +0200. 'O': "-0700", // Zone: Difference to Greenwich time (GMT) in hours. Eg: +0200.
'P': "-07:00", // Zone: Difference to Greenwich time (GMT) with colon between hours and minutes. Eg: +02:00. 'P': "-07:00", // Zone: Difference to Greenwich time (GMT) with colon between hours and minutes. Eg: +02:00.
'T': "MST", // Zone: Timezone abbreviation. Eg: UTC, EST, MDT ... 'T': "MST", // Zone: Timezone abbreviation. Eg: UTC, EST, MDT ...
'c': "2006-01-02T15:04:05-07:00", // Format: ISO 8601 date. Eg: 2004-02-12T15:19:21+00:00. 'c': "2006-01-02T15:04:05-07:00", // Format: ISO 8601 date. Eg: 2004-02-12T15:19:21+00:00.
'r': "Mon, 02 Jan 06 15:04 MST", // Format: RFC 2822 formatted date. Eg: Thu, 21 Dec 2000 16:01:07 +0200. 'r': "Mon, 02 Jan 06 15:04 MST", // Format: RFC 2822 formatted date. Eg: Thu, 21 Dec 2000 16:01:07 +0200.
} }
@ -159,7 +159,11 @@ func (t *Time) LayoutNew(layout string) *Time {
if t == nil { if t == nil {
return nil return nil
} }
return NewFromStr(t.Layout(layout)) newTime, err := StrToTimeLayout(t.Layout(layout), layout)
if err != nil {
panic(err)
}
return newTime
} }
// LayoutTo formats `t` with stdlib layout. // LayoutTo formats `t` with stdlib layout.
@ -167,7 +171,11 @@ func (t *Time) LayoutTo(layout string) *Time {
if t == nil { if t == nil {
return nil return nil
} }
t.Time = NewFromStr(t.Layout(layout)).Time newTime, err := StrToTimeLayout(t.Layout(layout), layout)
if err != nil {
panic(err)
}
t.Time = newTime.Time
return t return t
} }

@ -8,6 +8,7 @@ package gtimer
import ( import (
"context" "context"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/container/gtype" "github.com/gogf/gf/v2/container/gtype"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
@ -51,7 +52,7 @@ func (entry *Entry) Run() {
if v, ok := exception.(error); ok && gerror.HasStack(v) { if v, ok := exception.(error); ok && gerror.HasStack(v) {
panic(v) panic(v)
} else { } else {
panic(gerror.Newf(`exception recovered: %+v`, exception)) panic(gerror.NewCodef(gcode.CodeInternalPanic, "exception recovered: %+v", exception))
} }
} else { } else {
entry.Close() entry.Close()

@ -14,8 +14,9 @@ import (
) )
// Convert converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string. // Convert converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string.
//
// The optional parameter `extraParams` is used for additional necessary parameter for this conversion. // The optional parameter `extraParams` is used for additional necessary parameter for this conversion.
// It supports common types conversion as its conversion based on type name string. // It supports common basic types conversion as its conversion based on type name string.
func Convert(fromValue interface{}, toTypeName string, extraParams ...interface{}) interface{} { func Convert(fromValue interface{}, toTypeName string, extraParams ...interface{}) interface{} {
return doConvert(doConvertInput{ return doConvert(doConvertInput{
FromValue: fromValue, FromValue: fromValue,

@ -0,0 +1,155 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gconv
import (
"reflect"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
)
type (
converterInType = reflect.Type
converterOutType = reflect.Type
converterFunc = reflect.Value
)
// customConverters for internal converter storing.
var customConverters = make(map[converterInType]map[converterOutType]converterFunc)
// RegisterConverter to register custom converter.
// It must be registered before you use this custom converting feature.
// It is suggested to do it in boot.
//
// Note:
// 1. The parameter `fn` must be defined as pattern `func(T1) (T2, error)`.
// It will convert type `T1` to type `T2`.
// 2. The `T1` should not be type of pointer, but the `T2` should be type of pointer.
func RegisterConverter(fn interface{}) (err error) {
var (
fnReflectType = reflect.TypeOf(fn)
errType = reflect.TypeOf((*error)(nil)).Elem()
)
if fnReflectType.Kind() != reflect.Func ||
fnReflectType.NumIn() != 1 || fnReflectType.NumOut() != 2 ||
!fnReflectType.Out(1).Implements(errType) {
err = gerror.NewCodef(
gcode.CodeInvalidParameter,
"parameter must be type of function and defined as pattern `func(T1) (T2, error)`, but defined as `%s`",
fnReflectType.String(),
)
return
}
// The Key and Value of the converter map should not be pointer.
var (
inType = fnReflectType.In(0)
outType = fnReflectType.Out(0)
)
if inType.Kind() == reflect.Pointer {
err = gerror.NewCodef(
gcode.CodeInvalidParameter,
"invalid input parameter type `%s`: should not be type of pointer",
inType.String(),
)
return
}
if outType.Kind() != reflect.Pointer {
err = gerror.NewCodef(
gcode.CodeInvalidParameter,
"invalid output parameter type `%s`: should be type of pointer",
outType.String(),
)
return
}
registeredOutTypeMap, ok := customConverters[inType]
if !ok {
registeredOutTypeMap = make(map[converterOutType]converterFunc)
customConverters[inType] = registeredOutTypeMap
}
if _, ok = registeredOutTypeMap[outType]; ok {
err = gerror.NewCodef(
gcode.CodeInvalidOperation,
"the converter parameter type `%s` to type `%s` has already been registered",
inType.String(), outType.String(),
)
return
}
registeredOutTypeMap[outType] = reflect.ValueOf(fn)
return
}
// callCustomConverter call the custom converter. It will try some possible type.
func callCustomConverter(srcReflectValue reflect.Value, dstReflectValue reflect.Value) (converted bool, err error) {
if len(customConverters) == 0 {
return false, nil
}
var (
ok bool
srcType = srcReflectValue.Type()
)
for srcType.Kind() == reflect.Pointer {
srcType = srcType.Elem()
}
var (
registeredOutTypeMap map[converterOutType]converterFunc
registeredConverterFunc converterFunc
)
// firstly, it searches the map by input parameter type.
registeredOutTypeMap, ok = customConverters[srcType]
if !ok {
return false, nil
}
var dstType = dstReflectValue.Type()
if dstType.Kind() == reflect.Pointer && dstReflectValue.Elem().Kind() == reflect.Pointer {
dstType = dstReflectValue.Elem().Type()
} else if dstType.Kind() != reflect.Pointer && dstReflectValue.CanAddr() {
dstType = dstReflectValue.Addr().Type()
}
// secondly, it searches the input parameter type map
// and finds the result converter function by the output parameter type.
registeredConverterFunc, ok = registeredOutTypeMap[dstType]
if !ok {
return false, nil
}
// Converter function calling.
for srcReflectValue.Type() != srcType {
srcReflectValue = srcReflectValue.Elem()
}
result := registeredConverterFunc.Call([]reflect.Value{srcReflectValue})
if !result[1].IsNil() {
return false, result[1].Interface().(error)
}
// The `result[0]` is a pointer.
if result[0].IsNil() {
return false, nil
}
var resultValue = result[0]
for {
if resultValue.Type() == dstReflectValue.Type() && dstReflectValue.CanSet() {
dstReflectValue.Set(resultValue)
converted = true
} else if dstReflectValue.Kind() == reflect.Pointer {
if resultValue.Type() == dstReflectValue.Elem().Type() && dstReflectValue.Elem().CanSet() {
dstReflectValue.Elem().Set(resultValue)
converted = true
}
}
if converted {
break
}
if resultValue.Kind() == reflect.Pointer {
resultValue = resultValue.Elem()
} else {
break
}
}
return converted, nil
}

@ -29,7 +29,7 @@ const (
// tags that will be detected, otherwise it detects the tags in order of: // tags that will be detected, otherwise it detects the tags in order of:
// gconv, json, field name. // gconv, json, field name.
func Map(value interface{}, tags ...string) map[string]interface{} { func Map(value interface{}, tags ...string) map[string]interface{} {
return doMapConvert(value, recursiveTypeAuto, tags...) return doMapConvert(value, recursiveTypeAuto, false, tags...)
} }
// MapDeep does Map function recursively, which means if the attribute of `value` // MapDeep does Map function recursively, which means if the attribute of `value`
@ -37,14 +37,14 @@ func Map(value interface{}, tags ...string) map[string]interface{} {
// a map[string]interface{} type variable. // a map[string]interface{} type variable.
// Also see Map. // Also see Map.
func MapDeep(value interface{}, tags ...string) map[string]interface{} { func MapDeep(value interface{}, tags ...string) map[string]interface{} {
return doMapConvert(value, recursiveTypeTrue, tags...) return doMapConvert(value, recursiveTypeTrue, false, tags...)
} }
// doMapConvert implements the map converting. // doMapConvert implements the map converting.
// It automatically checks and converts json string to map if `value` is string/[]byte. // It automatically checks and converts json string to map if `value` is string/[]byte.
// //
// TODO completely implement the recursive converting for all types, especially the map. // TODO completely implement the recursive converting for all types, especially the map.
func doMapConvert(value interface{}, recursive recursiveType, tags ...string) map[string]interface{} { func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, tags ...string) map[string]interface{} {
if value == nil { if value == nil {
return nil return nil
} }
@ -209,6 +209,7 @@ func doMapConvert(value interface{}, recursive recursiveType, tags ...string) ma
RecursiveType: recursive, RecursiveType: recursive,
RecursiveOption: recursive == recursiveTypeTrue, RecursiveOption: recursive == recursiveTypeTrue,
Tags: newTags, Tags: newTags,
MustMapReturn: mustMapReturn,
}, },
) )
if m, ok := convertedValue.(map[string]interface{}); ok { if m, ok := convertedValue.(map[string]interface{}); ok {
@ -228,6 +229,7 @@ type doMapConvertForMapOrStructValueInput struct {
RecursiveType recursiveType // The type from top function entry. RecursiveType recursiveType // The type from top function entry.
RecursiveOption bool // Whether convert recursively for `current` operation. RecursiveOption bool // Whether convert recursively for `current` operation.
Tags []string // Map key mapping. Tags []string // Map key mapping.
MustMapReturn bool // Must return map instead of Value when empty.
} }
func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} { func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} {
@ -259,11 +261,17 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
mapKeyValue = reflectValue.MapIndex(k) mapKeyValue = reflectValue.MapIndex(k)
mapValue interface{} mapValue interface{}
) )
if mapKeyValue.IsZero() { switch {
// in case of: case mapKeyValue.IsZero():
// exception recovered: reflect: call of reflect.Value.Interface on zero Value if mapKeyValue.IsNil() {
mapValue = reflect.New(mapKeyValue.Type()).Elem() // quick check for nil value.
} else { mapValue = nil
} else {
// in case of:
// exception recovered: reflect: call of reflect.Value.Interface on zero Value
mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface()
}
default:
mapValue = mapKeyValue.Interface() mapValue = mapKeyValue.Interface()
} }
dataMap[String(k.Interface())] = doMapConvertForMapOrStructValue( dataMap[String(k.Interface())] = doMapConvertForMapOrStructValue(
@ -462,7 +470,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
} }
} }
} }
if len(dataMap) == 0 { if !in.MustMapReturn && len(dataMap) == 0 {
return in.Value return in.Value
} }
return dataMap return dataMap

@ -100,7 +100,7 @@ func doMapToMap(params interface{}, pointer interface{}, mapping ...map[string]s
if v, ok := exception.(error); ok && gerror.HasStack(v) { if v, ok := exception.(error); ok && gerror.HasStack(v) {
err = v err = v
} else { } else {
err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception) err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception)
} }
} }
}() }()

@ -113,7 +113,7 @@ func doMapToMaps(params interface{}, pointer interface{}, mapping ...map[string]
if v, ok := exception.(error); ok && gerror.HasStack(v) { if v, ok := exception.(error); ok && gerror.HasStack(v) {
err = v err = v
} else { } else {
err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception) err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception)
} }
} }
}() }()

@ -100,7 +100,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
if v, ok := exception.(error); ok && gerror.HasStack(v) { if v, ok := exception.(error); ok && gerror.HasStack(v) {
err = v err = v
} else { } else {
err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception) err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception)
} }
} }
}() }()
@ -143,6 +143,11 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
pointerElemReflectValue = pointerReflectValue.Elem() pointerElemReflectValue = pointerReflectValue.Elem()
} }
// custom convert try first
if ok, err = callCustomConverter(paramsReflectValue, pointerReflectValue); ok {
return err
}
// If `params` and `pointer` are the same type, the do directly assignment. // If `params` and `pointer` are the same type, the do directly assignment.
// For performance enhancement purpose. // For performance enhancement purpose.
if pointerElemReflectValue.IsValid() { if pointerElemReflectValue.IsValid() {
@ -179,8 +184,14 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
// For example, if `pointer` is **User, then `elem` is *User, which is a pointer to User. // For example, if `pointer` is **User, then `elem` is *User, which is a pointer to User.
if pointerElemReflectValue.Kind() == reflect.Ptr { if pointerElemReflectValue.Kind() == reflect.Ptr {
if !pointerElemReflectValue.IsValid() || pointerElemReflectValue.IsNil() { if !pointerElemReflectValue.IsValid() || pointerElemReflectValue.IsNil() {
e := reflect.New(pointerElemReflectValue.Type().Elem()).Elem() e := reflect.New(pointerElemReflectValue.Type().Elem())
pointerElemReflectValue.Set(e.Addr()) pointerElemReflectValue.Set(e)
defer func() {
if err != nil {
// If it is converted failed, it reset the `pointer` to nil.
pointerReflectValue.Elem().Set(reflect.Zero(pointerReflectValue.Type().Elem()))
}
}()
} }
// if v, ok := pointerElemReflectValue.Interface().(iUnmarshalValue); ok { // if v, ok := pointerElemReflectValue.Interface().(iUnmarshalValue); ok {
// return v.UnmarshalValue(params) // return v.UnmarshalValue(params)
@ -195,7 +206,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
// paramsMap is the map[string]interface{} type variable for params. // paramsMap is the map[string]interface{} type variable for params.
// DO NOT use MapDeep here. // DO NOT use MapDeep here.
paramsMap := Map(paramsInterface) paramsMap := doMapConvert(paramsInterface, recursiveTypeAuto, true)
if paramsMap == nil { if paramsMap == nil {
return gerror.NewCodef( return gerror.NewCodef(
gcode.CodeInvalidParameter, gcode.CodeInvalidParameter,
@ -379,6 +390,11 @@ func bindVarToStructAttr(structReflectValue reflect.Value, attrName string, valu
return return
} }
// Try to call custom converter.
if ok, err := callCustomConverter(reflect.ValueOf(value), structFieldValue); ok {
return err
}
// Common interface check. // Common interface check.
var ok bool var ok bool
if err, ok = bindVarToReflectValueWithInterfaceCheck(structFieldValue, value); ok { if err, ok = bindVarToReflectValueWithInterfaceCheck(structFieldValue, value); ok {
@ -623,7 +639,7 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma
defer func() { defer func() {
if exception := recover(); exception != nil { if exception := recover(); exception != nil {
err = gerror.NewCodef( err = gerror.NewCodef(
gcode.CodeInternalError, gcode.CodeInternalPanic,
`cannot convert value "%+v" to type "%s":%+v`, `cannot convert value "%+v" to type "%s":%+v`,
value, value,
structFieldValue.Type().String(), structFieldValue.Type().String(),

@ -53,7 +53,7 @@ func doStructs(params interface{}, pointer interface{}, mapping map[string]strin
if v, ok := exception.(error); ok && gerror.HasStack(v) { if v, ok := exception.(error); ok && gerror.HasStack(v) {
err = v err = v
} else { } else {
err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception) err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception)
} }
} }
}() }()

@ -9,6 +9,7 @@ package gutil
import ( import (
"context" "context"
"github.com/gogf/gf/v2/errors/gcode"
"reflect" "reflect"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
@ -33,7 +34,7 @@ func Try(ctx context.Context, try func(ctx context.Context)) (err error) {
if v, ok := exception.(error); ok && gerror.HasStack(v) { if v, ok := exception.(error); ok && gerror.HasStack(v) {
err = v err = v
} else { } else {
err = gerror.Newf(`%+v`, exception) err = gerror.NewCodef(gcode.CodeInternalPanic, "%+v", exception)
} }
} }
}() }()
@ -49,7 +50,7 @@ func TryCatch(ctx context.Context, try func(ctx context.Context), catch ...func(
if v, ok := exception.(error); ok && gerror.HasStack(v) { if v, ok := exception.(error); ok && gerror.HasStack(v) {
catch[0](ctx, v) catch[0](ctx, v)
} else { } else {
catch[0](ctx, gerror.Newf(`%+v`, exception)) catch[0](ctx, gerror.NewCodef(gcode.CodeInternalPanic, "%+v", exception))
} }
} }
}() }()

@ -1,3 +1,15 @@
# 5.4.3 (August 5, 2023)
* Fix: QCharArrayOID was defined with the wrong OID (Christoph Engelbert)
* Fix: connect_timeout for sslmode=allow|prefer (smaher-edb)
* Fix: pgxpool: background health check cannot overflow pool
* Fix: Check for nil in defer when sending batch (recover properly from panic)
* Fix: json scan of non-string pointer to pointer
* Fix: zeronull.Timestamptz should use pgtype.Timestamptz
* Fix: NewConnsCount was not correctly counting connections created by Acquire directly. (James Hartig)
* RowTo(AddrOf)StructByPos ignores fields with "-" db tag
* Optimization: improve text format numeric parsing (horpto)
# 5.4.2 (July 11, 2023) # 5.4.2 (July 11, 2023)
* Fix: RowScanner errors are fatal to Rows * Fix: RowScanner errors are fatal to Rows

@ -1,5 +1,5 @@
[![Go Reference](https://pkg.go.dev/badge/github.com/jackc/pgx/v5.svg)](https://pkg.go.dev/github.com/jackc/pgx/v5) [![Go Reference](https://pkg.go.dev/badge/github.com/jackc/pgx/v5.svg)](https://pkg.go.dev/github.com/jackc/pgx/v5)
![Build Status](https://github.com/jackc/pgx/actions/workflows/ci.yml/badge.svg) [![Build Status](https://github.com/jackc/pgx/actions/workflows/ci.yml/badge.svg)](https://github.com/jackc/pgx/actions/workflows/ci.yml)
# pgx - PostgreSQL Driver and Toolkit # pgx - PostgreSQL Driver and Toolkit
@ -139,8 +139,8 @@ These adapters can be used with the tracelog package.
### [github.com/pashagolub/pgxmock](https://github.com/pashagolub/pgxmock) ### [github.com/pashagolub/pgxmock](https://github.com/pashagolub/pgxmock)
pgxmock is a mock library implementing pgx interfaces. pgxmock is a mock library implementing pgx interfaces.
pgxmock has one and only purpose - to simulate pgx behavior in tests, without needing a real database connection. pgxmock has one and only purpose - to simulate pgx behavior in tests, without needing a real database connection.
### [github.com/georgysavva/scany](https://github.com/georgysavva/scany) ### [github.com/georgysavva/scany](https://github.com/georgysavva/scany)

@ -194,7 +194,7 @@ func ParseConfigWithOptions(connString string, options ParseConfigOptions) (*Con
return connConfig, nil return connConfig, nil
} }
// ParseConfig creates a ConnConfig from a connection string. ParseConfig handles all options that pgconn.ParseConfig // ParseConfig creates a ConnConfig from a connection string. ParseConfig handles all options that [pgconn.ParseConfig]
// does. In addition, it accepts the following options: // does. In addition, it accepts the following options:
// //
// - default_query_exec_mode. // - default_query_exec_mode.
@ -507,7 +507,7 @@ func (c *Conn) execSimpleProtocol(ctx context.Context, sql string, arguments []a
mrr := c.pgConn.Exec(ctx, sql) mrr := c.pgConn.Exec(ctx, sql)
for mrr.NextResult() { for mrr.NextResult() {
commandTag, err = mrr.ResultReader().Close() commandTag, _ = mrr.ResultReader().Close()
} }
err = mrr.Close() err = mrr.Close()
return commandTag, err return commandTag, err
@ -1064,7 +1064,7 @@ func (c *Conn) sendBatchQueryExecModeDescribeExec(ctx context.Context, b *Batch)
func (c *Conn) sendBatchExtendedWithDescription(ctx context.Context, b *Batch, distinctNewQueries []*pgconn.StatementDescription, sdCache stmtcache.Cache) (pbr *pipelineBatchResults) { func (c *Conn) sendBatchExtendedWithDescription(ctx context.Context, b *Batch, distinctNewQueries []*pgconn.StatementDescription, sdCache stmtcache.Cache) (pbr *pipelineBatchResults) {
pipeline := c.pgConn.StartPipeline(context.Background()) pipeline := c.pgConn.StartPipeline(context.Background())
defer func() { defer func() {
if pbr.err != nil { if pbr != nil && pbr.err != nil {
pipeline.Close() pipeline.Close()
} }
}() }()

@ -7,17 +7,17 @@ details.
Establishing a Connection Establishing a Connection
The primary way of establishing a connection is with `pgx.Connect`. The primary way of establishing a connection is with [pgx.Connect]:
conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL")) conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
The database connection string can be in URL or DSN format. Both PostgreSQL settings and pgx settings can be specified The database connection string can be in URL or DSN format. Both PostgreSQL settings and pgx settings can be specified
here. In addition, a config struct can be created by `ParseConfig` and modified before establishing the connection with here. In addition, a config struct can be created by [ParseConfig] and modified before establishing the connection with
`ConnectConfig` to configure settings such as tracing that cannot be configured with a connection string. [ConnectConfig] to configure settings such as tracing that cannot be configured with a connection string.
Connection Pool Connection Pool
`*pgx.Conn` represents a single connection to the database and is not concurrency safe. Use package [*pgx.Conn] represents a single connection to the database and is not concurrency safe. Use package
github.com/jackc/pgx/v5/pgxpool for a concurrency safe connection pool. github.com/jackc/pgx/v5/pgxpool for a concurrency safe connection pool.
Query Interface Query Interface

@ -26,7 +26,7 @@ type AfterConnectFunc func(ctx context.Context, pgconn *PgConn) error
type ValidateConnectFunc func(ctx context.Context, pgconn *PgConn) error type ValidateConnectFunc func(ctx context.Context, pgconn *PgConn) error
type GetSSLPasswordFunc func(ctx context.Context) string type GetSSLPasswordFunc func(ctx context.Context) string
// Config is the settings used to establish a connection to a PostgreSQL server. It must be created by ParseConfig. A // Config is the settings used to establish a connection to a PostgreSQL server. It must be created by [ParseConfig]. A
// manually initialized Config will cause ConnectConfig to panic. // manually initialized Config will cause ConnectConfig to panic.
type Config struct { type Config struct {
Host string // host (e.g. localhost) or absolute path to unix domain socket directory (e.g. /private/tmp) Host string // host (e.g. localhost) or absolute path to unix domain socket directory (e.g. /private/tmp)

@ -97,7 +97,7 @@ type PgConn struct {
} }
// Connect establishes a connection to a PostgreSQL server using the environment and connString (in URL or DSN format) // Connect establishes a connection to a PostgreSQL server using the environment and connString (in URL or DSN format)
// to provide configuration. See documentation for ParseConfig for details. ctx can be used to cancel a connect attempt. // to provide configuration. See documentation for [ParseConfig] for details. ctx can be used to cancel a connect attempt.
func Connect(ctx context.Context, connString string) (*PgConn, error) { func Connect(ctx context.Context, connString string) (*PgConn, error) {
config, err := ParseConfig(connString) config, err := ParseConfig(connString)
if err != nil { if err != nil {
@ -108,7 +108,7 @@ func Connect(ctx context.Context, connString string) (*PgConn, error) {
} }
// Connect establishes a connection to a PostgreSQL server using the environment and connString (in URL or DSN format) // Connect establishes a connection to a PostgreSQL server using the environment and connString (in URL or DSN format)
// and ParseConfigOptions to provide additional configuration. See documentation for ParseConfig for details. ctx can be // and ParseConfigOptions to provide additional configuration. See documentation for [ParseConfig] for details. ctx can be
// used to cancel a connect attempt. // used to cancel a connect attempt.
func ConnectWithOptions(ctx context.Context, connString string, parseConfigOptions ParseConfigOptions) (*PgConn, error) { func ConnectWithOptions(ctx context.Context, connString string, parseConfigOptions ParseConfigOptions) (*PgConn, error) {
config, err := ParseConfigWithOptions(connString, parseConfigOptions) config, err := ParseConfigWithOptions(connString, parseConfigOptions)
@ -120,7 +120,7 @@ func ConnectWithOptions(ctx context.Context, connString string, parseConfigOptio
} }
// Connect establishes a connection to a PostgreSQL server using config. config must have been constructed with // Connect establishes a connection to a PostgreSQL server using config. config must have been constructed with
// ParseConfig. ctx can be used to cancel a connect attempt. // [ParseConfig]. ctx can be used to cancel a connect attempt.
// //
// If config.Fallbacks are present they will sequentially be tried in case of error establishing network connection. An // If config.Fallbacks are present they will sequentially be tried in case of error establishing network connection. An
// authentication error will terminate the chain of attempts (like libpq: // authentication error will terminate the chain of attempts (like libpq:
@ -154,12 +154,15 @@ func ConnectConfig(octx context.Context, config *Config) (pgConn *PgConn, err er
foundBestServer := false foundBestServer := false
var fallbackConfig *FallbackConfig var fallbackConfig *FallbackConfig
for _, fc := range fallbackConfigs { for i, fc := range fallbackConfigs {
// ConnectTimeout restricts the whole connection process. // ConnectTimeout restricts the whole connection process.
if config.ConnectTimeout != 0 { if config.ConnectTimeout != 0 {
var cancel context.CancelFunc // create new context first time or when previous host was different
ctx, cancel = context.WithTimeout(octx, config.ConnectTimeout) if i == 0 || (fallbackConfigs[i].Host != fallbackConfigs[i-1].Host) {
defer cancel() var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(octx, config.ConnectTimeout)
defer cancel()
}
} else { } else {
ctx = octx ctx = octx
} }

@ -6,15 +6,18 @@ import (
"io" "io"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
) )
// tracer traces the messages send to and from a Backend or Frontend. The format it produces roughly mimics the // tracer traces the messages send to and from a Backend or Frontend. The format it produces roughly mimics the
// format produced by the libpq C function PQtrace. // format produced by the libpq C function PQtrace.
type tracer struct { type tracer struct {
TracerOptions
mux sync.Mutex
w io.Writer w io.Writer
buf *bytes.Buffer buf *bytes.Buffer
TracerOptions
} }
// TracerOptions controls tracing behavior. It is roughly equivalent to the libpq function PQsetTraceFlags. // TracerOptions controls tracing behavior. It is roughly equivalent to the libpq function PQsetTraceFlags.
@ -119,278 +122,255 @@ func (t *tracer) traceMessage(sender byte, encodedLen int32, msg Message) {
case *Terminate: case *Terminate:
t.traceTerminate(sender, encodedLen, msg) t.traceTerminate(sender, encodedLen, msg)
default: default:
t.beginTrace(sender, encodedLen, "Unknown") t.writeTrace(sender, encodedLen, "Unknown", nil)
t.finishTrace()
} }
} }
func (t *tracer) traceAuthenticationCleartextPassword(sender byte, encodedLen int32, msg *AuthenticationCleartextPassword) { func (t *tracer) traceAuthenticationCleartextPassword(sender byte, encodedLen int32, msg *AuthenticationCleartextPassword) {
t.beginTrace(sender, encodedLen, "AuthenticationCleartextPassword") t.writeTrace(sender, encodedLen, "AuthenticationCleartextPassword", nil)
t.finishTrace()
} }
func (t *tracer) traceAuthenticationGSS(sender byte, encodedLen int32, msg *AuthenticationGSS) { func (t *tracer) traceAuthenticationGSS(sender byte, encodedLen int32, msg *AuthenticationGSS) {
t.beginTrace(sender, encodedLen, "AuthenticationGSS") t.writeTrace(sender, encodedLen, "AuthenticationGSS", nil)
t.finishTrace()
} }
func (t *tracer) traceAuthenticationGSSContinue(sender byte, encodedLen int32, msg *AuthenticationGSSContinue) { func (t *tracer) traceAuthenticationGSSContinue(sender byte, encodedLen int32, msg *AuthenticationGSSContinue) {
t.beginTrace(sender, encodedLen, "AuthenticationGSSContinue") t.writeTrace(sender, encodedLen, "AuthenticationGSSContinue", nil)
t.finishTrace()
} }
func (t *tracer) traceAuthenticationMD5Password(sender byte, encodedLen int32, msg *AuthenticationMD5Password) { func (t *tracer) traceAuthenticationMD5Password(sender byte, encodedLen int32, msg *AuthenticationMD5Password) {
t.beginTrace(sender, encodedLen, "AuthenticationMD5Password") t.writeTrace(sender, encodedLen, "AuthenticationMD5Password", nil)
t.finishTrace()
} }
func (t *tracer) traceAuthenticationOk(sender byte, encodedLen int32, msg *AuthenticationOk) { func (t *tracer) traceAuthenticationOk(sender byte, encodedLen int32, msg *AuthenticationOk) {
t.beginTrace(sender, encodedLen, "AuthenticationOk") t.writeTrace(sender, encodedLen, "AuthenticationOk", nil)
t.finishTrace()
} }
func (t *tracer) traceAuthenticationSASL(sender byte, encodedLen int32, msg *AuthenticationSASL) { func (t *tracer) traceAuthenticationSASL(sender byte, encodedLen int32, msg *AuthenticationSASL) {
t.beginTrace(sender, encodedLen, "AuthenticationSASL") t.writeTrace(sender, encodedLen, "AuthenticationSASL", nil)
t.finishTrace()
} }
func (t *tracer) traceAuthenticationSASLContinue(sender byte, encodedLen int32, msg *AuthenticationSASLContinue) { func (t *tracer) traceAuthenticationSASLContinue(sender byte, encodedLen int32, msg *AuthenticationSASLContinue) {
t.beginTrace(sender, encodedLen, "AuthenticationSASLContinue") t.writeTrace(sender, encodedLen, "AuthenticationSASLContinue", nil)
t.finishTrace()
} }
func (t *tracer) traceAuthenticationSASLFinal(sender byte, encodedLen int32, msg *AuthenticationSASLFinal) { func (t *tracer) traceAuthenticationSASLFinal(sender byte, encodedLen int32, msg *AuthenticationSASLFinal) {
t.beginTrace(sender, encodedLen, "AuthenticationSASLFinal") t.writeTrace(sender, encodedLen, "AuthenticationSASLFinal", nil)
t.finishTrace()
} }
func (t *tracer) traceBackendKeyData(sender byte, encodedLen int32, msg *BackendKeyData) { func (t *tracer) traceBackendKeyData(sender byte, encodedLen int32, msg *BackendKeyData) {
t.beginTrace(sender, encodedLen, "BackendKeyData") t.writeTrace(sender, encodedLen, "BackendKeyData", func() {
if t.RegressMode { if t.RegressMode {
t.buf.WriteString("\t NNNN NNNN") t.buf.WriteString("\t NNNN NNNN")
} else { } else {
fmt.Fprintf(t.buf, "\t %d %d", msg.ProcessID, msg.SecretKey) fmt.Fprintf(t.buf, "\t %d %d", msg.ProcessID, msg.SecretKey)
} }
t.finishTrace() })
} }
func (t *tracer) traceBind(sender byte, encodedLen int32, msg *Bind) { func (t *tracer) traceBind(sender byte, encodedLen int32, msg *Bind) {
t.beginTrace(sender, encodedLen, "Bind") t.writeTrace(sender, encodedLen, "Bind", func() {
fmt.Fprintf(t.buf, "\t %s %s %d", traceDoubleQuotedString([]byte(msg.DestinationPortal)), traceDoubleQuotedString([]byte(msg.PreparedStatement)), len(msg.ParameterFormatCodes)) fmt.Fprintf(t.buf, "\t %s %s %d", traceDoubleQuotedString([]byte(msg.DestinationPortal)), traceDoubleQuotedString([]byte(msg.PreparedStatement)), len(msg.ParameterFormatCodes))
for _, fc := range msg.ParameterFormatCodes { for _, fc := range msg.ParameterFormatCodes {
fmt.Fprintf(t.buf, " %d", fc) fmt.Fprintf(t.buf, " %d", fc)
} }
fmt.Fprintf(t.buf, " %d", len(msg.Parameters)) fmt.Fprintf(t.buf, " %d", len(msg.Parameters))
for _, p := range msg.Parameters { for _, p := range msg.Parameters {
fmt.Fprintf(t.buf, " %s", traceSingleQuotedString(p)) fmt.Fprintf(t.buf, " %s", traceSingleQuotedString(p))
} }
fmt.Fprintf(t.buf, " %d", len(msg.ResultFormatCodes)) fmt.Fprintf(t.buf, " %d", len(msg.ResultFormatCodes))
for _, fc := range msg.ResultFormatCodes { for _, fc := range msg.ResultFormatCodes {
fmt.Fprintf(t.buf, " %d", fc) fmt.Fprintf(t.buf, " %d", fc)
} }
t.finishTrace() })
} }
func (t *tracer) traceBindComplete(sender byte, encodedLen int32, msg *BindComplete) { func (t *tracer) traceBindComplete(sender byte, encodedLen int32, msg *BindComplete) {
t.beginTrace(sender, encodedLen, "BindComplete") t.writeTrace(sender, encodedLen, "BindComplete", nil)
t.finishTrace()
} }
func (t *tracer) traceCancelRequest(sender byte, encodedLen int32, msg *CancelRequest) { func (t *tracer) traceCancelRequest(sender byte, encodedLen int32, msg *CancelRequest) {
t.beginTrace(sender, encodedLen, "CancelRequest") t.writeTrace(sender, encodedLen, "CancelRequest", nil)
t.finishTrace()
} }
func (t *tracer) traceClose(sender byte, encodedLen int32, msg *Close) { func (t *tracer) traceClose(sender byte, encodedLen int32, msg *Close) {
t.beginTrace(sender, encodedLen, "Close") t.writeTrace(sender, encodedLen, "Close", nil)
t.finishTrace()
} }
func (t *tracer) traceCloseComplete(sender byte, encodedLen int32, msg *CloseComplete) { func (t *tracer) traceCloseComplete(sender byte, encodedLen int32, msg *CloseComplete) {
t.beginTrace(sender, encodedLen, "CloseComplete") t.writeTrace(sender, encodedLen, "CloseComplete", nil)
t.finishTrace()
} }
func (t *tracer) traceCommandComplete(sender byte, encodedLen int32, msg *CommandComplete) { func (t *tracer) traceCommandComplete(sender byte, encodedLen int32, msg *CommandComplete) {
t.beginTrace(sender, encodedLen, "CommandComplete") t.writeTrace(sender, encodedLen, "CommandComplete", func() {
fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString(msg.CommandTag)) fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString(msg.CommandTag))
t.finishTrace() })
} }
func (t *tracer) traceCopyBothResponse(sender byte, encodedLen int32, msg *CopyBothResponse) { func (t *tracer) traceCopyBothResponse(sender byte, encodedLen int32, msg *CopyBothResponse) {
t.beginTrace(sender, encodedLen, "CopyBothResponse") t.writeTrace(sender, encodedLen, "CopyBothResponse", nil)
t.finishTrace()
} }
func (t *tracer) traceCopyData(sender byte, encodedLen int32, msg *CopyData) { func (t *tracer) traceCopyData(sender byte, encodedLen int32, msg *CopyData) {
t.beginTrace(sender, encodedLen, "CopyData") t.writeTrace(sender, encodedLen, "CopyData", nil)
t.finishTrace()
} }
func (t *tracer) traceCopyDone(sender byte, encodedLen int32, msg *CopyDone) { func (t *tracer) traceCopyDone(sender byte, encodedLen int32, msg *CopyDone) {
t.beginTrace(sender, encodedLen, "CopyDone") t.writeTrace(sender, encodedLen, "CopyDone", nil)
t.finishTrace()
} }
func (t *tracer) traceCopyFail(sender byte, encodedLen int32, msg *CopyFail) { func (t *tracer) traceCopyFail(sender byte, encodedLen int32, msg *CopyFail) {
t.beginTrace(sender, encodedLen, "CopyFail") t.writeTrace(sender, encodedLen, "CopyFail", func() {
fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString([]byte(msg.Message))) fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString([]byte(msg.Message)))
t.finishTrace() })
} }
func (t *tracer) traceCopyInResponse(sender byte, encodedLen int32, msg *CopyInResponse) { func (t *tracer) traceCopyInResponse(sender byte, encodedLen int32, msg *CopyInResponse) {
t.beginTrace(sender, encodedLen, "CopyInResponse") t.writeTrace(sender, encodedLen, "CopyInResponse", nil)
t.finishTrace()
} }
func (t *tracer) traceCopyOutResponse(sender byte, encodedLen int32, msg *CopyOutResponse) { func (t *tracer) traceCopyOutResponse(sender byte, encodedLen int32, msg *CopyOutResponse) {
t.beginTrace(sender, encodedLen, "CopyOutResponse") t.writeTrace(sender, encodedLen, "CopyOutResponse", nil)
t.finishTrace()
} }
func (t *tracer) traceDataRow(sender byte, encodedLen int32, msg *DataRow) { func (t *tracer) traceDataRow(sender byte, encodedLen int32, msg *DataRow) {
t.beginTrace(sender, encodedLen, "DataRow") t.writeTrace(sender, encodedLen, "DataRow", func() {
fmt.Fprintf(t.buf, "\t %d", len(msg.Values)) fmt.Fprintf(t.buf, "\t %d", len(msg.Values))
for _, v := range msg.Values { for _, v := range msg.Values {
if v == nil { if v == nil {
t.buf.WriteString(" -1") t.buf.WriteString(" -1")
} else { } else {
fmt.Fprintf(t.buf, " %d %s", len(v), traceSingleQuotedString(v)) fmt.Fprintf(t.buf, " %d %s", len(v), traceSingleQuotedString(v))
}
} }
} })
t.finishTrace()
} }
func (t *tracer) traceDescribe(sender byte, encodedLen int32, msg *Describe) { func (t *tracer) traceDescribe(sender byte, encodedLen int32, msg *Describe) {
t.beginTrace(sender, encodedLen, "Describe") t.writeTrace(sender, encodedLen, "Describe", func() {
fmt.Fprintf(t.buf, "\t %c %s", msg.ObjectType, traceDoubleQuotedString([]byte(msg.Name))) fmt.Fprintf(t.buf, "\t %c %s", msg.ObjectType, traceDoubleQuotedString([]byte(msg.Name)))
t.finishTrace() })
} }
func (t *tracer) traceEmptyQueryResponse(sender byte, encodedLen int32, msg *EmptyQueryResponse) { func (t *tracer) traceEmptyQueryResponse(sender byte, encodedLen int32, msg *EmptyQueryResponse) {
t.beginTrace(sender, encodedLen, "EmptyQueryResponse") t.writeTrace(sender, encodedLen, "EmptyQueryResponse", nil)
t.finishTrace()
} }
func (t *tracer) traceErrorResponse(sender byte, encodedLen int32, msg *ErrorResponse) { func (t *tracer) traceErrorResponse(sender byte, encodedLen int32, msg *ErrorResponse) {
t.beginTrace(sender, encodedLen, "ErrorResponse") t.writeTrace(sender, encodedLen, "ErrorResponse", nil)
t.finishTrace()
} }
func (t *tracer) TraceQueryute(sender byte, encodedLen int32, msg *Execute) { func (t *tracer) TraceQueryute(sender byte, encodedLen int32, msg *Execute) {
t.beginTrace(sender, encodedLen, "Execute") t.writeTrace(sender, encodedLen, "Execute", func() {
fmt.Fprintf(t.buf, "\t %s %d", traceDoubleQuotedString([]byte(msg.Portal)), msg.MaxRows) fmt.Fprintf(t.buf, "\t %s %d", traceDoubleQuotedString([]byte(msg.Portal)), msg.MaxRows)
t.finishTrace() })
} }
func (t *tracer) traceFlush(sender byte, encodedLen int32, msg *Flush) { func (t *tracer) traceFlush(sender byte, encodedLen int32, msg *Flush) {
t.beginTrace(sender, encodedLen, "Flush") t.writeTrace(sender, encodedLen, "Flush", nil)
t.finishTrace()
} }
func (t *tracer) traceFunctionCall(sender byte, encodedLen int32, msg *FunctionCall) { func (t *tracer) traceFunctionCall(sender byte, encodedLen int32, msg *FunctionCall) {
t.beginTrace(sender, encodedLen, "FunctionCall") t.writeTrace(sender, encodedLen, "FunctionCall", nil)
t.finishTrace()
} }
func (t *tracer) traceFunctionCallResponse(sender byte, encodedLen int32, msg *FunctionCallResponse) { func (t *tracer) traceFunctionCallResponse(sender byte, encodedLen int32, msg *FunctionCallResponse) {
t.beginTrace(sender, encodedLen, "FunctionCallResponse") t.writeTrace(sender, encodedLen, "FunctionCallResponse", nil)
t.finishTrace()
} }
func (t *tracer) traceGSSEncRequest(sender byte, encodedLen int32, msg *GSSEncRequest) { func (t *tracer) traceGSSEncRequest(sender byte, encodedLen int32, msg *GSSEncRequest) {
t.beginTrace(sender, encodedLen, "GSSEncRequest") t.writeTrace(sender, encodedLen, "GSSEncRequest", nil)
t.finishTrace()
} }
func (t *tracer) traceNoData(sender byte, encodedLen int32, msg *NoData) { func (t *tracer) traceNoData(sender byte, encodedLen int32, msg *NoData) {
t.beginTrace(sender, encodedLen, "NoData") t.writeTrace(sender, encodedLen, "NoData", nil)
t.finishTrace()
} }
func (t *tracer) traceNoticeResponse(sender byte, encodedLen int32, msg *NoticeResponse) { func (t *tracer) traceNoticeResponse(sender byte, encodedLen int32, msg *NoticeResponse) {
t.beginTrace(sender, encodedLen, "NoticeResponse") t.writeTrace(sender, encodedLen, "NoticeResponse", nil)
t.finishTrace()
} }
func (t *tracer) traceNotificationResponse(sender byte, encodedLen int32, msg *NotificationResponse) { func (t *tracer) traceNotificationResponse(sender byte, encodedLen int32, msg *NotificationResponse) {
t.beginTrace(sender, encodedLen, "NotificationResponse") t.writeTrace(sender, encodedLen, "NotificationResponse", func() {
fmt.Fprintf(t.buf, "\t %d %s %s", msg.PID, traceDoubleQuotedString([]byte(msg.Channel)), traceDoubleQuotedString([]byte(msg.Payload))) fmt.Fprintf(t.buf, "\t %d %s %s", msg.PID, traceDoubleQuotedString([]byte(msg.Channel)), traceDoubleQuotedString([]byte(msg.Payload)))
t.finishTrace() })
} }
func (t *tracer) traceParameterDescription(sender byte, encodedLen int32, msg *ParameterDescription) { func (t *tracer) traceParameterDescription(sender byte, encodedLen int32, msg *ParameterDescription) {
t.beginTrace(sender, encodedLen, "ParameterDescription") t.writeTrace(sender, encodedLen, "ParameterDescription", nil)
t.finishTrace()
} }
func (t *tracer) traceParameterStatus(sender byte, encodedLen int32, msg *ParameterStatus) { func (t *tracer) traceParameterStatus(sender byte, encodedLen int32, msg *ParameterStatus) {
t.beginTrace(sender, encodedLen, "ParameterStatus") t.writeTrace(sender, encodedLen, "ParameterStatus", func() {
fmt.Fprintf(t.buf, "\t %s %s", traceDoubleQuotedString([]byte(msg.Name)), traceDoubleQuotedString([]byte(msg.Value))) fmt.Fprintf(t.buf, "\t %s %s", traceDoubleQuotedString([]byte(msg.Name)), traceDoubleQuotedString([]byte(msg.Value)))
t.finishTrace() })
} }
func (t *tracer) traceParse(sender byte, encodedLen int32, msg *Parse) { func (t *tracer) traceParse(sender byte, encodedLen int32, msg *Parse) {
t.beginTrace(sender, encodedLen, "Parse") t.writeTrace(sender, encodedLen, "Parse", func() {
fmt.Fprintf(t.buf, "\t %s %s %d", traceDoubleQuotedString([]byte(msg.Name)), traceDoubleQuotedString([]byte(msg.Query)), len(msg.ParameterOIDs)) fmt.Fprintf(t.buf, "\t %s %s %d", traceDoubleQuotedString([]byte(msg.Name)), traceDoubleQuotedString([]byte(msg.Query)), len(msg.ParameterOIDs))
for _, oid := range msg.ParameterOIDs { for _, oid := range msg.ParameterOIDs {
fmt.Fprintf(t.buf, " %d", oid) fmt.Fprintf(t.buf, " %d", oid)
} }
t.finishTrace() })
} }
func (t *tracer) traceParseComplete(sender byte, encodedLen int32, msg *ParseComplete) { func (t *tracer) traceParseComplete(sender byte, encodedLen int32, msg *ParseComplete) {
t.beginTrace(sender, encodedLen, "ParseComplete") t.writeTrace(sender, encodedLen, "ParseComplete", nil)
t.finishTrace()
} }
func (t *tracer) tracePortalSuspended(sender byte, encodedLen int32, msg *PortalSuspended) { func (t *tracer) tracePortalSuspended(sender byte, encodedLen int32, msg *PortalSuspended) {
t.beginTrace(sender, encodedLen, "PortalSuspended") t.writeTrace(sender, encodedLen, "PortalSuspended", nil)
t.finishTrace()
} }
func (t *tracer) traceQuery(sender byte, encodedLen int32, msg *Query) { func (t *tracer) traceQuery(sender byte, encodedLen int32, msg *Query) {
t.beginTrace(sender, encodedLen, "Query") t.writeTrace(sender, encodedLen, "Query", func() {
fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString([]byte(msg.String))) fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString([]byte(msg.String)))
t.finishTrace() })
} }
func (t *tracer) traceReadyForQuery(sender byte, encodedLen int32, msg *ReadyForQuery) { func (t *tracer) traceReadyForQuery(sender byte, encodedLen int32, msg *ReadyForQuery) {
t.beginTrace(sender, encodedLen, "ReadyForQuery") t.writeTrace(sender, encodedLen, "ReadyForQuery", func() {
fmt.Fprintf(t.buf, "\t %c", msg.TxStatus) fmt.Fprintf(t.buf, "\t %c", msg.TxStatus)
t.finishTrace() })
} }
func (t *tracer) traceRowDescription(sender byte, encodedLen int32, msg *RowDescription) { func (t *tracer) traceRowDescription(sender byte, encodedLen int32, msg *RowDescription) {
t.beginTrace(sender, encodedLen, "RowDescription") t.writeTrace(sender, encodedLen, "RowDescription", func() {
fmt.Fprintf(t.buf, "\t %d", len(msg.Fields)) fmt.Fprintf(t.buf, "\t %d", len(msg.Fields))
for _, fd := range msg.Fields { for _, fd := range msg.Fields {
fmt.Fprintf(t.buf, ` %s %d %d %d %d %d %d`, traceDoubleQuotedString(fd.Name), fd.TableOID, fd.TableAttributeNumber, fd.DataTypeOID, fd.DataTypeSize, fd.TypeModifier, fd.Format) fmt.Fprintf(t.buf, ` %s %d %d %d %d %d %d`, traceDoubleQuotedString(fd.Name), fd.TableOID, fd.TableAttributeNumber, fd.DataTypeOID, fd.DataTypeSize, fd.TypeModifier, fd.Format)
} }
t.finishTrace() })
} }
func (t *tracer) traceSSLRequest(sender byte, encodedLen int32, msg *SSLRequest) { func (t *tracer) traceSSLRequest(sender byte, encodedLen int32, msg *SSLRequest) {
t.beginTrace(sender, encodedLen, "SSLRequest") t.writeTrace(sender, encodedLen, "SSLRequest", nil)
t.finishTrace()
} }
func (t *tracer) traceStartupMessage(sender byte, encodedLen int32, msg *StartupMessage) { func (t *tracer) traceStartupMessage(sender byte, encodedLen int32, msg *StartupMessage) {
t.beginTrace(sender, encodedLen, "StartupMessage") t.writeTrace(sender, encodedLen, "StartupMessage", nil)
t.finishTrace()
} }
func (t *tracer) traceSync(sender byte, encodedLen int32, msg *Sync) { func (t *tracer) traceSync(sender byte, encodedLen int32, msg *Sync) {
t.beginTrace(sender, encodedLen, "Sync") t.writeTrace(sender, encodedLen, "Sync", nil)
t.finishTrace()
} }
func (t *tracer) traceTerminate(sender byte, encodedLen int32, msg *Terminate) { func (t *tracer) traceTerminate(sender byte, encodedLen int32, msg *Terminate) {
t.beginTrace(sender, encodedLen, "Terminate") t.writeTrace(sender, encodedLen, "Terminate", nil)
t.finishTrace()
} }
func (t *tracer) beginTrace(sender byte, encodedLen int32, msgType string) { func (t *tracer) writeTrace(sender byte, encodedLen int32, msgType string, writeDetails func()) {
t.mux.Lock()
defer t.mux.Unlock()
defer func() {
if t.buf.Cap() > 1024 {
t.buf = &bytes.Buffer{}
} else {
t.buf.Reset()
}
}()
if !t.SuppressTimestamps { if !t.SuppressTimestamps {
now := time.Now() now := time.Now()
t.buf.WriteString(now.Format("2006-01-02 15:04:05.000000")) t.buf.WriteString(now.Format("2006-01-02 15:04:05.000000"))
@ -402,17 +382,13 @@ func (t *tracer) beginTrace(sender byte, encodedLen int32, msgType string) {
t.buf.WriteString(msgType) t.buf.WriteString(msgType)
t.buf.WriteByte('\t') t.buf.WriteByte('\t')
t.buf.WriteString(strconv.FormatInt(int64(encodedLen), 10)) t.buf.WriteString(strconv.FormatInt(int64(encodedLen), 10))
}
func (t *tracer) finishTrace() { if writeDetails != nil {
writeDetails()
}
t.buf.WriteByte('\n') t.buf.WriteByte('\n')
t.buf.WriteTo(t.w) t.buf.WriteTo(t.w)
if t.buf.Cap() > 1024 {
t.buf = &bytes.Buffer{}
} else {
t.buf.Reset()
}
} }
// traceDoubleQuotedString returns t.buf as a double-quoted string without any escaping. It is roughly equivalent to // traceDoubleQuotedString returns t.buf as a double-quoted string without any escaping. It is roughly equivalent to

@ -92,6 +92,23 @@ func (JSONCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan
switch target.(type) { switch target.(type) {
case *string: case *string:
return scanPlanAnyToString{} return scanPlanAnyToString{}
case **string:
// This is to fix **string scanning. It seems wrong to special case **string, but it's not clear what a better
// solution would be.
//
// https://github.com/jackc/pgx/issues/1470 -- **string
// https://github.com/jackc/pgx/issues/1691 -- ** anything else
if wrapperPlan, nextDst, ok := TryPointerPointerScanPlan(target); ok {
if nextPlan := m.planScan(oid, format, nextDst); nextPlan != nil {
if _, failed := nextPlan.(*scanPlanFail); !failed {
wrapperPlan.SetNext(nextPlan)
return wrapperPlan
}
}
}
case *[]byte: case *[]byte:
return scanPlanJSONToByteSlice{} return scanPlanJSONToByteSlice{}
case BytesScanner: case BytesScanner:
@ -104,19 +121,6 @@ func (JSONCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan
return &scanPlanSQLScanner{formatCode: format} return &scanPlanSQLScanner{formatCode: format}
} }
// This is to fix **string scanning. It seems wrong to special case sql.Scanner and pointer to pointer, but it's not
// clear what a better solution would be.
//
// https://github.com/jackc/pgx/issues/1470
if wrapperPlan, nextDst, ok := TryPointerPointerScanPlan(target); ok {
if nextPlan := m.planScan(oid, format, nextDst); nextPlan != nil {
if _, failed := nextPlan.(*scanPlanFail); !failed {
wrapperPlan.SetNext(nextPlan)
return wrapperPlan
}
}
}
return scanPlanJSONToJSONUnmarshal{} return scanPlanJSONToJSONUnmarshal{}
} }

@ -144,20 +144,20 @@ func (n *Numeric) toBigInt() (*big.Int, error) {
} }
func parseNumericString(str string) (n *big.Int, exp int32, err error) { func parseNumericString(str string) (n *big.Int, exp int32, err error) {
parts := strings.SplitN(str, ".", 2) idx := strings.IndexByte(str, '.')
digits := strings.Join(parts, "")
if len(parts) > 1 { if idx == -1 {
exp = int32(-len(parts[1])) for len(str) > 1 && str[len(str)-1] == '0' && str[len(str)-2] != '-' {
} else { str = str[:len(str)-1]
for len(digits) > 1 && digits[len(digits)-1] == '0' && digits[len(digits)-2] != '-' {
digits = digits[:len(digits)-1]
exp++ exp++
} }
} else {
exp = int32(-(len(str) - idx - 1))
str = str[:idx] + str[idx+1:]
} }
accum := &big.Int{} accum := &big.Int{}
if _, ok := accum.SetString(digits, 10); !ok { if _, ok := accum.SetString(str, 10); !ok {
return nil, 0, fmt.Errorf("%s is not a number", str) return nil, 0, fmt.Errorf("%s is not a number", str)
} }

@ -44,7 +44,7 @@ const (
MacaddrOID = 829 MacaddrOID = 829
InetOID = 869 InetOID = 869
BoolArrayOID = 1000 BoolArrayOID = 1000
QCharArrayOID = 1003 QCharArrayOID = 1002
NameArrayOID = 1003 NameArrayOID = 1003
Int2ArrayOID = 1005 Int2ArrayOID = 1005
Int4ArrayOID = 1007 Int4ArrayOID = 1007

@ -306,7 +306,7 @@ func (rows *baseRows) Values() ([]any, error) {
copy(newBuf, buf) copy(newBuf, buf)
values = append(values, newBuf) values = append(values, newBuf)
default: default:
rows.fatal(errors.New("Unknown format code")) rows.fatal(errors.New("unknown format code"))
} }
} }
@ -496,7 +496,8 @@ func (rs *mapRowScanner) ScanRow(rows Rows) error {
} }
// RowToStructByPos returns a T scanned from row. T must be a struct. T must have the same number a public fields as row // RowToStructByPos returns a T scanned from row. T must be a struct. T must have the same number a public fields as row
// has fields. The row and T fields will by matched by position. // has fields. The row and T fields will by matched by position. If the "db" struct tag is "-" then the field will be
// ignored.
func RowToStructByPos[T any](row CollectableRow) (T, error) { func RowToStructByPos[T any](row CollectableRow) (T, error) {
var value T var value T
err := row.Scan(&positionalStructRowScanner{ptrToStruct: &value}) err := row.Scan(&positionalStructRowScanner{ptrToStruct: &value})
@ -504,7 +505,8 @@ func RowToStructByPos[T any](row CollectableRow) (T, error) {
} }
// RowToAddrOfStructByPos returns the address of a T scanned from row. T must be a struct. T must have the same number a // RowToAddrOfStructByPos returns the address of a T scanned from row. T must be a struct. T must have the same number a
// public fields as row has fields. The row and T fields will by matched by position. // public fields as row has fields. The row and T fields will by matched by position. If the "db" struct tag is "-" then
// the field will be ignored.
func RowToAddrOfStructByPos[T any](row CollectableRow) (*T, error) { func RowToAddrOfStructByPos[T any](row CollectableRow) (*T, error) {
var value T var value T
err := row.Scan(&positionalStructRowScanner{ptrToStruct: &value}) err := row.Scan(&positionalStructRowScanner{ptrToStruct: &value})
@ -545,6 +547,11 @@ func (rs *positionalStructRowScanner) appendScanTargets(dstElemValue reflect.Val
if sf.Anonymous && sf.Type.Kind() == reflect.Struct { if sf.Anonymous && sf.Type.Kind() == reflect.Struct {
scanTargets = rs.appendScanTargets(dstElemValue.Field(i), scanTargets) scanTargets = rs.appendScanTargets(dstElemValue.Field(i), scanTargets)
} else if sf.PkgPath == "" { } else if sf.PkgPath == "" {
dbTag, _ := sf.Tag.Lookup(structTagKey)
if dbTag == "-" {
// Field is ignored, skip it.
continue
}
scanTargets = append(scanTargets, dstElemValue.Field(i).Addr().Interface()) scanTargets = append(scanTargets, dstElemValue.Field(i).Addr().Interface())
} }
} }

@ -152,7 +152,6 @@ type Tx interface {
// called on the dbTx. // called on the dbTx.
type dbTx struct { type dbTx struct {
conn *Conn conn *Conn
err error
savepointNum int64 savepointNum int64
closed bool closed bool
} }

@ -1,3 +1,4 @@
*.rdb *.rdb
testdata/* testdata/*
.idea/ .idea/
.DS_Store

@ -23,7 +23,7 @@ bench: testdeps
testdata/redis: testdata/redis:
mkdir -p $@ mkdir -p $@
wget -qO- https://download.redis.io/releases/redis-7.2-rc1.tar.gz | tar xvz --strip-components=1 -C $@ wget -qO- https://download.redis.io/releases/redis-7.2-rc3.tar.gz | tar xvz --strip-components=1 -C $@
testdata/redis/src/redis-server: testdata/redis testdata/redis/src/redis-server: testdata/redis
cd $< && make all cd $< && make all

@ -46,6 +46,7 @@ key value NoSQL database that uses RocksDB as storage engine and is compatible w
- [Redis Cluster](https://redis.uptrace.dev/guide/go-redis-cluster.html). - [Redis Cluster](https://redis.uptrace.dev/guide/go-redis-cluster.html).
- [Redis Ring](https://redis.uptrace.dev/guide/ring.html). - [Redis Ring](https://redis.uptrace.dev/guide/ring.html).
- [Redis Performance Monitoring](https://redis.uptrace.dev/guide/redis-performance-monitoring.html). - [Redis Performance Monitoring](https://redis.uptrace.dev/guide/redis-performance-monitoring.html).
- [Redis Probabilistic [RedisStack]](https://redis.io/docs/data-types/probabilistic/)
## Installation ## Installation
@ -105,6 +106,40 @@ func ExampleClient() {
} }
``` ```
The above can be modified to specify the version of the RESP protocol by adding the `protocol` option to the `Options` struct:
```go
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
Protocol: 3, // specify 2 for RESP 2 or 3 for RESP 3
})
```
### Connecting via a redis url
go-redis also supports connecting via the [redis uri specification](https://github.com/redis/redis-specifications/tree/master/uri/redis.txt). The example below demonstrates how the connection can easily be configured using a string, adhering to this specification.
```go
import (
"context"
"github.com/redis/go-redis/v9"
"fmt"
)
var ctx = context.Background()
func ExampleClient() {
url := "redis://localhost:6379?password=hello&protocol=3"
opts, err := redis.ParseURL(url)
if err != nil {
panic(err)
}
rdb := redis.NewClient(opts)
```
## Look and feel ## Look and feel
Some corner cases: Some corner cases:

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save