- update vendor

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

@ -4,18 +4,18 @@ go 1.20
require (
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/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/bytedance/sonic v1.10.0-rc3
github.com/bytedance/sonic v1.10.0
github.com/gin-gonic/gin v1.9.1
github.com/go-playground/locales v0.14.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/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/lib/pq v1.10.9
github.com/mitchellh/mapstructure v1.5.0
@ -23,7 +23,7 @@ require (
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/oschwald/geoip2-golang v1.9.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/saracen/go7z v0.0.0-20191010121135-9c09b6bd7fda
github.com/shirou/gopsutil v3.21.11+incompatible
@ -32,14 +32,14 @@ require (
go.mongodb.org/mongo-driver v1.12.1
go.uber.org/zap v1.25.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
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gorm.io/datatypes v1.2.0
gorm.io/driver/mysql v1.5.1
gorm.io/driver/postgres v1.5.2
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/xorm v1.3.2
)
@ -50,7 +50,6 @@ require (
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.0 // 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/fatih/color v1.15.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/go-logr/logr v1.2.4 // 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/google/go-querystring v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // 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/now v1.1.5 // 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/solidblock v0.0.0-20190426153529-45df20abab6f // 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/twitchyliquid64/golang-asm v0.15.1 // 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/sys v0.11.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
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // 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=
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 v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
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/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/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/aliyun/aliyun-oss-go-sdk v2.2.8+incompatible h1:6JF1bjhT0WN2srEmijfOFtVWwV91KZ6dJY1/JbdtGrI=
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 h1:Sg/2xHwDrioHpxTN6WMiwbXTpUEinBpHsN7mG21Rc2k=
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/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
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-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/baidubce/bce-sdk-go v0.9.154 h1:MKGCBV7EpDoQDwpn8X6L/SiEcii7twwWTBd241e4f5I=
github.com/baidubce/bce-sdk-go v0.9.154/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
github.com/baidubce/bce-sdk-go v0.9.156 h1:f++WfptxGmSp5acsjl4kUxHpWDDccoFqkIrQKxvp/Sw=
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/go.mod h1:wH7a5Np/Q4QoECFIU8zTQlZwZkrilY0itPfecMw41Dw=
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/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/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/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-rc3 h1:uNSnscRapXTwUgTyOF0GVljYD08p9X/Lbr9MweSV3V0=
github.com/bytedance/sonic v1.10.0-rc3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk=
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/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
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/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/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
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/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
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/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/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.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
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/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.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
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.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.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/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
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-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.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.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
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/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.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-playground/validator/v10 v10.15.1 h1:BSe8uhN+xQ4r5guV/ywQI4gO59C2raYcGffYWZEjZzM=
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.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
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/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/gogf/gf/v2 v2.5.1 h1:mkmqWrKTsuLRnv4OL1CS9voPMqfSx/DSY7JJnd/HnfA=
github.com/gogf/gf/v2 v2.5.1/go.mod h1:9XLWIkCQmaWIugHag4AEOtex0LlVeUHsUxqjAC8f6ew=
github.com/gogf/gf/v2 v2.5.2 h1:fACJE7DJH6iTGHGhgiNY1uuZIZtr2IqQkJ52E+wBnt8=
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/protobuf v1.1.1/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.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.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
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.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/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/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/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-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
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.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/v5 v5.4.2 h1:u1gmGDwbdRUZiwisBm/Ky2M14uQyUP65bG8+20nnyrg=
github.com/jackc/pgx/v5 v5.4.2/go.mod h1:q6iHT8uDNXWiFNOlRqJzBTaSH3+2xCXkokxHZC5qWFY=
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
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-20190608224051-11cab39313c9/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/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/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.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.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/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
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.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/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.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
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.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
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.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/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/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
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/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/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/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o=
github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY=
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/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/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
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/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/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
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=
@ -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/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
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/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
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.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
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/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
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/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/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/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
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/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-20230801115018-d63ba01acd4b h1:r+vk0EmXNmekl0S0BascoeeoHk/L7wmaW2QF90K+kYI=
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
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-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
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.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.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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
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-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-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-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
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-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-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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
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-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-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-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-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-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-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.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.6.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.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.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.4.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-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.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.11.1 h1:ojD5zOW8+7dOGzdnNgersm8aPfcDjhMp12UfG93NIMc=
golang.org/x/tools v0.11.1/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E=
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-20190513163551-3ee3066db522/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.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.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho=
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/go.mod h1:/ARdpUHAtyEMCh5NNi3tI7FsGh+Cj/MIUlvNxCNCFWg=
gorm.io/plugin/dbresolver v1.4.2 h1:IeLSH20ayxbo4rN6HMIQ0ccdsh/fkLK23pp6ivZrqBI=
gorm.io/plugin/dbresolver v1.4.2/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0=
gorm.io/plugin/dbresolver v1.4.7 h1:ZwtwmJQxTx9us7o6zEHFvH1q4OeEo1pooU7efmnunJA=
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-20190102054323-c2f93a96b099/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
func Version() string {
return "1.0.158"
return "1.0.159"
}

@ -2,6 +2,7 @@ package oss
import (
"bytes"
"context"
"crypto/md5"
"encoding/base64"
"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 "\".
// 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
// 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 {
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.
//
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) PutObjectFromFile(objectKey, filePath string, options ...Option) error {
fd, err := os.Open(filePath)
if err != nil {
@ -87,7 +87,6 @@ func (bucket Bucket) PutObjectFromFile(objectKey, filePath string, options ...Op
//
// Response the response from OSS.
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DoPutObject(request *PutObjectRequest, options []Option) (*Response, error) {
isOptSet, _, _ := IsOptionSet(options, HTTPHeaderContentType)
if !isOptSet {
@ -118,12 +117,12 @@ func (bucket Bucket) DoPutObject(request *PutObjectRequest, options []Option) (*
//
// objectKey the object key.
// 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.
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObject(objectKey string, options ...Option) (io.ReadCloser, error) {
result, err := bucket.DoGetObject(&GetObjectRequest{objectKey}, options)
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.
//
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Option) error {
tempFilePath := filePath + TempFileSuffix
@ -190,7 +188,6 @@ func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Opti
//
// GetObjectResult the result instance of getting the object.
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DoGetObject(request *GetObjectRequest, options []Option) (*GetObjectResult, error) {
params, _ := GetRawParams(options)
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.
// destObjectKey the target object to copy.
// 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) {
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.
//
// 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) {
return bucket.copy(srcObjectKey, destBucketName, destObjectKey, options...)
}
//
// CopyObjectFrom copies the object to another bucket.
//
// 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.
//
// 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) {
destBucketName := bucket.BucketName
var out CopyObjectResult
@ -309,7 +303,11 @@ func (bucket Bucket) copy(srcObjectKey, destBucketName, destObjectKey string, op
return out, err
}
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
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.
// appendPosition the start position to append.
// 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.
// 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) {
request := &AppendObjectRequest{
ObjectKey: objectKey,
@ -367,7 +365,6 @@ func (bucket Bucket) AppendObject(objectKey string, reader io.Reader, appendPosi
//
// AppendObjectResult the result object for appending object.
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Option) (*AppendObjectResult, error) {
params := map[string]interface{}{}
params["append"] = nil
@ -386,7 +383,11 @@ func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Opti
listener := GetProgressListener(options)
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)
// get response header
@ -424,7 +425,6 @@ func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Opti
// objectKey the object key to delete.
//
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DeleteObject(objectKey string, options ...Option) error {
params, _ := GetRawParams(options)
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.
// 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.
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DeleteObjects(objectKeys []string, options ...Option) (DeleteObjectsResult, error) {
out := DeleteObjectsResult{}
dxml := deleteXML{}
@ -475,11 +475,11 @@ func (bucket Bucket) DeleteObjects(objectKeys []string, options ...Option) (Dele
//
// objectVersions the object keys and versions to delete.
// 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.
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DeleteObjectVersions(objectVersions []DeleteObject, options ...Option) (DeleteObjectVersionsResult, error) {
out := DeleteObjectVersionsResult{}
dxml := deleteXML{}
@ -506,7 +506,6 @@ func (bucket Bucket) DeleteObjectVersions(objectVersions []DeleteObject, options
//
// string the result response body.
// error it's nil if no error, otherwise it's an error.
//
func (bucket Bucket) DeleteMultipleObjectsXml(xmlData string, options ...Option) (string, error) {
buffer := new(bytes.Buffer)
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.
//
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) IsObjectExist(objectKey string, options ...Option) (bool, error) {
_, err := bucket.GetObjectMeta(objectKey, options...)
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.
//
// 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,
// 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.
// 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 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) {
var out ListObjectsResult
@ -653,10 +651,10 @@ func (bucket Bucket) ListObjectVersions(options ...Option) (ListObjectVersionsRe
//
// objectKey object
// 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 {
options = append(options, MetadataDirective(MetaReplace))
_, err := bucket.CopyObject(objectKey, objectKey, options...)
@ -667,11 +665,11 @@ func (bucket Bucket) SetObjectMeta(objectKey string, options ...Option) error {
//
// 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,
// 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.
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObjectDetailedMeta(objectKey string, options ...Option) (http.Header, error) {
params, _ := GetRawParams(options)
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.
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObjectMeta(objectKey string, options ...Option) (http.Header, error) {
params, _ := GetRawParams(options)
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.
//
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) SetObjectACL(objectKey string, objectACL ACLType, options ...Option) error {
options = append(options, ObjectACL(objectACL))
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.
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObjectACL(objectKey string, options ...Option) (GetObjectACLResult, error) {
var out GetObjectACLResult
params, _ := GetRawParams(options)
@ -767,7 +762,6 @@ func (bucket Bucket) GetObjectACL(objectKey string, options ...Option) (GetObjec
// targetObjectKey the target object key to point to.
//
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) PutSymlink(symObjectKey string, targetObjectKey string, options ...Option) error {
options = append(options, symlinkTarget(url.QueryEscape(targetObjectKey)))
params, _ := GetRawParams(options)
@ -786,8 +780,8 @@ func (bucket Bucket) PutSymlink(symObjectKey string, targetObjectKey string, opt
// objectKey the symlink object's key.
//
// 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) {
params, _ := GetRawParams(options)
params["symlink"] = nil
@ -817,7 +811,6 @@ func (bucket Bucket) GetSymlink(objectKey string, options ...Option) (http.Heade
// objectKey object key to restore.
//
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) RestoreObject(objectKey string, options ...Option) error {
params, _ := GetRawParams(options)
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.
// 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) {
err := CheckObjectName(objectKey)
if err != nil {
@ -920,11 +912,11 @@ func (bucket Bucket) SignURL(objectKey string, method HTTPMethod, expiredInSec i
// signedURL signed URL.
// 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,
// 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 {
resp, err := bucket.DoPutObjectWithURL(signedURL, reader, options)
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.
//
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) PutObjectFromFileWithURL(signedURL, filePath string, options ...Option) error {
fd, err := os.Open(filePath)
if err != nil {
@ -968,7 +959,6 @@ func (bucket Bucket) PutObjectFromFileWithURL(signedURL, filePath string, option
//
// Response the response object which contains the HTTP response.
// 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) {
listener := GetProgressListener(options)
@ -994,12 +984,12 @@ func (bucket Bucket) DoPutObjectWithURL(signedURL string, reader io.Reader, opti
//
// signedURL the signed URL.
// 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.
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObjectWithURL(signedURL string, options ...Option) (io.ReadCloser, error) {
result, err := bucket.DoGetObjectWithURL(signedURL, options)
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.
//
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) GetObjectToFileWithURL(signedURL, filePath string, options ...Option) error {
tempFilePath := filePath + TempFileSuffix
@ -1066,7 +1055,6 @@ func (bucket Bucket) GetObjectToFileWithURL(signedURL, filePath string, options
//
// GetObjectResult the result object when the error is nil.
// error it's nil if no error, otherwise it's an error object.
//
func (bucket Bucket) DoGetObjectWithURL(signedURL string, options []Option) (*GetObjectResult, error) {
params, _ := GetRawParams(options)
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
}
//
// ProcessObject apply process on the specified image file.
//
// The supported process includes resize, rotate, crop, watermark, format,
// udf, customized style, etc.
//
//
// objectKey object key to process.
// 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.
//
func (bucket Bucket) ProcessObject(objectKey string, process string, options ...Option) (ProcessObjectResult, error) {
var out ProcessObjectResult
params, _ := GetRawParams(options)
@ -1160,7 +1145,6 @@ func (bucket Bucket) AsyncProcessObject(objectKey string, asyncProcess string, o
// tagging tagging to be added
//
// error nil if success, otherwise error
//
func (bucket Bucket) PutObjectTagging(objectKey string, tagging Tagging, options ...Option) error {
bs, err := xml.Marshal(tagging)
if err != nil {
@ -1204,13 +1188,11 @@ func (bucket Bucket) GetObjectTagging(objectKey string, options ...Option) (GetO
return out, err
}
//
// DeleteObjectTagging delete object taggging
//
// objectKey object key to delete tagging
//
// error nil if success, otherwise error
//
func (bucket Bucket) DeleteObjectTagging(objectKey string, options ...Option) error {
params, _ := GetRawParams(options)
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 {
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)
// 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,
data io.Reader, listener ProgressListener) (*Response, error) {
headers := make(map[string]string)
err := handleOptions(headers, options)
if err != nil {
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
respHeader, _ := FindOption(options, responseHeader, nil)

@ -49,10 +49,6 @@ func New(endpoint, accessKeyID, accessKeySecret string, options ...ClientOption)
// URL parse
url := &urlMaker{}
err := url.Init(config.Endpoint, config.IsCname, config.IsUseProxy)
if err != nil {
return nil, err
}
// HTTP connect
conn := &Conn{config: config, url: url}
@ -68,6 +64,11 @@ func New(endpoint, accessKeyID, accessKeySecret string, options ...ClientOption)
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 {
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 {
return func(client *Client) {
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) {
client.Config.IsUseProxy = true
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.ProxyUser = proxyUser
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.
SecurityToken string // STS Token
IsCname bool // If cname is in the endpoint.
IsPathStyle bool // If Path Style is in the endpoint.
HTTPTimeout HTTPTimeout // HTTP timeout
HTTPMaxConns HTTPMaxConns // Http max connections
IsUseProxy bool // Flag of using proxy.
@ -256,6 +257,7 @@ func getDefaultOssConfig() *Config {
config.Timeout = 60 // Seconds
config.SecurityToken = ""
config.IsCname = false
config.IsPathStyle = false
config.HTTPTimeout.ConnectTimeout = time.Second * 30 // 30s
config.HTTPTimeout.ReadWriteTimeout = time.Second * 60 // 60s

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

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

@ -1,6 +1,7 @@
package oss
import (
"context"
"fmt"
"net/http"
"net/url"
@ -12,9 +13,11 @@ import (
type optionType string
const (
optionParam optionType = "HTTPParameter" // URL parameter
optionHTTP optionType = "HTTPHeader" // HTTP header
optionArg optionType = "FuncArgument" // Function argument
optionParam optionType = "HTTPParameter" // URL parameter
optionHTTP optionType = "HTTPHeader" // HTTP header
optionContext optionType = "HTTPContext" // context
optionArg optionType = "FuncArgument" // Function argument
)
const (
@ -27,6 +30,7 @@ const (
responseHeader = "x-response-header"
redundancyType = "redundancy-type"
objectHashFunc = "object-hash-func"
contextArg = "x-context-arg"
)
type (
@ -448,6 +452,11 @@ func ObjectHashFunc(value ObjecthashFuncType) Option {
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
type cpConfig struct {
IsEnable bool

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

@ -26,7 +26,7 @@ import (
// Constants and default values for the package bce
const (
SDK_VERSION = "0.9.154"
SDK_VERSION = "0.9.156"
URI_PREFIX = "/" // now support uri without prefix "v1" so just set root path
DEFAULT_DOMAIN = "baidubce.com"
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.SetUri(getBucketUri(bucket))
req.SetMethod(http.PUT)
req.SetParam("tagging", "")
reqByte, _ := json.Marshal(putBucketTagReq)
reqByte, _ := json.Marshal(putBucketTagArgs)
body, err := bce.NewBodyFromString(string(reqByte))
if err != nil {
return err
@ -1172,7 +1172,7 @@ func PutBucketTag(cli bce.Client, bucket string, putBucketTagReq PutBucketTagReq
return nil
}
func GetBucketTag(cli bce.Client, bucket string) (*PutBucketTagReq, error) {
func GetBucketTag(cli bce.Client, bucket string) (*PutBucketTagArgs, error) {
req := &bce.BceRequest{}
req.SetUri(getBucketUri(bucket))
req.SetMethod(http.GET)
@ -1184,7 +1184,7 @@ func GetBucketTag(cli bce.Client, bucket string) (*PutBucketTagReq, error) {
if resp.IsFail() {
return nil, resp.ServiceError()
}
result := &PutBucketTagReq{}
result := &PutBucketTagArgs{}
if err := resp.ParseJsonBody(result); err != nil {
return nil, err
}

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

@ -2252,3 +2252,15 @@ func (c *Client) GetBucketMirror(bucket string) (*api.PutBucketMirrorArgs, error
func (c *Client) DeleteBucketMirror(bucket string) error {
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).
## Requirement
- Go 1.16~1.20
- Go 1.16~1.21
- Linux / MacOS / Windows(need go1.17 above)
- Amd64 ARCH

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

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

@ -82,26 +82,54 @@ type ObjectIterator struct {
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,
// copies each child to v, and returns .HasNext().
func (self *ListIterator) Next(v *Node) bool {
if !self.HasNext() {
n := self.next()
if n == nil {
return false
}
*v = *n
return true
}
func (self *ObjectIterator) next() *Pair {
next_start:
if !self.HasNext() {
return nil
} else {
*v, self.i = *self.p.nodeAt(self.i), self.i + 1
return true
n := self.p.pairAt(self.i)
self.i++
if !n.Value.Exists() {
goto next_start
}
return n
}
}
// Next scans through children of underlying V_OBJECT,
// copies each child to v, and returns .HasNext().
func (self *ObjectIterator) Next(p *Pair) bool {
if !self.HasNext() {
n := self.next()
if n == nil {
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.
@ -129,30 +157,39 @@ type Scanner func(path Sequence, node *Node) bool
//
// Especailly, if the node is not V_ARRAY or V_OBJECT,
// 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 {
switch self.itype() {
case types.V_ARRAY:
ns, err := self.unsafeArray()
iter, err := self.Values()
if err != nil {
return err
}
for i:=0; i<ns.Len(); i++ {
if !sc(Sequence{i, nil}, ns.At(i)) {
return err
v := iter.next()
for v != nil {
if !sc(Sequence{iter.i-1, nil}, v) {
return nil
}
v = iter.next()
}
case types.V_OBJECT:
ns, err := self.unsafeMap()
iter, err := self.Properties()
if err != nil {
return err
}
for i:=0; i<ns.Len(); i++ {
if !sc(Sequence{i, &ns.At(i).Key}, &ns.At(i).Value) {
return err
v := iter.next()
for v != nil {
if !sc(Sequence{iter.i-1, &v.Key}, &v.Value) {
return nil
}
v = iter.next()
}
default:
if self.Check() != nil {
return 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
// 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_NULL = 2 (json value `null`)
// V_NULL = 2 (json value `null`, key exists)
// V_TRUE = 3 (json value `true`)
// V_FALSE = 4 (json value `false`)
// 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
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
@ -114,7 +114,7 @@ func (self *Node) Valid() bool {
}
// 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
func (self *Node) Check() error {
if self == nil {
@ -572,7 +572,7 @@ func (self *Node) SetAny(key string, val interface{}) (bool, error) {
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
func (self *Node) Unset(key string) (bool, error) {
self.must(types.V_OBJECT, "an object")
@ -619,6 +619,9 @@ func (self *Node) UnsetByIndex(index int) (bool, error) {
if it == types.V_ARRAY {
p = self.Index(index)
}else if it == types.V_OBJECT {
if err := self.checkRaw(); err != nil {
return false, err
}
pr := self.skipIndexPair(index)
if pr == nil {
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
//
// Deprecated: this API now returns copied nodes instead of directly reference,
func (self *Node) UnsafeMap() ([]Pair, error) {
if err := self.should(types.V_OBJECT, "an object"); err != nil {
return nil, err
}
if err := self.skipAllKey(); err != nil {
return nil, err
}
return self.toGenericObjectUsePair()
}
// func (self *Node) UnsafeMap() ([]Pair, error) {
// if err := self.should(types.V_OBJECT, "an object"); err != nil {
// return nil, err
// }
// if err := self.skipAllKey(); err != nil {
// return nil, err
// }
// return self.toGenericObjectUsePair()
// }
func (self *Node) unsafeMap() (*linkedPairs, error) {
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,
// which has no difference with ArrayUseNode
func (self *Node) UnsafeArray() ([]Node, error) {
if err := self.should(types.V_ARRAY, "an array"); err != nil {
return nil, err
}
if err := self.skipAllIndex(); err != nil {
return nil, err
}
return self.toGenericArrayUseNode()
}
// func (self *Node) UnsafeArray() ([]Node, error) {
// if err := self.should(types.V_ARRAY, "an array"); err != nil {
// return nil, err
// }
// if err := self.skipAllIndex(); err != nil {
// return nil, err
// }
// return self.toGenericArrayUseNode()
// }
func (self *Node) unsafeArray() (*linkedNodes, error) {
if err := self.should(types.V_ARRAY, "an array"); err != nil {

@ -34,7 +34,10 @@ const (
)
var (
// ErrNotExist means both key and value doesn't exist
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")
)

@ -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.

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

@ -1,5 +1,4 @@
//go:build !amd64 || !go1.16 || go1.21
// +build !amd64 !go1.16 go1.21
// +build !amd64 !go1.16 go1.22
/*
* Copyright 2023 ByteDance Inc.
@ -170,35 +169,13 @@ func Pretouch(vt reflect.Type, opts ...option.CompileOption) error {
return nil
}
type StreamDecoder struct {
r io.Reader
buf []byte
scanp int
scanned int64
err error
Decoder
}
type StreamDecoder = json.Decoder
// NewStreamDecoder adapts to encoding/json.NewDecoder API.
//
// NewStreamDecoder returns a new decoder that reads from r.
func NewStreamDecoder(r io.Reader) *StreamDecoder {
return &StreamDecoder{r : 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)
return json.NewDecoder(r)
}
// 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.

@ -1,4 +1,4 @@
// +build !amd64 !go1.16 go1.21
// +build !amd64 !go1.16 go1.22
/*
* Copyright 2023 ByteDance Inc.
@ -216,23 +216,12 @@ func Valid(data []byte) (ok bool, start int) {
}
// StreamEncoder uses io.Writer as
type StreamEncoder struct {
w io.Writer
Encoder
}
type StreamEncoder = json.Encoder
// NewStreamEncoder adapts to encoding/json.NewDecoder API.
//
// NewStreamEncoder returns a new encoder that write to w.
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
// +build go1.17,!go1.21
//go:build go1.17 && !go1.22
// +build go1.17,!go1.22
/*
* Copyright 2021 ByteDance Inc.
@ -24,7 +24,6 @@ import (
`fmt`
`math`
`reflect`
`strconv`
`unsafe`
`github.com/bytedance/sonic/internal/caching`
@ -33,7 +32,6 @@ import (
`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
)
/** 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.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.
@ -23,7 +23,6 @@ import (
`fmt`
`math`
`reflect`
`strconv`
`unsafe`
`github.com/bytedance/sonic/internal/caching`
@ -32,7 +31,6 @@ import (
`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
)
/** 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.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.21
// +build go1.17,!go1.22
/*
* Copyright 2021 ByteDance Inc.
@ -23,13 +22,11 @@ import (
`encoding/json`
`fmt`
`reflect`
`strconv`
`github.com/bytedance/sonic/internal/jit`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
)
/** Crucial Registers:
@ -286,7 +283,7 @@ func (self *_ValueDecoder) compile() {
self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX
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.callc(_F_value) // CALL value
self.callc(_F_value) // CALL value
self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC
/* 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 **/
var (

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

@ -1,4 +1,4 @@
// +build go1.15,!go1.17
// +build go1.16,!go1.17
/*
* Copyright 2021 ByteDance Inc.
@ -22,13 +22,11 @@ import (
`encoding/json`
`fmt`
`reflect`
`strconv`
`github.com/bytedance/sonic/internal/jit`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
)
/** Crucial Registers:
@ -645,7 +643,8 @@ func (self *_ValueDecoder) compile() {
self.Emit("MOVQ", _R8, _VAR_cs_p)
self.Emit("MOVQ", _AX, _VAR_cs_n)
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, 16))
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 **/
var (

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

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

@ -82,23 +82,23 @@ func makemap_small() unsafe.Pointer
//go:linkname mapassign runtime.mapassign
//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
//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
//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
//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
//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: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
// +build go1.17,!go1.21
//go:build go1.17 && !go1.22
// +build go1.17,!go1.22
/*
* 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.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.WriteRecNotAX(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(0, _SP_p, jit.Sib(_ST, _CX, 1, 24)) // MOVQ SP.p, 24(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)
}
@ -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.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.
@ -421,8 +421,8 @@ func (self *_Assembler) save_state() {
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_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.WriteRecNotAX(1, _SP_q, jit.Sib(_ST, _CX, 1, 32)) // MOVQ SP.q, 32(ST)(CX)
self.WritePtr(0, _SP_p, jit.Sib(_ST, _CX, 1, 24)) // MOVQ SP.p, 24(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)
}
@ -579,7 +579,8 @@ var (
func (self *_Assembler) 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", _RL, jit.Ptr(_SP, 16)) // MOVQ RL, 16(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.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.

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

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

@ -1,4 +1,4 @@
// +build go1.20
// +build go1.20,!go1.21
/*
* 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()

@ -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
// +build go1.18,!go1.21
// go:build go1.18 && !go1.22
// +build go1.18,!go1.22
/*
* Copyright 2021 ByteDance Inc.

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

@ -1,4 +1,4 @@
// +build amd64,go1.16,!go1.21
// +build amd64,go1.16,!go1.22
/*
* 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}"
os: Windows Server 2012 R2
os: Visual Studio 2019
branches:
only:
- master
- v1.2
- v1.1
- v1.0
build: off
skip_tags: true
@ -21,20 +16,40 @@ clone_folder: c:\gopath\src\github.com\go-ole\go-ole
environment:
GOPATH: c:\gopath
matrix:
- GOARCH: amd64
GOVERSION: 1.5
GOROOT: c:\go
DOWNLOADPLATFORM: "x64"
GOROOT: c:\go
DOWNLOADPLATFORM: "x64"
install:
- choco install mingw
- SET PATH=c:\tools\mingw64\bin;%PATH%
before_test:
# - 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"
- 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
# - 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 env
- 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
- go get -v -t ./...
- go build
- go test -v -cover ./...
# disable automatic tests
test: off
test: on
# disable deployment
deploy: off

@ -11,6 +11,7 @@ import (
var (
procCoInitialize = modole32.NewProc("CoInitialize")
procCoInitializeEx = modole32.NewProc("CoInitializeEx")
procCoInitializeSecurity = modole32.NewProc("CoInitializeSecurity")
procCoUninitialize = modole32.NewProc("CoUninitialize")
procCoCreateInstance = modole32.NewProc("CoCreateInstance")
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
@ -37,6 +38,9 @@ var (
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.
//
// MSDN documentation suggests that this function should not be called. Call
@ -68,6 +72,35 @@ func coInitializeEx(coinit uint32) (err error) {
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.
//
// MSDN documentation suggests that this function should not be called. Call
@ -96,6 +129,15 @@ func CoUninitialize() {
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.
func CoTaskMemFree(memptr uintptr) {
procCoTaskMemFree.Call(memptr)

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

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

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

@ -230,6 +230,7 @@ var (
"luhn_checksum": hasLuhnChecksum,
"mongodb": isMongoDB,
"cron": isCron,
"spicedb": isSpiceDB,
}
)
@ -1294,8 +1295,13 @@ func isEq(fl FieldLevel) bool {
return field.Uint() == p
case reflect.Float32, reflect.Float64:
p := asFloat(param)
case reflect.Float32:
p := asFloat32(param)
return field.Float() == p
case reflect.Float64:
p := asFloat64(param)
return field.Float() == p
@ -1561,6 +1567,10 @@ func isFilePath(fl FieldLevel) bool {
field := fl.Field()
// Not valid if it is a directory.
if isDir(fl) {
return false
}
// If it exists, it obviously is valid.
// This is done first to avoid code duplication and unnecessary additional logic.
if exists = isFile(fl); exists {
@ -1710,7 +1720,7 @@ func hasValue(fl FieldLevel) bool {
if fl.(*validate).fldIsPointer && field.Interface() != nil {
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 {
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:
return field.Uint() == asUint(value)
case reflect.Float32, reflect.Float64:
return field.Float() == asFloat(value)
case reflect.Float32:
return field.Float() == asFloat32(value)
case reflect.Float64:
return field.Float() == asFloat64(value)
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) == asInt(value)
@ -2055,8 +2068,13 @@ func isGte(fl FieldLevel) bool {
return field.Uint() >= p
case reflect.Float32, reflect.Float64:
p := asFloat(param)
case reflect.Float32:
p := asFloat32(param)
return field.Float() >= p
case reflect.Float64:
p := asFloat64(param)
return field.Float() >= p
@ -2101,10 +2119,16 @@ func isGt(fl FieldLevel) bool {
return field.Uint() > p
case reflect.Float32, reflect.Float64:
p := asFloat(param)
case reflect.Float32:
p := asFloat32(param)
return field.Float() > p
case reflect.Float64:
p := asFloat64(param)
return field.Float() > p
case reflect.Struct:
if field.Type().ConvertibleTo(timeType) {
@ -2143,8 +2167,13 @@ func hasLengthOf(fl FieldLevel) bool {
return field.Uint() == p
case reflect.Float32, reflect.Float64:
p := asFloat(param)
case reflect.Float32:
p := asFloat32(param)
return field.Float() == p
case reflect.Float64:
p := asFloat64(param)
return field.Float() == p
}
@ -2276,8 +2305,13 @@ func isLte(fl FieldLevel) bool {
return field.Uint() <= p
case reflect.Float32, reflect.Float64:
p := asFloat(param)
case reflect.Float32:
p := asFloat32(param)
return field.Float() <= p
case reflect.Float64:
p := asFloat64(param)
return field.Float() <= p
@ -2322,8 +2356,13 @@ func isLt(fl FieldLevel) bool {
return field.Uint() < p
case reflect.Float32, reflect.Float64:
p := asFloat(param)
case reflect.Float32:
p := asFloat32(param)
return field.Float() < p
case reflect.Float64:
p := asFloat64(param)
return field.Float() < p
@ -2808,6 +2847,23 @@ func isMongoDB(fl FieldLevel) bool {
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
func isCreditCard(fl FieldLevel) bool {
val := fl.Field().String()

@ -20,6 +20,7 @@ const (
typeOr
typeKeys
typeEndKeys
typeNestedStructLevel
)
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
if len(tag) > 0 {
ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, "", false)
ctag, _ = v.parseFieldTagsRecursive(tag, fld, "", false)
} else {
// even if field doesn't have validations need cTag for traversing to potential inner/nested
// elements of the field.
@ -171,7 +172,7 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
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
noAlias := len(alias) == 0
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
if tagsVal, found := v.aliases[t]; found {
if i == 0 {
firstCtag, current = v.parseFieldTagsRecursive(tagsVal, fieldName, t, true)
firstCtag, current = v.parseFieldTagsRecursive(tagsVal, field, t, true)
} else {
next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true)
next, curr := v.parseFieldTagsRecursive(tagsVal, field, t, true)
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
case endKeysTag:
@ -284,14 +285,18 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s
current.tag = vals[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 {
current.fn = wrapper.fn
current.runValidationWhenNil = wrapper.runValidatinOnNil
} 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 {
@ -319,7 +324,7 @@ func (v *Validate) fetchCacheTag(tag string) *cTag {
// isn't parsed again.
ctag, found = v.tagCache.Get(tag)
if !found {
ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false)
ctag, _ = v.parseFieldTagsRecursive(tag, reflect.StructField{}, "", false)
v.tagCache.Set(tag, ctag)
}
}

@ -247,7 +247,7 @@ Example #2
This validates that the value is not the data types default zero value.
For numbers ensures value is not zero. For strings ensures value is
not "". For slices, maps, pointers, interfaces, channels and functions
ensures the value is not nil.
ensures the value is not nil. For structs ensures value is not the zero value.
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 other specified fields are equal to the value following the specified
field. For strings ensures value is not "". For slices, maps, pointers,
interfaces, channels and functions ensures the value is not nil.
interfaces, channels and functions ensures the value is not nil. For structs ensures value is not the zero value.
Usage: required_if
@ -273,7 +273,7 @@ Examples:
The field under validation must be present and not empty unless all
the other specified fields are equal to the value following the specified
field. For strings ensures value is not "". For slices, maps, pointers,
interfaces, channels and functions ensures the value is not nil.
interfaces, channels and functions ensures the value is not nil. For structs ensures value is not the zero value.
Usage: required_unless
@ -290,7 +290,7 @@ Examples:
The field under validation must be present and not empty only if any
of the other specified fields are present. For strings ensures value is
not "". For slices, maps, pointers, interfaces, channels and functions
ensures the value is not nil.
ensures the value is not nil. For structs ensures value is not the zero value.
Usage: required_with
@ -307,7 +307,7 @@ Examples:
The field under validation must be present and not empty only if all
of the other specified fields are present. For strings ensures value is
not "". For slices, maps, pointers, interfaces, channels and functions
ensures the value is not nil.
ensures the value is not nil. For structs ensures value is not the zero value.
Usage: required_with_all
@ -321,7 +321,7 @@ Example:
The field under validation must be present and not empty only when any
of the other specified fields are not present. For strings ensures value is
not "". For slices, maps, pointers, interfaces, channels and functions
ensures the value is not nil.
ensures the value is not nil. For structs ensures value is not the zero value.
Usage: required_without
@ -338,7 +338,7 @@ Examples:
The field under validation must be present and not empty only when all
of the other specified fields are not present. For strings ensures value is
not "". For slices, maps, pointers, interfaces, channels and functions
ensures the value is not nil.
ensures the value is not nil. For structs ensures value is not the zero value.
Usage: required_without_all
@ -352,7 +352,7 @@ Example:
The field under validation must not be present or not empty only if all
the other specified fields are equal to the value following the specified
field. For strings ensures value is not "". For slices, maps, pointers,
interfaces, channels and functions ensures the value is not nil.
interfaces, channels and functions ensures the value is not nil. For structs ensures value is not the zero value.
Usage: excluded_if
@ -369,7 +369,7 @@ Examples:
The field under validation must not be present or empty unless all
the other specified fields are equal to the value following the specified
field. For strings ensures value is not "". For slices, maps, pointers,
interfaces, channels and functions ensures the value is not nil.
interfaces, channels and functions ensures the value is not nil. For structs ensures value is not the zero value.
Usage: excluded_unless
@ -879,8 +879,6 @@ This is done using os.Stat and github.com/gabriel-vasile/mimetype
Usage: image
# URL String
# File Path
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
# 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

@ -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
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})`
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 (
@ -134,4 +137,7 @@ var (
cveRegex = regexp.MustCompile(cveRegexString)
mongodbRegex = regexp.MustCompile(mongodbRegexString)
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
}
// asFloat returns the parameter as a float64
// asFloat64 returns the parameter as a float64
// or panics if it can't convert
func asFloat(param string) float64 {
func asFloat64(param string) float64 {
i, err := strconv.ParseFloat(param, 64)
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
}
@ -286,3 +292,11 @@ func panicIf(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 {
goto CONTINUE
} else if ct.typeof == typeIsDefault {
} else if ct.typeof == typeIsDefault || ct.typeof == typeNestedStructLevel {
// set Field Level fields
v.slflParent = parent
v.flField = current

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

@ -46,6 +46,7 @@ var (
CodeNotFound = localCode{65, "Not Found", nil} // Resource does not exist.
CodeInvalidRequest = localCode{66, "Invalid Request", nil} // Invalid request.
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.
)

@ -37,7 +37,11 @@ type iTime interface {
// IsEmpty checks whether given `value` empty.
// It returns true if `value` is in: 0, nil, false, "", len(slice/map/chan) == 0,
// 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 {
return true
}
@ -88,38 +92,39 @@ func IsEmpty(value interface{}) bool {
return len(result) == 0
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.
var rv reflect.Value
if v, ok := value.(reflect.Value); ok {
rv = v
} 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)
}
@ -169,21 +174,27 @@ func IsEmpty(value interface{}) bool {
reflect.Array:
return rv.Len() == 0
case reflect.Ptr:
if len(traceSource) > 0 && traceSource[0] {
return IsEmpty(rv.Elem())
}
return rv.IsNil()
case
reflect.Func,
reflect.Ptr,
reflect.Interface,
reflect.UnsafePointer:
if rv.IsNil() {
return true
}
return rv.IsNil()
case reflect.Invalid:
return true
}
}
return false
}
// 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.
// Note that it might use reflect feature which affects performance a little.
func IsNil(value interface{}, traceSource ...bool) bool {

@ -9,7 +9,6 @@ package gfile
import (
"bufio"
"io"
"io/ioutil"
"os"
"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.
// It returns nil if it fails reading.
func GetBytes(path string) []byte {
data, err := ioutil.ReadFile(path)
data, err := os.ReadFile(path)
if err != nil {
return nil
}

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

@ -8,6 +8,8 @@ package gfsnotify
import (
"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/internal/intlog"
@ -127,6 +129,9 @@ func (w *Watcher) eventLoop() {
case callbackExitEventPanicStr:
w.RemoveCallback(callback.Id)
default:
if e, ok := err.(error); ok {
panic(gerror.WrapCode(gcode.CodeInternalPanic, e))
}
panic(err)
}
}

@ -7,8 +7,9 @@
package gmlock
import (
"sync"
"github.com/gogf/gf/v2/container/gmap"
"github.com/gogf/gf/v2/os/gmutex"
)
// 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`.
func (l *Locker) Unlock(key string) {
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`.
func (l *Locker) RUnlock(key string) {
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,
// 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 gmutex.New()
}).(*gmutex.Mutex)
return &sync.RWMutex{}
}).(*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) {
recoverFunc(ctx, v)
} else {
recoverFunc(ctx, gerror.Newf(`%+v`, exception))
recoverFunc(ctx, gerror.NewCodef(gcode.CodeInternalPanic, "%+v", exception))
}
}
}

@ -17,35 +17,35 @@ import (
var (
// Refer: http://php.net/manual/en/function.date.php
formats = map[byte]string{
'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.
'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).
'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.
'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.
'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.
'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.
'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.
'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.
'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.
'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.
'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.
'i': "04", // Time: Minutes with leading zeros. Eg: 00 to 59.
's': "05", // Time: Seconds with leading zeros. Eg: 00 through 59.
'u': "=u=.000", // Time: Milliseconds. Eg: 234, 678.
'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.
'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 ...
'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.
'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).
'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.
'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.
'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.
'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.
'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.
'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.
'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.
'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.
'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.
'i': "04", // Time: Minutes with leading zeros. Eg: 00 to 59.
's': "05", // Time: Seconds with leading zeros. Eg: 00 through 59.
'u': "=u=.000", // Time: Milliseconds. Eg: 234, 678.
'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.
'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 ...
'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.
}
@ -159,7 +159,11 @@ func (t *Time) LayoutNew(layout string) *Time {
if t == 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.
@ -167,7 +171,11 @@ func (t *Time) LayoutTo(layout string) *Time {
if t == 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
}

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

@ -14,8 +14,9 @@ import (
)
// 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.
// 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{} {
return doConvert(doConvertInput{
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:
// gconv, json, field name.
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`
@ -37,14 +37,14 @@ func Map(value interface{}, tags ...string) map[string]interface{} {
// a map[string]interface{} type variable.
// Also see Map.
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.
// 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.
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 {
return nil
}
@ -209,6 +209,7 @@ func doMapConvert(value interface{}, recursive recursiveType, tags ...string) ma
RecursiveType: recursive,
RecursiveOption: recursive == recursiveTypeTrue,
Tags: newTags,
MustMapReturn: mustMapReturn,
},
)
if m, ok := convertedValue.(map[string]interface{}); ok {
@ -228,6 +229,7 @@ type doMapConvertForMapOrStructValueInput struct {
RecursiveType recursiveType // The type from top function entry.
RecursiveOption bool // Whether convert recursively for `current` operation.
Tags []string // Map key mapping.
MustMapReturn bool // Must return map instead of Value when empty.
}
func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} {
@ -259,11 +261,17 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
mapKeyValue = reflectValue.MapIndex(k)
mapValue interface{}
)
if mapKeyValue.IsZero() {
// in case of:
// exception recovered: reflect: call of reflect.Value.Interface on zero Value
mapValue = reflect.New(mapKeyValue.Type()).Elem()
} else {
switch {
case mapKeyValue.IsZero():
if mapKeyValue.IsNil() {
// quick check for nil value.
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()
}
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 dataMap

@ -100,7 +100,7 @@ func doMapToMap(params interface{}, pointer interface{}, mapping ...map[string]s
if v, ok := exception.(error); ok && gerror.HasStack(v) {
err = v
} 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) {
err = v
} 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) {
err = v
} 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()
}
// 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.
// For performance enhancement purpose.
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.
if pointerElemReflectValue.Kind() == reflect.Ptr {
if !pointerElemReflectValue.IsValid() || pointerElemReflectValue.IsNil() {
e := reflect.New(pointerElemReflectValue.Type().Elem()).Elem()
pointerElemReflectValue.Set(e.Addr())
e := reflect.New(pointerElemReflectValue.Type().Elem())
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 {
// 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.
// DO NOT use MapDeep here.
paramsMap := Map(paramsInterface)
paramsMap := doMapConvert(paramsInterface, recursiveTypeAuto, true)
if paramsMap == nil {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
@ -379,6 +390,11 @@ func bindVarToStructAttr(structReflectValue reflect.Value, attrName string, valu
return
}
// Try to call custom converter.
if ok, err := callCustomConverter(reflect.ValueOf(value), structFieldValue); ok {
return err
}
// Common interface check.
var ok bool
if err, ok = bindVarToReflectValueWithInterfaceCheck(structFieldValue, value); ok {
@ -623,7 +639,7 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma
defer func() {
if exception := recover(); exception != nil {
err = gerror.NewCodef(
gcode.CodeInternalError,
gcode.CodeInternalPanic,
`cannot convert value "%+v" to type "%s":%+v`,
value,
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) {
err = v
} else {
err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception)
err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception)
}
}
}()

@ -9,6 +9,7 @@ package gutil
import (
"context"
"github.com/gogf/gf/v2/errors/gcode"
"reflect"
"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) {
err = v
} 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) {
catch[0](ctx, v)
} 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)
* 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)
![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
@ -139,8 +139,8 @@ These adapters can be used with the tracelog package.
### [github.com/pashagolub/pgxmock](https://github.com/pashagolub/pgxmock)
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 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.
### [github.com/georgysavva/scany](https://github.com/georgysavva/scany)

@ -194,7 +194,7 @@ func ParseConfigWithOptions(connString string, options ParseConfigOptions) (*Con
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:
//
// - 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)
for mrr.NextResult() {
commandTag, err = mrr.ResultReader().Close()
commandTag, _ = mrr.ResultReader().Close()
}
err = mrr.Close()
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) {
pipeline := c.pgConn.StartPipeline(context.Background())
defer func() {
if pbr.err != nil {
if pbr != nil && pbr.err != nil {
pipeline.Close()
}
}()

@ -7,17 +7,17 @@ details.
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"))
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
`ConnectConfig` to configure settings such as tracing that cannot be configured with a connection string.
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.
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.
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 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.
type Config struct {
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)
// 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) {
config, err := ParseConfig(connString)
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)
// 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.
func ConnectWithOptions(ctx context.Context, connString string, parseConfigOptions ParseConfigOptions) (*PgConn, error) {
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
// 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
// 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
var fallbackConfig *FallbackConfig
for _, fc := range fallbackConfigs {
for i, fc := range fallbackConfigs {
// ConnectTimeout restricts the whole connection process.
if config.ConnectTimeout != 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(octx, config.ConnectTimeout)
defer cancel()
// create new context first time or when previous host was different
if i == 0 || (fallbackConfigs[i].Host != fallbackConfigs[i-1].Host) {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(octx, config.ConnectTimeout)
defer cancel()
}
} else {
ctx = octx
}

@ -6,15 +6,18 @@ import (
"io"
"strconv"
"strings"
"sync"
"time"
)
// 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.
type tracer struct {
TracerOptions
mux sync.Mutex
w io.Writer
buf *bytes.Buffer
TracerOptions
}
// 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:
t.traceTerminate(sender, encodedLen, msg)
default:
t.beginTrace(sender, encodedLen, "Unknown")
t.finishTrace()
t.writeTrace(sender, encodedLen, "Unknown", nil)
}
}
func (t *tracer) traceAuthenticationCleartextPassword(sender byte, encodedLen int32, msg *AuthenticationCleartextPassword) {
t.beginTrace(sender, encodedLen, "AuthenticationCleartextPassword")
t.finishTrace()
t.writeTrace(sender, encodedLen, "AuthenticationCleartextPassword", nil)
}
func (t *tracer) traceAuthenticationGSS(sender byte, encodedLen int32, msg *AuthenticationGSS) {
t.beginTrace(sender, encodedLen, "AuthenticationGSS")
t.finishTrace()
t.writeTrace(sender, encodedLen, "AuthenticationGSS", nil)
}
func (t *tracer) traceAuthenticationGSSContinue(sender byte, encodedLen int32, msg *AuthenticationGSSContinue) {
t.beginTrace(sender, encodedLen, "AuthenticationGSSContinue")
t.finishTrace()
t.writeTrace(sender, encodedLen, "AuthenticationGSSContinue", nil)
}
func (t *tracer) traceAuthenticationMD5Password(sender byte, encodedLen int32, msg *AuthenticationMD5Password) {
t.beginTrace(sender, encodedLen, "AuthenticationMD5Password")
t.finishTrace()
t.writeTrace(sender, encodedLen, "AuthenticationMD5Password", nil)
}
func (t *tracer) traceAuthenticationOk(sender byte, encodedLen int32, msg *AuthenticationOk) {
t.beginTrace(sender, encodedLen, "AuthenticationOk")
t.finishTrace()
t.writeTrace(sender, encodedLen, "AuthenticationOk", nil)
}
func (t *tracer) traceAuthenticationSASL(sender byte, encodedLen int32, msg *AuthenticationSASL) {
t.beginTrace(sender, encodedLen, "AuthenticationSASL")
t.finishTrace()
t.writeTrace(sender, encodedLen, "AuthenticationSASL", nil)
}
func (t *tracer) traceAuthenticationSASLContinue(sender byte, encodedLen int32, msg *AuthenticationSASLContinue) {
t.beginTrace(sender, encodedLen, "AuthenticationSASLContinue")
t.finishTrace()
t.writeTrace(sender, encodedLen, "AuthenticationSASLContinue", nil)
}
func (t *tracer) traceAuthenticationSASLFinal(sender byte, encodedLen int32, msg *AuthenticationSASLFinal) {
t.beginTrace(sender, encodedLen, "AuthenticationSASLFinal")
t.finishTrace()
t.writeTrace(sender, encodedLen, "AuthenticationSASLFinal", nil)
}
func (t *tracer) traceBackendKeyData(sender byte, encodedLen int32, msg *BackendKeyData) {
t.beginTrace(sender, encodedLen, "BackendKeyData")
if t.RegressMode {
t.buf.WriteString("\t NNNN NNNN")
} else {
fmt.Fprintf(t.buf, "\t %d %d", msg.ProcessID, msg.SecretKey)
}
t.finishTrace()
t.writeTrace(sender, encodedLen, "BackendKeyData", func() {
if t.RegressMode {
t.buf.WriteString("\t NNNN NNNN")
} else {
fmt.Fprintf(t.buf, "\t %d %d", msg.ProcessID, msg.SecretKey)
}
})
}
func (t *tracer) traceBind(sender byte, encodedLen int32, msg *Bind) {
t.beginTrace(sender, encodedLen, "Bind")
fmt.Fprintf(t.buf, "\t %s %s %d", traceDoubleQuotedString([]byte(msg.DestinationPortal)), traceDoubleQuotedString([]byte(msg.PreparedStatement)), len(msg.ParameterFormatCodes))
for _, fc := range msg.ParameterFormatCodes {
fmt.Fprintf(t.buf, " %d", fc)
}
fmt.Fprintf(t.buf, " %d", len(msg.Parameters))
for _, p := range msg.Parameters {
fmt.Fprintf(t.buf, " %s", traceSingleQuotedString(p))
}
fmt.Fprintf(t.buf, " %d", len(msg.ResultFormatCodes))
for _, fc := range msg.ResultFormatCodes {
fmt.Fprintf(t.buf, " %d", fc)
}
t.finishTrace()
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))
for _, fc := range msg.ParameterFormatCodes {
fmt.Fprintf(t.buf, " %d", fc)
}
fmt.Fprintf(t.buf, " %d", len(msg.Parameters))
for _, p := range msg.Parameters {
fmt.Fprintf(t.buf, " %s", traceSingleQuotedString(p))
}
fmt.Fprintf(t.buf, " %d", len(msg.ResultFormatCodes))
for _, fc := range msg.ResultFormatCodes {
fmt.Fprintf(t.buf, " %d", fc)
}
})
}
func (t *tracer) traceBindComplete(sender byte, encodedLen int32, msg *BindComplete) {
t.beginTrace(sender, encodedLen, "BindComplete")
t.finishTrace()
t.writeTrace(sender, encodedLen, "BindComplete", nil)
}
func (t *tracer) traceCancelRequest(sender byte, encodedLen int32, msg *CancelRequest) {
t.beginTrace(sender, encodedLen, "CancelRequest")
t.finishTrace()
t.writeTrace(sender, encodedLen, "CancelRequest", nil)
}
func (t *tracer) traceClose(sender byte, encodedLen int32, msg *Close) {
t.beginTrace(sender, encodedLen, "Close")
t.finishTrace()
t.writeTrace(sender, encodedLen, "Close", nil)
}
func (t *tracer) traceCloseComplete(sender byte, encodedLen int32, msg *CloseComplete) {
t.beginTrace(sender, encodedLen, "CloseComplete")
t.finishTrace()
t.writeTrace(sender, encodedLen, "CloseComplete", nil)
}
func (t *tracer) traceCommandComplete(sender byte, encodedLen int32, msg *CommandComplete) {
t.beginTrace(sender, encodedLen, "CommandComplete")
fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString(msg.CommandTag))
t.finishTrace()
t.writeTrace(sender, encodedLen, "CommandComplete", func() {
fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString(msg.CommandTag))
})
}
func (t *tracer) traceCopyBothResponse(sender byte, encodedLen int32, msg *CopyBothResponse) {
t.beginTrace(sender, encodedLen, "CopyBothResponse")
t.finishTrace()
t.writeTrace(sender, encodedLen, "CopyBothResponse", nil)
}
func (t *tracer) traceCopyData(sender byte, encodedLen int32, msg *CopyData) {
t.beginTrace(sender, encodedLen, "CopyData")
t.finishTrace()
t.writeTrace(sender, encodedLen, "CopyData", nil)
}
func (t *tracer) traceCopyDone(sender byte, encodedLen int32, msg *CopyDone) {
t.beginTrace(sender, encodedLen, "CopyDone")
t.finishTrace()
t.writeTrace(sender, encodedLen, "CopyDone", nil)
}
func (t *tracer) traceCopyFail(sender byte, encodedLen int32, msg *CopyFail) {
t.beginTrace(sender, encodedLen, "CopyFail")
fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString([]byte(msg.Message)))
t.finishTrace()
t.writeTrace(sender, encodedLen, "CopyFail", func() {
fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString([]byte(msg.Message)))
})
}
func (t *tracer) traceCopyInResponse(sender byte, encodedLen int32, msg *CopyInResponse) {
t.beginTrace(sender, encodedLen, "CopyInResponse")
t.finishTrace()
t.writeTrace(sender, encodedLen, "CopyInResponse", nil)
}
func (t *tracer) traceCopyOutResponse(sender byte, encodedLen int32, msg *CopyOutResponse) {
t.beginTrace(sender, encodedLen, "CopyOutResponse")
t.finishTrace()
t.writeTrace(sender, encodedLen, "CopyOutResponse", nil)
}
func (t *tracer) traceDataRow(sender byte, encodedLen int32, msg *DataRow) {
t.beginTrace(sender, encodedLen, "DataRow")
fmt.Fprintf(t.buf, "\t %d", len(msg.Values))
for _, v := range msg.Values {
if v == nil {
t.buf.WriteString(" -1")
} else {
fmt.Fprintf(t.buf, " %d %s", len(v), traceSingleQuotedString(v))
t.writeTrace(sender, encodedLen, "DataRow", func() {
fmt.Fprintf(t.buf, "\t %d", len(msg.Values))
for _, v := range msg.Values {
if v == nil {
t.buf.WriteString(" -1")
} else {
fmt.Fprintf(t.buf, " %d %s", len(v), traceSingleQuotedString(v))
}
}
}
t.finishTrace()
})
}
func (t *tracer) traceDescribe(sender byte, encodedLen int32, msg *Describe) {
t.beginTrace(sender, encodedLen, "Describe")
fmt.Fprintf(t.buf, "\t %c %s", msg.ObjectType, traceDoubleQuotedString([]byte(msg.Name)))
t.finishTrace()
t.writeTrace(sender, encodedLen, "Describe", func() {
fmt.Fprintf(t.buf, "\t %c %s", msg.ObjectType, traceDoubleQuotedString([]byte(msg.Name)))
})
}
func (t *tracer) traceEmptyQueryResponse(sender byte, encodedLen int32, msg *EmptyQueryResponse) {
t.beginTrace(sender, encodedLen, "EmptyQueryResponse")
t.finishTrace()
t.writeTrace(sender, encodedLen, "EmptyQueryResponse", nil)
}
func (t *tracer) traceErrorResponse(sender byte, encodedLen int32, msg *ErrorResponse) {
t.beginTrace(sender, encodedLen, "ErrorResponse")
t.finishTrace()
t.writeTrace(sender, encodedLen, "ErrorResponse", nil)
}
func (t *tracer) TraceQueryute(sender byte, encodedLen int32, msg *Execute) {
t.beginTrace(sender, encodedLen, "Execute")
fmt.Fprintf(t.buf, "\t %s %d", traceDoubleQuotedString([]byte(msg.Portal)), msg.MaxRows)
t.finishTrace()
t.writeTrace(sender, encodedLen, "Execute", func() {
fmt.Fprintf(t.buf, "\t %s %d", traceDoubleQuotedString([]byte(msg.Portal)), msg.MaxRows)
})
}
func (t *tracer) traceFlush(sender byte, encodedLen int32, msg *Flush) {
t.beginTrace(sender, encodedLen, "Flush")
t.finishTrace()
t.writeTrace(sender, encodedLen, "Flush", nil)
}
func (t *tracer) traceFunctionCall(sender byte, encodedLen int32, msg *FunctionCall) {
t.beginTrace(sender, encodedLen, "FunctionCall")
t.finishTrace()
t.writeTrace(sender, encodedLen, "FunctionCall", nil)
}
func (t *tracer) traceFunctionCallResponse(sender byte, encodedLen int32, msg *FunctionCallResponse) {
t.beginTrace(sender, encodedLen, "FunctionCallResponse")
t.finishTrace()
t.writeTrace(sender, encodedLen, "FunctionCallResponse", nil)
}
func (t *tracer) traceGSSEncRequest(sender byte, encodedLen int32, msg *GSSEncRequest) {
t.beginTrace(sender, encodedLen, "GSSEncRequest")
t.finishTrace()
t.writeTrace(sender, encodedLen, "GSSEncRequest", nil)
}
func (t *tracer) traceNoData(sender byte, encodedLen int32, msg *NoData) {
t.beginTrace(sender, encodedLen, "NoData")
t.finishTrace()
t.writeTrace(sender, encodedLen, "NoData", nil)
}
func (t *tracer) traceNoticeResponse(sender byte, encodedLen int32, msg *NoticeResponse) {
t.beginTrace(sender, encodedLen, "NoticeResponse")
t.finishTrace()
t.writeTrace(sender, encodedLen, "NoticeResponse", nil)
}
func (t *tracer) traceNotificationResponse(sender byte, encodedLen int32, msg *NotificationResponse) {
t.beginTrace(sender, encodedLen, "NotificationResponse")
fmt.Fprintf(t.buf, "\t %d %s %s", msg.PID, traceDoubleQuotedString([]byte(msg.Channel)), traceDoubleQuotedString([]byte(msg.Payload)))
t.finishTrace()
t.writeTrace(sender, encodedLen, "NotificationResponse", func() {
fmt.Fprintf(t.buf, "\t %d %s %s", msg.PID, traceDoubleQuotedString([]byte(msg.Channel)), traceDoubleQuotedString([]byte(msg.Payload)))
})
}
func (t *tracer) traceParameterDescription(sender byte, encodedLen int32, msg *ParameterDescription) {
t.beginTrace(sender, encodedLen, "ParameterDescription")
t.finishTrace()
t.writeTrace(sender, encodedLen, "ParameterDescription", nil)
}
func (t *tracer) traceParameterStatus(sender byte, encodedLen int32, msg *ParameterStatus) {
t.beginTrace(sender, encodedLen, "ParameterStatus")
fmt.Fprintf(t.buf, "\t %s %s", traceDoubleQuotedString([]byte(msg.Name)), traceDoubleQuotedString([]byte(msg.Value)))
t.finishTrace()
t.writeTrace(sender, encodedLen, "ParameterStatus", func() {
fmt.Fprintf(t.buf, "\t %s %s", traceDoubleQuotedString([]byte(msg.Name)), traceDoubleQuotedString([]byte(msg.Value)))
})
}
func (t *tracer) traceParse(sender byte, encodedLen int32, msg *Parse) {
t.beginTrace(sender, encodedLen, "Parse")
fmt.Fprintf(t.buf, "\t %s %s %d", traceDoubleQuotedString([]byte(msg.Name)), traceDoubleQuotedString([]byte(msg.Query)), len(msg.ParameterOIDs))
for _, oid := range msg.ParameterOIDs {
fmt.Fprintf(t.buf, " %d", oid)
}
t.finishTrace()
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))
for _, oid := range msg.ParameterOIDs {
fmt.Fprintf(t.buf, " %d", oid)
}
})
}
func (t *tracer) traceParseComplete(sender byte, encodedLen int32, msg *ParseComplete) {
t.beginTrace(sender, encodedLen, "ParseComplete")
t.finishTrace()
t.writeTrace(sender, encodedLen, "ParseComplete", nil)
}
func (t *tracer) tracePortalSuspended(sender byte, encodedLen int32, msg *PortalSuspended) {
t.beginTrace(sender, encodedLen, "PortalSuspended")
t.finishTrace()
t.writeTrace(sender, encodedLen, "PortalSuspended", nil)
}
func (t *tracer) traceQuery(sender byte, encodedLen int32, msg *Query) {
t.beginTrace(sender, encodedLen, "Query")
fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString([]byte(msg.String)))
t.finishTrace()
t.writeTrace(sender, encodedLen, "Query", func() {
fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString([]byte(msg.String)))
})
}
func (t *tracer) traceReadyForQuery(sender byte, encodedLen int32, msg *ReadyForQuery) {
t.beginTrace(sender, encodedLen, "ReadyForQuery")
fmt.Fprintf(t.buf, "\t %c", msg.TxStatus)
t.finishTrace()
t.writeTrace(sender, encodedLen, "ReadyForQuery", func() {
fmt.Fprintf(t.buf, "\t %c", msg.TxStatus)
})
}
func (t *tracer) traceRowDescription(sender byte, encodedLen int32, msg *RowDescription) {
t.beginTrace(sender, encodedLen, "RowDescription")
fmt.Fprintf(t.buf, "\t %d", len(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)
}
t.finishTrace()
t.writeTrace(sender, encodedLen, "RowDescription", func() {
fmt.Fprintf(t.buf, "\t %d", len(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)
}
})
}
func (t *tracer) traceSSLRequest(sender byte, encodedLen int32, msg *SSLRequest) {
t.beginTrace(sender, encodedLen, "SSLRequest")
t.finishTrace()
t.writeTrace(sender, encodedLen, "SSLRequest", nil)
}
func (t *tracer) traceStartupMessage(sender byte, encodedLen int32, msg *StartupMessage) {
t.beginTrace(sender, encodedLen, "StartupMessage")
t.finishTrace()
t.writeTrace(sender, encodedLen, "StartupMessage", nil)
}
func (t *tracer) traceSync(sender byte, encodedLen int32, msg *Sync) {
t.beginTrace(sender, encodedLen, "Sync")
t.finishTrace()
t.writeTrace(sender, encodedLen, "Sync", nil)
}
func (t *tracer) traceTerminate(sender byte, encodedLen int32, msg *Terminate) {
t.beginTrace(sender, encodedLen, "Terminate")
t.finishTrace()
t.writeTrace(sender, encodedLen, "Terminate", nil)
}
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 {
now := time.Now()
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.WriteByte('\t')
t.buf.WriteString(strconv.FormatInt(int64(encodedLen), 10))
}
func (t *tracer) finishTrace() {
if writeDetails != nil {
writeDetails()
}
t.buf.WriteByte('\n')
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

@ -92,6 +92,23 @@ func (JSONCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan
switch target.(type) {
case *string:
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:
return scanPlanJSONToByteSlice{}
case BytesScanner:
@ -104,19 +121,6 @@ func (JSONCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan
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{}
}

@ -144,20 +144,20 @@ func (n *Numeric) toBigInt() (*big.Int, error) {
}
func parseNumericString(str string) (n *big.Int, exp int32, err error) {
parts := strings.SplitN(str, ".", 2)
digits := strings.Join(parts, "")
idx := strings.IndexByte(str, '.')
if len(parts) > 1 {
exp = int32(-len(parts[1]))
} else {
for len(digits) > 1 && digits[len(digits)-1] == '0' && digits[len(digits)-2] != '-' {
digits = digits[:len(digits)-1]
if idx == -1 {
for len(str) > 1 && str[len(str)-1] == '0' && str[len(str)-2] != '-' {
str = str[:len(str)-1]
exp++
}
} else {
exp = int32(-(len(str) - idx - 1))
str = str[:idx] + str[idx+1:]
}
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)
}

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

@ -306,7 +306,7 @@ func (rows *baseRows) Values() ([]any, error) {
copy(newBuf, buf)
values = append(values, newBuf)
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
// 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) {
var value T
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
// 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) {
var value T
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 {
scanTargets = rs.appendScanTargets(dstElemValue.Field(i), scanTargets)
} 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())
}
}

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

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

@ -23,7 +23,7 @@ bench: testdeps
testdata/redis:
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
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 Ring](https://redis.uptrace.dev/guide/ring.html).
- [Redis Performance Monitoring](https://redis.uptrace.dev/guide/redis-performance-monitoring.html).
- [Redis Probabilistic [RedisStack]](https://redis.io/docs/data-types/probabilistic/)
## 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
Some corner cases:

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

Loading…
Cancel
Save