diff --git a/go.mod b/go.mod index 7d83e939..0b17a730 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,15 @@ module github.com/Scalingo/link/v3 go 1.25.0 require ( - github.com/Scalingo/go-handlers v1.11.0 + github.com/Scalingo/go-handlers v1.11.1 github.com/Scalingo/go-philae/v4 v4.4.7 github.com/Scalingo/go-utils/crypto v1.1.1 github.com/Scalingo/go-utils/errors v1.1.1 github.com/Scalingo/go-utils/errors/v2 v2.5.1 - github.com/Scalingo/go-utils/errors/v3 v3.2.0 - github.com/Scalingo/go-utils/etcd v1.2.1 - github.com/Scalingo/go-utils/logger v1.12.1 - github.com/Scalingo/go-utils/retry v1.4.0 + github.com/Scalingo/go-utils/errors/v3 v3.2.1 + github.com/Scalingo/go-utils/etcd v1.2.2 + github.com/Scalingo/go-utils/logger v1.12.2 + github.com/Scalingo/go-utils/retry v1.4.1 github.com/Scalingo/link/v2 v2.0.7 github.com/cenkalti/backoff/v5 v5.0.3 github.com/gofrs/uuid/v5 v5.4.0 @@ -28,8 +28,8 @@ require ( github.com/stretchr/testify v1.11.1 github.com/urfave/cli/v3 v3.8.0 github.com/vishvananda/netlink v1.3.1 - go.etcd.io/etcd/api/v3 v3.6.9 - go.etcd.io/etcd/client/v3 v3.6.9 + go.etcd.io/etcd/api/v3 v3.6.10 + go.etcd.io/etcd/client/v3 v3.6.10 ) require ( @@ -50,33 +50,33 @@ require ( github.com/goccy/go-json v0.10.6 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.21 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/mattn/go-runewidth v0.0.23 // indirect github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect - github.com/olekukonko/errors v1.2.0 // indirect + github.com/olekukonko/errors v1.3.0 // indirect github.com/olekukonko/ll v0.1.8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rollbar/rollbar-go v1.4.8 // indirect github.com/urfave/negroni/v3 v3.1.1 // indirect github.com/vishvananda/netns v0.0.5 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.6.9 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.10 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.67.0 // indirect - go.opentelemetry.io/otel v1.42.0 // indirect - go.opentelemetry.io/otel/metric v1.42.0 // indirect - go.opentelemetry.io/otel/trace v1.42.0 // indirect + go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.68.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.1 // indirect - golang.org/x/net v0.52.0 // indirect + go.uber.org/zap v1.28.0 // indirect + golang.org/x/net v0.53.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect - golang.org/x/sys v0.42.0 // indirect - golang.org/x/text v0.35.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect - google.golang.org/grpc v1.79.3 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/text v0.36.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect + google.golang.org/grpc v1.80.0 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/errgo.v1 v1.0.1 // indirect gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect diff --git a/go.sum b/go.sum index 8ee90f7e..fa1ae434 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Scalingo/errgo-rollbar v0.2.1 h1:S2hz3FcjiSEB8yoQS2A0WzUY2Cq6tvD2IHzB4xlW4bA= github.com/Scalingo/errgo-rollbar v0.2.1/go.mod h1:C2wzmHChrL2NqZDhDIIWemnJtBJh5nvAbw396uVR6Kc= -github.com/Scalingo/go-handlers v1.11.0 h1:aAVIfJRfJ5u5b2yt7vGPi2FSUztB95+GBY7Dy9zwLoE= -github.com/Scalingo/go-handlers v1.11.0/go.mod h1:T+l8ERwHlb/ZGGNKfFcW9peZq95TfApjOmdO0H05nQk= +github.com/Scalingo/go-handlers v1.11.1 h1:c1BnZe2EhCebIzfygoOmcl7iZlUdn5OYuG/4xdAddT8= +github.com/Scalingo/go-handlers v1.11.1/go.mod h1:FP+IibVd+yWkSY9B+rzcIi629MMk/7kNfcEjIZUhMq4= github.com/Scalingo/go-philae/v4 v4.4.7 h1:UBcHkWHMdMJJxKia2YAqSNBZ8cda0hqCdkK+6Kq81pM= github.com/Scalingo/go-philae/v4 v4.4.7/go.mod h1:GFAw9PTKhMsG8cQ/Yadyopl7yMCp0CCSo7480NxLV44= github.com/Scalingo/go-utils/crypto v1.1.1 h1:+F4JqC/8Lu8b1MDJwdQjT19yzLhShWPk+K93cUv7KVg= @@ -10,14 +10,14 @@ github.com/Scalingo/go-utils/errors v1.1.1 h1:G7zypaDBj0O6QFvX0xL5dMDXbiBgq+3KKu github.com/Scalingo/go-utils/errors v1.1.1/go.mod h1:gsnGOMma5x3CSgPb8i5eMuHcKi3RvTJ9dWPNRev161c= github.com/Scalingo/go-utils/errors/v2 v2.5.1 h1:1tfJW6/ZxTgrRmFTlKQCOtArQquOW0/XdZQzx8wMHoM= github.com/Scalingo/go-utils/errors/v2 v2.5.1/go.mod h1:SbR1JuMtfAl+gpM7ahUW/c3Jm5MMzMAwJBk1pEHkVd8= -github.com/Scalingo/go-utils/errors/v3 v3.2.0 h1:Ks+v2oRwv3VZfe+xVB+kpfmZouXHVCPHHtwL5W60prc= -github.com/Scalingo/go-utils/errors/v3 v3.2.0/go.mod h1:jVVNoOdYFjuNkR/BeEZWNWJVvu4jmyLY4udlsQQyBss= -github.com/Scalingo/go-utils/etcd v1.2.1 h1:3cNNLYLxUTGdP1c+XA5VNH052uaCjRwN9Y1NkIgwYkk= -github.com/Scalingo/go-utils/etcd v1.2.1/go.mod h1:mrwfLv05Ddy1ssNPweCPhnygsHacQD3aBiP7y9LuaFQ= -github.com/Scalingo/go-utils/logger v1.12.1 h1:r+RqwOcnsTtKoQdvcNVZCtu0Xhq01tp/3gT6+4Q7AxI= -github.com/Scalingo/go-utils/logger v1.12.1/go.mod h1:uH7LVG1pQR+5jpVgGDFyFfTMeHc3nUXC7GRUc2dPoZ4= -github.com/Scalingo/go-utils/retry v1.4.0 h1:/h11gWPeRyIPdfDJG93b7kUOjQ18Pbzo/JbyWNSE2vs= -github.com/Scalingo/go-utils/retry v1.4.0/go.mod h1:wpmbBFWID/Gt1WPv7WKUYMKMq7kOFJtAQTTU7vIEuZ8= +github.com/Scalingo/go-utils/errors/v3 v3.2.1 h1:2w3qUz6MxJa3aqx/biz2G3JquSKsFnfz/E7wrNf/LPc= +github.com/Scalingo/go-utils/errors/v3 v3.2.1/go.mod h1:jVVNoOdYFjuNkR/BeEZWNWJVvu4jmyLY4udlsQQyBss= +github.com/Scalingo/go-utils/etcd v1.2.2 h1:9de1/sv8tM5y0i62ImN7/01QSgEruu8up55wJghxbSQ= +github.com/Scalingo/go-utils/etcd v1.2.2/go.mod h1:hHEFYB/AT1HJqkAAUXHBgtJKjKH4pgYK+IDG4x0KS0g= +github.com/Scalingo/go-utils/logger v1.12.2 h1:9vm83/gqjCIy5t+OuNYjkVOUrJtdMy78XNIv8E+OCCU= +github.com/Scalingo/go-utils/logger v1.12.2/go.mod h1:vaeFcI5LMHiRRmMfJbbnblbj3RXRJIzxUcyEjZpMFpg= +github.com/Scalingo/go-utils/retry v1.4.1 h1:tlr9FYbmDa+5mDenBpTNAJmF9bfcH8FzVb3hl80A+Zg= +github.com/Scalingo/go-utils/retry v1.4.1/go.mod h1:Vz/QTqciCzurJKwBFjrzY0QG5re/kOCNSUDFKHeXcaE= github.com/Scalingo/go-utils/security v1.2.2 h1:3AkvqQm0b58wsM4mtvh6vlaOEelRJuvI1iLviMTdXX4= github.com/Scalingo/go-utils/security v1.2.2/go.mod h1:oGgcjK4/PtG3rspMTygnZUl0z2cu/qS+JA+HGpKY0Lk= github.com/Scalingo/link/v2 v2.0.7 h1:jv9y/XTLOWBgPqBjkhh3sJbRhoQ9f79rC+KHlUCeBU0= @@ -69,8 +69,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= github.com/j-keck/arping v1.0.3 h1:aeVk5WnsK6xPaRsFt5wV6W2x5l/n5XBNp0MMr/FEv2k= github.com/j-keck/arping v1.0.3/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -94,14 +94,14 @@ github.com/looplab/fsm v1.0.3 h1:qtxBsa2onOs0qFOtkqwf5zE0uP0+Te+wlIvXctPKpcw= github.com/looplab/fsm v1.0.3/go.mod h1:PmD3fFvQEIsjMEfvZdrCDZ6y8VwKTwWNjlpEr6IKPO4= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w= -github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw= +github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= -github.com/olekukonko/errors v1.2.0 h1:10Zcn4GeV59t/EGqJc8fUjtFT/FuUh5bTMzZ1XwmCRo= -github.com/olekukonko/errors v1.2.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= +github.com/olekukonko/errors v1.3.0 h1:teJvgLGUEqMzBUms+Dj3/3szNqCG/Jdw9iDbum8fR6U= +github.com/olekukonko/errors v1.3.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= github.com/olekukonko/ll v0.1.8 h1:ysHCJRGHYKzmBSdz9w5AySztx7lG8SQY+naTGYUbsz8= github.com/olekukonko/ll v0.1.8/go.mod h1:RPRC6UcscfFZgjo1nulkfMH5IM0QAYim0LfnMvUuozw= github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I= @@ -135,34 +135,36 @@ github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZla github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/etcd/api/v3 v3.6.9 h1:UA7iKfEW1AzgihcBSGXci2kDGQiokSq41F9HMCI/RTI= -go.etcd.io/etcd/api/v3 v3.6.9/go.mod h1:csEk/qTfxKL36NqJdU15Tgtl65A8dyEY2BYo7PRsIwk= -go.etcd.io/etcd/client/pkg/v3 v3.6.9 h1:T8nuk8Lz64C+Hzb0coBFLMSlVSQZBpAtFk46swdM1DA= -go.etcd.io/etcd/client/pkg/v3 v3.6.9/go.mod h1:WEy3PpwbbEBVRdh1NVJYsuUe/8eyI21PNJRazeD8z/Y= -go.etcd.io/etcd/client/v3 v3.6.9 h1:3X555hQXmhRr27O37wls53g68CpUiPOiHXrZfz2Al+o= -go.etcd.io/etcd/client/v3 v3.6.9/go.mod h1:KO7H1HLYh1qaljuVZJQwBFk1lRce6pJzt+C81GEnrlM= +go.etcd.io/etcd/api/v3 v3.6.10 h1:jlwjtELjA8yi2VWpOFH+0w0lGr3K6mVDyn0RDB9aaAY= +go.etcd.io/etcd/api/v3 v3.6.10/go.mod h1:pdV4VeFmvhdNjB4LWRkC8ReLyRBAxUOze3GarMhE2sk= +go.etcd.io/etcd/client/pkg/v3 v3.6.10 h1:tBT7podcPhuVbCVkAEzx8bC5I+aqxfLwBN8/As1arrA= +go.etcd.io/etcd/client/pkg/v3 v3.6.10/go.mod h1:WEy3PpwbbEBVRdh1NVJYsuUe/8eyI21PNJRazeD8z/Y= +go.etcd.io/etcd/client/v3 v3.6.10 h1:J598zJ+C/ZPvImypmq5waj84+bovePrlZERHklf34y0= +go.etcd.io/etcd/client/v3 v3.6.10/go.mod h1:iHhUDUcEwaKs1YFq3MgmI9U4zhTVasp/vgdVbFf1RS8= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.67.0 h1:b6GmayQMq3nLt5X/+u+B4wnU5CqaMBBDuPz+TFu07rg= -go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.67.0/go.mod h1:R6Z44a4CJLVvfd0n95UfHq6wD6SyGMvjfZfVK9GRy3c= -go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho= -go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 h1:s/1iRkCKDfhlh1JF26knRneorus8aOwVIDhvYx9WoDw= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0/go.mod h1:UI3wi0FXg1Pofb8ZBiBLhtMzgoTm1TYkMvn71fAqDzs= -go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4= -go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI= -go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= -go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= -go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA= -go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc= -go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY= -go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc= +go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.68.0 h1:IWiaPd/st8QTIiNaFonF/Q9RtSoV8JD2qheNr7e/I64= +go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.68.0/go.mod h1:EVeEQjePpdJBXJQJX2qnguGnZI++PB363Khvz6BRdMM= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 h1:mS47AX77OtFfKG4vtp+84kuGSFZHTyxtXIN269vChY0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0/go.mod h1:PJnsC41lAGncJlPUniSwM81gc80GkgWJWr3cu2nKEtU= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= -go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= +go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -174,8 +176,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= -golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -189,15 +191,14 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= -golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -207,14 +208,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0= -google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= -google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= -google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec= +google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/vendor/github.com/Scalingo/go-handlers/CHANGELOG.md b/vendor/github.com/Scalingo/go-handlers/CHANGELOG.md index d7eedcfc..4de48b39 100644 --- a/vendor/github.com/Scalingo/go-handlers/CHANGELOG.md +++ b/vendor/github.com/Scalingo/go-handlers/CHANGELOG.md @@ -2,6 +2,10 @@ ## To be Released +## v1.11.1 + +- chore(deps): bump several dependencies + ## v1.11.0 - feat(otel) Improve opentelemetry instrumentation by integrating with gorilla mux, add missing http.route attribute diff --git a/vendor/github.com/Scalingo/go-handlers/README.md b/vendor/github.com/Scalingo/go-handlers/README.md index d2ceaa6e..6f04b54f 100644 --- a/vendor/github.com/Scalingo/go-handlers/README.md +++ b/vendor/github.com/Scalingo/go-handlers/README.md @@ -1,4 +1,4 @@ -# Custom Router and Handler v1.10.0 +# Custom Router and Handler v1.11.1 ## Advantages @@ -164,7 +164,7 @@ Bump new version number in `CHANGELOG.md` and `README.md`. Commit, tag and create a new release: ```sh -version="1.10.0" +version="1.11.1" git switch --create release/${version} git add CHANGELOG.md README.md diff --git a/vendor/github.com/Scalingo/go-utils/errors/v3/CHANGELOG.md b/vendor/github.com/Scalingo/go-utils/errors/v3/CHANGELOG.md index 8855b809..b7e9a9e6 100644 --- a/vendor/github.com/Scalingo/go-utils/errors/v3/CHANGELOG.md +++ b/vendor/github.com/Scalingo/go-utils/errors/v3/CHANGELOG.md @@ -2,6 +2,10 @@ ## To be Released +## v3.2.1 + +* chore(deps): bump several dependencies + ## v3.2.0 * feat(errors) Add `Join` wrapping `errors.Join` from standard library diff --git a/vendor/github.com/Scalingo/go-utils/errors/v3/README.md b/vendor/github.com/Scalingo/go-utils/errors/v3/README.md index a37614dc..f73f1fe8 100644 --- a/vendor/github.com/Scalingo/go-utils/errors/v3/README.md +++ b/vendor/github.com/Scalingo/go-utils/errors/v3/README.md @@ -1,3 +1,3 @@ -# Package `errors` v3.2.0 +# Package `errors` v3.2.1 The package `errors` contains various utility regarding errors management. diff --git a/vendor/github.com/Scalingo/go-utils/errors/v3/cause.go b/vendor/github.com/Scalingo/go-utils/errors/v3/cause.go index 1ab64725..37925c9b 100644 --- a/vendor/github.com/Scalingo/go-utils/errors/v3/cause.go +++ b/vendor/github.com/Scalingo/go-utils/errors/v3/cause.go @@ -7,7 +7,7 @@ import ( ) // Is checks if any error of the stack matches the error value expectedError -// API machting the standard library but allowing to wrap errors with ErrCtx + errgo or pkg/errors +// API matching the standard library but allowing to wrap errors with ErrCtx + errgo or pkg/errors func Is(receivedErr, expectedError error) bool { if errors.Is(receivedErr, expectedError) { return true @@ -22,7 +22,7 @@ func Is(receivedErr, expectedError error) bool { } // As checks if any error of the stack matches the expectedType -// API machting the standard library but allowing to wrap errors with ErrCtx + errgo or pkg/errors +// API matching the standard library but allowing to wrap errors with ErrCtx + errgo or pkg/errors func As(receivedErr error, expectedType any) bool { if errors.As(receivedErr, expectedType) { return true diff --git a/vendor/github.com/Scalingo/go-utils/etcd/CHANGELOG.md b/vendor/github.com/Scalingo/go-utils/etcd/CHANGELOG.md index 1b7f2f2c..54b70515 100644 --- a/vendor/github.com/Scalingo/go-utils/etcd/CHANGELOG.md +++ b/vendor/github.com/Scalingo/go-utils/etcd/CHANGELOG.md @@ -2,6 +2,12 @@ ## To be Released +## v1.2.2 + +* chore(go): upgrade to Go 1.25.0 +* build(deps): bump etcd client packages from 3.6.0 to 3.6.10 +* build(deps): update indirect dependencies, including `google.golang.org/grpc` to 1.80.0 + ## v1.2.1 * chore(go): corrective bump - Go version regression from 1.24.3 to 1.24 diff --git a/vendor/github.com/Scalingo/go-utils/etcd/README.md b/vendor/github.com/Scalingo/go-utils/etcd/README.md index 953b2d4c..dd1f5c82 100644 --- a/vendor/github.com/Scalingo/go-utils/etcd/README.md +++ b/vendor/github.com/Scalingo/go-utils/etcd/README.md @@ -1,3 +1,3 @@ -# Package `etcd` v1.2.1 +# Package `etcd` v1.2.2 The package `etcd` contains a builder for an etcd client. diff --git a/vendor/github.com/Scalingo/go-utils/logger/CHANGELOG.md b/vendor/github.com/Scalingo/go-utils/logger/CHANGELOG.md index f11ffedf..20581f03 100644 --- a/vendor/github.com/Scalingo/go-utils/logger/CHANGELOG.md +++ b/vendor/github.com/Scalingo/go-utils/logger/CHANGELOG.md @@ -2,6 +2,10 @@ ## To be Released +## v1.12.2 + +* refactor: replace `github.com/pkg/errors` with `errors` + ## v1.12.1 * chore(deps): bump github.com/Scalingo/logrus-rollbar from 1.4.3 to 1.4.4 diff --git a/vendor/github.com/Scalingo/go-utils/logger/README.md b/vendor/github.com/Scalingo/go-utils/logger/README.md index 3cb2226b..e95726a6 100644 --- a/vendor/github.com/Scalingo/go-utils/logger/README.md +++ b/vendor/github.com/Scalingo/go-utils/logger/README.md @@ -1,4 +1,4 @@ -# Package `logger` v1.12.1 +# Package `logger` v1.12.2 This package will provide you a generic way to handle logging. diff --git a/vendor/github.com/Scalingo/go-utils/logger/redacting_formatter.go b/vendor/github.com/Scalingo/go-utils/logger/redacting_formatter.go index 44c35133..0d5072a4 100644 --- a/vendor/github.com/Scalingo/go-utils/logger/redacting_formatter.go +++ b/vendor/github.com/Scalingo/go-utils/logger/redacting_formatter.go @@ -1,9 +1,9 @@ package logger import ( + "errors" "regexp" - "github.com/pkg/errors" "github.com/sirupsen/logrus" ) diff --git a/vendor/github.com/Scalingo/go-utils/retry/CHANGELOG.md b/vendor/github.com/Scalingo/go-utils/retry/CHANGELOG.md index 0c86b05d..2e3cf7fd 100644 --- a/vendor/github.com/Scalingo/go-utils/retry/CHANGELOG.md +++ b/vendor/github.com/Scalingo/go-utils/retry/CHANGELOG.md @@ -2,6 +2,10 @@ ## To be Released +## v1.4.1 + +* chore(deps): bump multiple dependencies + ## v1.4.0 * feat(retry): add exponential backoff wait duration diff --git a/vendor/github.com/Scalingo/go-utils/retry/README.md b/vendor/github.com/Scalingo/go-utils/retry/README.md index 52aea503..477f9049 100644 --- a/vendor/github.com/Scalingo/go-utils/retry/README.md +++ b/vendor/github.com/Scalingo/go-utils/retry/README.md @@ -1,4 +1,4 @@ -# Package `retry` v1.4.0 +# Package `retry` v1.4.1 This library implements a retryer: a generic way to execute some code at regular interval. diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options/BUILD.bazel b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options/BUILD.bazel index d71991e6..58bdc765 100644 --- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options/BUILD.bazel +++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options/BUILD.bazel @@ -1,6 +1,6 @@ +load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") package(default_visibility = ["//visibility:public"]) diff --git a/vendor/github.com/mattn/go-isatty/isatty_others.go b/vendor/github.com/mattn/go-isatty/isatty_others.go index 7402e061..b24a2fad 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_others.go +++ b/vendor/github.com/mattn/go-isatty/isatty_others.go @@ -1,5 +1,5 @@ -//go:build (appengine || js || nacl || tinygo || wasm) && !windows -// +build appengine js nacl tinygo wasm +//go:build (appengine || js || nacl || tinygo || wasm || wasip1 || wasip2) && !windows +// +build appengine js nacl tinygo wasm wasip1 wasip2 // +build !windows package isatty diff --git a/vendor/github.com/mattn/go-isatty/isatty_windows.go b/vendor/github.com/mattn/go-isatty/isatty_windows.go index 8e3c9917..5f29c11d 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_windows.go +++ b/vendor/github.com/mattn/go-isatty/isatty_windows.go @@ -31,6 +31,10 @@ func init() { if procGetFileInformationByHandleEx.Find() != nil { procGetFileInformationByHandleEx = nil } + // Check if NtQueryObject is available. + if procNtQueryObject.Find() != nil { + procNtQueryObject = nil + } } // IsTerminal return true if the file descriptor is terminal. @@ -43,6 +47,7 @@ func IsTerminal(fd uintptr) bool { // Check pipe name is used for cygwin/msys2 pty. // Cygwin/MSYS2 PTY has a name like: // \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master +// On Windows 7 a trailing suffix (e.g. "-nat") may be appended. func isCygwinPipeName(name string) bool { token := strings.Split(name, "-") if len(token) < 5 { @@ -72,13 +77,19 @@ func isCygwinPipeName(name string) bool { return false } + for _, t := range token[5:] { + if t == "" { + return false + } + } + return true } -// getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler +// getFileNameByHandle use the undocumented ntdll NtQueryObject to get file full name from file handler // since GetFileInformationByHandleEx is not available under windows Vista and still some old fashion // guys are using Windows XP, this is a workaround for those guys, it will also work on system from -// Windows vista to 10 +// Windows Vista to 10 // see https://stackoverflow.com/a/18792477 for details func getFileNameByHandle(fd uintptr) (string, error) { if procNtQueryObject == nil { diff --git a/vendor/github.com/mattn/go-runewidth/runewidth.go b/vendor/github.com/mattn/go-runewidth/runewidth.go index a8c9c1fb..f6c00582 100644 --- a/vendor/github.com/mattn/go-runewidth/runewidth.go +++ b/vendor/github.com/mattn/go-runewidth/runewidth.go @@ -3,6 +3,7 @@ package runewidth import ( "os" "strings" + "unicode/utf8" "github.com/clipperhouse/uax29/v2/graphemes" ) @@ -23,10 +24,48 @@ var ( } ) +var ( + zerowidth table // combining + nonprint merged for faster zero-width lookup + widewidth table // ambiguous + doublewidth merged for EA path +) + func init() { + zerowidth = mergeIntervals(combining, nonprint) + widewidth = mergeIntervals(ambiguous, doublewidth) handleEnv() } +func mergeIntervals(t1, t2 table) table { + merged := make(table, 0, len(t1)+len(t2)) + i, j := 0, 0 + for i < len(t1) && j < len(t2) { + if t1[i].first <= t2[j].first { + merged = append(merged, t1[i]) + i++ + } else { + merged = append(merged, t2[j]) + j++ + } + } + merged = append(merged, t1[i:]...) + merged = append(merged, t2[j:]...) + if len(merged) == 0 { + return merged + } + result := merged[:1] + for _, iv := range merged[1:] { + last := &result[len(result)-1] + if iv.first <= last.last+1 { + if iv.last > last.last { + last.last = iv.last + } + } else { + result = append(result, iv) + } + } + return result +} + func handleEnv() { env := os.Getenv("RUNEWIDTH_EASTASIAN") if env == "" { @@ -51,15 +90,6 @@ type interval struct { type table []interval -func inTables(r rune, ts ...table) bool { - for _, t := range ts { - if inTable(r, t) { - return true - } - } - return false -} - func inTable(r rune, t table) bool { if r < t[0].first { return false @@ -130,9 +160,7 @@ func (c *Condition) RuneWidth(r rune) int { return 0 case r < 0x300: return 1 - case inTable(r, narrow): - return 1 - case inTables(r, nonprint, combining): + case inTable(r, zerowidth): return 0 case inTable(r, doublewidth): return 2 @@ -141,13 +169,13 @@ func (c *Condition) RuneWidth(r rune) int { } } else { switch { - case inTables(r, nonprint, combining): + case inTable(r, zerowidth): return 0 case inTable(r, narrow): return 1 - case inTables(r, ambiguous, doublewidth): + case inTable(r, widewidth): return 2 - case !c.StrictEmojiNeutral && inTables(r, ambiguous, emoji, narrow): + case !c.StrictEmojiNeutral && inTable(r, emoji): return 2 default: return 1 @@ -178,6 +206,22 @@ func (c *Condition) CreateLUT() { // StringWidth return width as you can see func (c *Condition) StringWidth(s string) (width int) { + if len(s) > 0 && len(s) <= utf8.UTFMax { + r, size := utf8.DecodeRuneInString(s) + if size == len(s) { + return c.RuneWidth(r) + } + } + // ASCII fast path: no grapheme clustering needed for pure ASCII + if isAllASCII(s) { + for i := 0; i < len(s); i++ { + b := s[i] + if b >= 0x20 && b != 0x7F { + width++ + } + } + return + } g := graphemes.FromString(s) for g.Next() { var chWidth int @@ -192,6 +236,15 @@ func (c *Condition) StringWidth(s string) (width int) { return } +func isAllASCII(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] >= 0x80 { + return false + } + } + return true +} + // Truncate return string truncated with w cells func (c *Condition) Truncate(s string, w int, tail string) string { if c.StringWidth(s) <= w { @@ -257,24 +310,25 @@ func (c *Condition) TruncateLeft(s string, w int, prefix string) string { // Wrap return string wrapped with w cells func (c *Condition) Wrap(s string, w int) string { width := 0 - out := "" + var out strings.Builder + out.Grow(len(s) + len(s)/w + 1) for _, r := range s { cw := c.RuneWidth(r) if r == '\n' { - out += string(r) + out.WriteRune(r) width = 0 continue } else if width+cw > w { - out += "\n" + out.WriteByte('\n') width = 0 - out += string(r) + out.WriteRune(r) width += cw continue } - out += string(r) + out.WriteRune(r) width += cw } - return out + return out.String() } // FillLeft return string filled in left by spaces in w cells @@ -313,7 +367,7 @@ func RuneWidth(r rune) int { // IsAmbiguousWidth returns whether is ambiguous width or not. func IsAmbiguousWidth(r rune) bool { - return inTables(r, private, ambiguous) + return inTable(r, private) || inTable(r, ambiguous) } // IsCombiningWidth returns whether is combining width or not. diff --git a/vendor/github.com/olekukonko/errors/README.md b/vendor/github.com/olekukonko/errors/README.md index 8830486e..a2a42e66 100644 --- a/vendor/github.com/olekukonko/errors/README.md +++ b/vendor/github.com/olekukonko/errors/README.md @@ -1,39 +1,40 @@ -# Enhanced Error Handling for Go with Context, Stack Traces, Monitoring, and More +# errors — production-grade error handling for Go [![Go Reference](https://pkg.go.dev/badge/github.com/olekukonko/errors.svg)](https://pkg.go.dev/github.com/olekukonko/errors) [![Go Report Card](https://goreportcard.com/badge/github.com/olekukonko/errors)](https://goreportcard.com/report/github.com/olekukonko/errors) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -[![Benchmarks](https://img.shields.io/badge/benchmarks-included-success)](README.md#benchmarks) - -A production-grade error handling library for Go, offering zero-cost abstractions, stack traces, multi-error support, retries, and advanced monitoring through two complementary packages: `errors` (core) and `errmgr` (management). - -## Features - -### `errors` Package (Core) -- **Performance Optimized** - - Optional memory pooling (12 ns/op with pooling) - - Lazy stack trace collection (205 ns/op with stack) - - Small context optimization (≤4 items, 40 ns/op) - - Lock-free configuration reads - -- **Debugging Tools** - - Full stack traces with internal frame filtering - - Error wrapping and chaining - - Structured context attachment - - JSON serialization (662 ns/op) - -- **Advanced Utilities** - - Configurable retry mechanism - - Multi-error aggregation with sampling - - HTTP status code support - - Callback triggers for cleanup or side effects - -### `errmgr` Package (Management) -- **Production Monitoring** - - Error occurrence counting - - Threshold-based alerting - - Categorized metrics - - Predefined error templates +[![Go 1.21+](https://img.shields.io/badge/go-1.21+-blue.svg)](https://golang.org/dl/) + +A feature-complete error handling library for Go. Fully compatible with `errors.Is`, `errors.As`, and `errors.Unwrap`. Optimised for high-throughput systems with object pooling, hybrid context storage, and inlining-immune stack capture. + +--- + +## Contents + +- [Installation](#installation) +- [Package overview](#package-overview) +- [Core — `errors`](#core--errors) + - [Creating errors](#creating-errors) + - [Stack traces](#stack-traces) + - [Context](#context) + - [Wrapping and chaining](#wrapping-and-chaining) + - [Sentinel errors](#sentinel-errors) + - [Type assertions — Is / As](#type-assertions--is--as) + - [Multi-error aggregation](#multi-error-aggregation) + - [Retry](#retry) + - [Chain execution](#chain-execution) + - [Channel utilities and streaming](#channel-utilities-and-streaming) + - [HTTP helpers](#http-helpers) + - [Concurrent group](#concurrent-group) + - [Inspect](#inspect) + - [slog integration](#slog-integration) + - [Pool management](#pool-management) +- [Management — `errmgr`](#management--errmgr) +- [Performance](#performance) +- [Migration guide](#migration-guide) +- [FAQ](#faq) + +--- ## Installation @@ -41,1525 +42,572 @@ A production-grade error handling library for Go, offering zero-cost abstraction go get github.com/olekukonko/errors@latest ``` -## Package Overview - -- **`errors`**: Core error handling with creation, wrapping, context, stack traces, retries, and multi-error support. -- **`errmgr`**: Error management with templates, monitoring, and predefined errors for consistent application use. +Requires Go 1.21 or later. --- -> [!NOTE] -> ✓ added support for `errors.Errorf("user %w not found", errors.New("bob"))` -> ✓ added support for `sequential chain` execution -`` - -## Using the `errors` Package +## Package overview -### Basic Error Creation +| Package | Purpose | +|---|---| +| `errors` | Core error type, wrapping, context, stack traces, retry, chain, multi-error, channel utilities | +| `errmgr` | Parameterised error templates, occurrence monitoring, threshold alerting | -#### Simple Error -```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" -) +--- -func main() { - // Fast error with no stack trace - err := errors.New("connection failed") - fmt.Println(err) // "connection failed" +## Core — `errors` - // Standard error, no allocation, same speed - stdErr := errors.Std("connection failed") - fmt.Println(stdErr) // "connection failed" -} -``` +### Creating errors -#### Formatted Error ```go -// main.go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" -) +// Fast — no stack trace, 0 allocations with pooling +err := errors.New("connection failed") -func main() { - // Formatted error without stack trace - errNoWrap := errors.Newf("user %s not found", "bob") - fmt.Println(errNoWrap) // Output: "user bob not found" +// Formatted — full fmt verb support including %w +err := errors.Newf("user %s not found", "alice") +err := errors.Errorf("query failed: %w", cause) // alias of Newf - // Standard formatted error, no fmt.Errorf needed (using own pkg) - stdErrNoWrap := errors.Stdf("user %s not found", "bob") - fmt.Println(stdErrNoWrap) // Output: "user bob not found" +// With stack trace +err := errors.Trace("critical issue") +err := errors.Tracef("query %s failed: %w", query, cause) - // Added support for %w (compatible with fmt.Errorf output) - // errors.Errorf is alias of errors.Newf - errWrap := errors.Errorf("user %w not found", errors.New("bob")) - fmt.Println(errWrap) // Output: "user bob not found" +// Named — useful for sentinel-style matching +err := errors.Named("AuthError") - // Standard formatted error for comparison - stdErrWrap := fmt.Errorf("user %w not found", fmt.Errorf("bob")) - fmt.Println(stdErrWrap) // Output: "user bob not found" -} +// Standard library compatible +err := errors.Std("connection failed") // returns plain error +err := errors.Stdf("error %s", "detail") // formatted plain error ``` -#### Error with Stack Trace -```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" -) - -func main() { - // Create an error with stack trace using Trace - err := errors.Trace("critical issue") - fmt.Println(err) // Output: "critical issue" - fmt.Println(err.Stack()) // Output: e.g., ["main.go:15", "caller.go:42"] - - // Convert basic error to traceable with WithStack - errS := errors.New("critical issue") - errS = errS.WithStack() // Add stack trace and update error - fmt.Println(errS) // Output: "critical issue" - fmt.Println(errS.Stack()) // Output: e.g., ["main.go:19", "caller.go:42"] -} -``` +### Stack traces -#### Named Error ```go -package main +// Capture at creation +err := errors.Trace("critical issue") -import ( - "fmt" - "github.com/olekukonko/errors" -) +// Add to an existing error +err = err.WithStack() -func main() { - // Create a named error with stack trace - err := errors.Named("InputError") - fmt.Println(err.Name()) // Output: "InputError" - fmt.Println(err) // Output: "InputError" +// Read frames +for _, frame := range err.Stack() { + fmt.Println(frame) // "main.go:42 main.main" } -``` - -### Adding Context - -#### Basic Context -```go -package main -import ( - "fmt" - "github.com/olekukonko/errors" -) - -func main() { - // Create an error with context - err := errors.New("processing failed"). - With("id", "123"). - With("attempt", 3). - With("retryable", true) - fmt.Println("Error:", err) // Output: "processing failed" - fmt.Println("Full context:", errors.Context(err)) // Output: map[id:123 attempt:3 retryable:true] +// Lightweight version (file:line only, no function names) +for _, frame := range err.FastStack() { + fmt.Println(frame) } ``` -#### Context with Wrapped Standard Error -```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" -) +Stack capture is immune to compiler inlining — frames are collected from +the physical call stack and trimmed by slice arithmetic, not by skip count. -func main() { - // Wrap a standard error and add context - err := errors.New("processing failed"). - With("id", "123") - wrapped := fmt.Errorf("wrapped: %w", err) - fmt.Println("Wrapped error:", wrapped) // Output: "wrapped: processing failed" - fmt.Println("Direct context:", errors.Context(wrapped)) // Output: nil - - // Convert to access context - e := errors.Convert(wrapped) - fmt.Println("Converted context:", e.Context()) // Output: map[id:123] -} -``` +### Context -#### Adding Context to Standard Error ```go -package main +err := errors.New("processing failed"). + With("user_id", "123"). + With("attempt", 3). + With("retryable", true) -import ( - "fmt" - "github.com/olekukonko/errors" -) - -func main() { - // Convert a standard error and add context - stdErr := fmt.Errorf("standard error") - converted := errors.Convert(stdErr). - With("source", "legacy"). - With("severity", "high") - fmt.Println("Message:", converted.Error()) // Output: "standard error" - fmt.Println("Context:", converted.Context()) // Output: map[source:legacy severity:high] -} -``` +// Read back +ctx := errors.Context(err) // map[user_id:123 attempt:3 retryable:true] -#### Complex Context -```go -package main +// Check for a key +if err.HasContextKey("user_id") { ... } -import ( - "fmt" - "github.com/olekukonko/errors" -) +// Variadic bulk attach +err.With("k1", v1, "k2", v2) -func main() { - // Create an error with complex context - err := errors.New("database operation failed"). - With("query", "SELECT * FROM users"). - With("params", map[string]interface{}{ - "limit": 100, - "offset": 0, - }). - With("duration_ms", 45.2) - fmt.Println("Complex error context:") - for k, v := range errors.Context(err) { - fmt.Printf("%s: %v (%T)\n", k, v, v) - } - // Output: - // query: SELECT * FROM users (string) - // params: map[limit:100 offset:0] (map[string]interface {}) - // duration_ms: 45.2 (float64) -} +// Semantic helpers +err.WithCode(500) +err.WithCategory("network") +err.WithTimeout() +err.WithRetryable() ``` -### Stack Traces +The first four context items are stored in a fixed-size array (no allocation). +Items beyond four spill to a map. -#### Adding Stack to Any Error -```go -package main +### Wrapping and chaining -import ( - "fmt" - "github.com/olekukonko/errors" -) +```go +lowErr := errors.New("connection timeout").With("server", "db01") +bizErr := errors.New("failed to load user").Wrap(lowErr) +apiErr := errors.Wrapf(bizErr, "request failed: %w", bizErr) -func main() { - // Add stack trace to a standard error - err := fmt.Errorf("basic error") - enhanced := errors.WithStack(err) - fmt.Println("Error with stack:") - fmt.Println("Message:", enhanced.Error()) // Output: "basic error" - fmt.Println("Stack:", enhanced.Stack()) // Output: e.g., "main.go:15" +// Traverse +for i, e := range errors.UnwrapAll(apiErr) { + fmt.Printf("%d. %s\n", i+1, e) } +// 1. request failed: ... +// 2. failed to load user +// 3. connection timeout ``` -#### Chaining with Stack -```go -package main +### Sentinel errors -import ( - "fmt" - "github.com/olekukonko/errors" - "time" -) +`Const` creates a stable, pointer-comparable sentinel safe for package-level variables. -func main() { - // Create an enhanced error and add stack/context - err := errors.New("validation error"). - With("field", "email") - stackErr := errors.WithStack(err). - With("timestamp", time.Now()). - WithCode(500) - fmt.Println("Message:", stackErr.Error()) // Output: "validation error" - fmt.Println("Context:", stackErr.Context()) // Output: map[field:email timestamp:...] - fmt.Println("Stack:") - for _, frame := range stackErr.Stack() { - fmt.Println(frame) - } -} -``` -### Stack Traces with `WithStack()` ```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" - "math/rand" - "time" +var ( + ErrNotFound = errors.Const("not_found", "resource not found") + ErrForbidden = errors.Const("forbidden", "access denied") ) -func basicFunc() error { - return fmt.Errorf("basic error") -} - -func enhancedFunc() *errors.Error { - return errors.New("enhanced error") -} +// Match anywhere in a chain +if errors.Is(err, ErrNotFound) { ... } -func main() { - // 1. Package-level WithStack - works with ANY error type - err1 := basicFunc() - enhanced1 := errors.WithStack(err1) // Handles basic errors - fmt.Println("Package-level WithStack:") - fmt.Println(enhanced1.Stack()) - - // 2. Method-style WithStack - only for *errors.Error - err2 := enhancedFunc() - enhanced2 := err2.WithStack() // More natural chaining - fmt.Println("\nMethod-style WithStack:") - fmt.Println(enhanced2.Stack()) - - // 3. Combined usage in real-world scenario - result := processData() - if result != nil { - // Use package-level when type is unknown - stackErr := errors.WithStack(result) - - // Then use method-style for chaining - finalErr := stackErr. - With("timestamp", time.Now()). - WithCode(500) - - fmt.Println("\nCombined Usage:") - fmt.Println("Message:", finalErr.Error()) - fmt.Println("Context:", finalErr.Context()) - fmt.Println("Stack:") - for _, frame := range finalErr.Stack() { - fmt.Println(frame) - } - } -} +// Add call-site context without losing the sentinel +err := ErrNotFound.With("user 42 not found") +errors.Is(err, ErrNotFound) // true — sentinel is the cause -func processData() error { - // Could return either basic or enhanced error - if rand.Intn(2) == 0 { - return fmt.Errorf("database error") - } - return errors.New("validation error").With("field", "email") -} +// JSON and slog work automatically +b, _ := json.Marshal(ErrNotFound) // {"error":"resource not found","code":"not_found"} +slog.Error("lookup failed", "err", ErrNotFound) ``` -### Error Wrapping and Chaining +> **`Const` vs `errmgr.Define`** +> `errors.Const` — static comparable value for `errors.Is` matching. +> `errmgr.Define` — parameterised factory that creates new `*Error` instances from a format template. -#### Basic Wrapping -```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" -) +### Type assertions — Is / As -func main() { - // Wrap an error with additional context - lowErr := errors.New("low-level failure") - highErr := errors.Wrapf(lowErr, "high-level operation failed: %s", "details") - fmt.Println(highErr) // Output: "high-level operation failed: details: low-level failure" - fmt.Println(errors.Unwrap(highErr)) // Output: "low-level failure" -} -``` - -#### Walking Error Chain ```go -package main +// Is — checks identity or name match +err := errors.Named("AuthError") +wrapped := errors.Wrapf(err, "login failed") +errors.Is(wrapped, err) // true -import ( - "fmt" - "github.com/olekukonko/errors" -) - -func main() { - // Create a chained error - dbErr := errors.New("connection timeout"). - With("server", "db01.prod") - bizErr := errors.New("failed to process user 12345"). - With("user_id", "12345"). - Wrap(dbErr) - apiErr := errors.New("API request failed"). - WithCode(500). - Wrap(bizErr) - - // Walk the error chain - fmt.Println("Error Chain:") - for i, e := range errors.UnwrapAll(apiErr) { - fmt.Printf("%d. %s\n", i+1, e) - } - // Output: - // 1. API request failed - // 2. failed to process user 12345 - // 3. connection timeout +// As — extract the first matching *Error from the chain +var target *errors.Error +if errors.As(wrapped, &target) { + fmt.Println(target.Name()) // "AuthError" } -``` -### Type Assertions - -#### Using Is -```go -package main +// Generic helpers (Go 1.18+) +if e, ok := errors.AsType[*MyError](err); ok { ... } +if errors.IsType[*MyError](err) { ... } -import ( - "fmt" - "github.com/olekukonko/errors" -) +found, ok := errors.FindType(err, func(e *MyError) bool { + return e.Code() == 404 +}) -func main() { - // Check error type with Is - err := errors.Named("AuthError") - wrapped := errors.Wrapf(err, "login failed") - if errors.Is(wrapped, err) { - fmt.Println("Is an AuthError") // Output: "Is an AuthError" - } -} +codes := errors.Map(err, func(e *MyError) int { return e.Code() }) +errors.Filter[*MyError](err) // [] *MyError from chain +errors.FirstOfType[*MyError](err) // first *MyError ``` -#### Using As -```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" -) - -func main() { - // Extract error type with As - err := errors.Named("AuthError") - wrapped := errors.Wrapf(err, "login failed") - var authErr *errors.Error - if wrapped.As(&authErr) { - fmt.Println("Extracted:", authErr.Name()) // Output: "Extracted: AuthError" - } -} -``` +> **`Is()` string-equality note** — `(*Error).Is` falls back to string comparison as a convenience for matching stdlib errors by message. For strict identity matching use `Const()`. -### Retry Mechanism +### Multi-error aggregation -#### Basic Retry ```go -package main +// Basic +m := errors.NewMultiError() +m.Add(errors.New("name required")) +m.Add(errors.New("email invalid")) +fmt.Println(m.Count()) // 2 -import ( - "fmt" - "github.com/olekukonko/errors" - "math/rand" - "time" +// With limits and sampling +m := errors.NewMultiError( + errors.WithLimit(100), + errors.WithSampling(10), // 10% sample rate ) -func main() { - // Simulate a flaky operation - attempts := 0 - retry := errors.NewRetry( - errors.WithMaxAttempts(3), - errors.WithDelay(100*time.Millisecond), - ) - err := retry.Execute(func() error { - attempts++ - if rand.Intn(2) == 0 { - return errors.New("temporary failure").WithRetryable() - } - return nil - }) - if err != nil { - fmt.Printf("Failed after %d attempts: %v\n", attempts, err) - } else { - fmt.Printf("Succeeded after %d attempts\n", attempts) - } -} +// Custom formatter +m := errors.NewMultiError( + errors.WithFormatter(func(errs []error) string { + return fmt.Sprintf("%d errors", len(errs)) + }), +) -``` +// Inspect +m.First() // first error +m.Last() // last error +m.Errors() // []error snapshot +m.Has() // bool +m.Single() // nil | first error | *MultiError -#### Retry with Context Timeout -```go -package main +// Filter +networkErrs := m.Filter(func(e error) bool { + return strings.Contains(e.Error(), "network") +}) -import ( - "context" - "fmt" - "github.com/olekukonko/errors" - "time" -) +// Merge two MultiErrors +m.Merge(other) -func main() { - // Retry with context timeout - ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) - defer cancel() - retry := errors.NewRetry( - errors.WithContext(ctx), - errors.WithMaxAttempts(5), - errors.WithDelay(200*time.Millisecond), - ) - err := retry.Execute(func() error { - return errors.New("operation failed").WithRetryable() - }) - if errors.Is(err, context.DeadlineExceeded) { - fmt.Println("Operation timed out:", err) - } else if err != nil { - fmt.Println("Operation failed:", err) - } -} +// Join is a convenience that collapses errors to *MultiError or nil +err := errors.Join(err1, err2, err3) ``` - -### Retry Comprehensive +### Retry ```go -package main - -import ( - "context" - "fmt" - "github.com/olekukonko/errors" - "math/rand" - "time" -) - -// DatabaseClient simulates a flaky database connection -type DatabaseClient struct { - healthyAfterAttempt int -} - -func (db *DatabaseClient) Query() error { - if db.healthyAfterAttempt > 0 { - db.healthyAfterAttempt-- - return errors.New("database connection failed"). - With("attempt_remaining", db.healthyAfterAttempt). - WithRetryable() // Mark as retryable - } - return nil -} - -// ExternalService simulates an unreliable external API -func ExternalService() error { - if rand.Intn(100) < 30 { // 30% failure rate - return errors.New("service unavailable"). - WithCode(503). - WithRetryable() - } - return nil -} - -func main() { - // Configure retry with exponential backoff and jitter - retry := errors.NewRetry( +retry := errors.NewRetry( errors.WithMaxAttempts(5), errors.WithDelay(200*time.Millisecond), errors.WithMaxDelay(2*time.Second), errors.WithJitter(true), errors.WithBackoff(errors.ExponentialBackoff{}), + errors.WithRetryIf(errors.IsRetryable), errors.WithOnRetry(func(attempt int, err error) { - // Calculate delay using the same logic as in Execute - baseDelay := 200 * time.Millisecond - maxDelay := 2 * time.Second - delay := errors.ExponentialBackoff{}.Backoff(attempt, baseDelay) - if delay > maxDelay { - delay = maxDelay - } - fmt.Printf("Attempt %d failed: %v (retrying in %v)\n", - attempt, - err.Error(), - delay) + log.Printf("attempt %d: %v", attempt, err) }), - ) - - // Scenario 1: Database connection with known recovery point - db := &DatabaseClient{healthyAfterAttempt: 3} - fmt.Println("Starting database operation...") - err := retry.Execute(func() error { - return db.Query() - }) - if err != nil { - fmt.Printf("Database operation failed after %d attempts: %v\n", retry.Attempts(), err) - } else { - fmt.Println("Database operation succeeded!") - } - - // Scenario 2: External service with random failures - fmt.Println("\nStarting external service call...") - var lastAttempts int - start := time.Now() - - // Using ExecuteReply to demonstrate return values - result, err := errors.ExecuteReply[string](retry, func() (string, error) { - lastAttempts++ - if err := ExternalService(); err != nil { - return "", err - } - return "service response data", nil - }) - - duration := time.Since(start) - - if err != nil { - fmt.Printf("Service call failed after %d attempts (%.2f sec): %v\n", - lastAttempts, - duration.Seconds(), - err) - } else { - fmt.Printf("Service call succeeded after %d attempts (%.2f sec): %s\n", - lastAttempts, - duration.Seconds(), - result) - } - - // Scenario 3: Context cancellation with more visibility - fmt.Println("\nStarting operation with timeout...") - ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) - defer cancel() - - timeoutRetry := retry.Transform( - errors.WithContext(ctx), - errors.WithMaxAttempts(10), - errors.WithOnRetry(func(attempt int, err error) { - fmt.Printf("Timeout scenario attempt %d: %v\n", attempt, err) - }), - ) - - startTimeout := time.Now() - err = timeoutRetry.Execute(func() error { - time.Sleep(300 * time.Millisecond) // Simulate long operation - return errors.New("operation timed out") - }) - - if errors.Is(err, context.DeadlineExceeded) { - fmt.Printf("Operation cancelled by timeout after %.2f sec: %v\n", - time.Since(startTimeout).Seconds(), - err) - } else if err != nil { - fmt.Printf("Operation failed: %v\n", err) - } else { - fmt.Println("Operation succeeded (unexpected)") - } -} -``` - -### Multi-Error Aggregation - -#### Form Validation -```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" ) -func main() { - // Validate a form with multiple errors - multi := errors.NewMultiError() - multi.Add(errors.New("name is required")) - multi.Add(errors.New("email is invalid")) - multi.Add(errors.New("password too short")) - if multi.Has() { - fmt.Println(multi) // Output: "errors(3): name is required; email is invalid; password too short" - fmt.Printf("Total errors: %d\n", multi.Count()) - } -} -``` +err := retry.Execute(func() error { + return callExternalService() +}) -#### Sampling Multi-Errors -```go -package main +// Generic version — preserves return value +result, err := errors.ExecuteReply[string](retry, func() (string, error) { + return fetchData() +}) -import ( - "fmt" - "github.com/olekukonko/errors" -) +// Context-aware +ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) +defer cancel() +retry2 := retry.Transform(errors.WithContext(ctx)) +err = retry2.Execute(fn) -func main() { - // Simulate many errors with sampling - multi := errors.NewMultiError( - errors.WithSampling(10), // 10% sampling - errors.WithLimit(5), - ) - for i := 0; i < 100; i++ { - multi.Add(errors.Newf("error %d", i)) - } - fmt.Println(multi) - fmt.Printf("Captured %d out of 100 errors\n", multi.Count()) -} +// Backoff strategies +errors.ConstantBackoff{} +errors.LinearBackoff{} +errors.ExponentialBackoff{} ``` -### Additional Examples - -#### Using Callbacks -```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" -) +### Chain execution -func main() { - // Add a callback to an error - err := errors.New("transaction failed"). - Callback(func() { - fmt.Println("Reversing transaction...") - }) - fmt.Println(err) // Output: "transaction failed" + "Reversing transaction..." - err.Free() -} -``` +Sequential steps with per-step retry, timeout, tagging, and optional steps. -#### Copying Errors ```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" -) +chain := errors.NewChain( + errors.ChainWithTimeout(10*time.Second), + errors.ChainWithLogHandler(slog.Default().Handler()), +). + Step(validateInput).Tag("validation"). + Step(verifyKYC).Tag("kyc"). + Step(processPayment).Tag("billing").Code(402). + Retry(3, 100*time.Millisecond, errors.WithRetryIf(errors.IsRetryable)). + Step(sendNotification).Tag("notification").Optional() -func main() { - // Copy an error and modify the copy - original := errors.New("base error").With("key", "value") - copied := original.Copy().With("extra", "data") - fmt.Println("Original:", original, original.Context()) // Output: "base error" map[key:value] - fmt.Println("Copied:", copied, copied.Context()) // Output: "base error" map[key:value extra:data] +if err := chain.Run(); err != nil { + errors.Inspect(err, os.Stderr) } -``` - -#### Transforming Errors -```go -package main -import ( - "fmt" - "github.com/olekukonko/errors" -) - -func main() { - // Transform an error with additional context - err := errors.New("base error") - transformed := errors.Transform(err, func(e *errors.Error) { - e.With("env", "prod"). - WithCode(500). - WithStack() - }) - fmt.Println(transformed.Error()) // Output: "base error" - fmt.Println(transformed.Context()) // Output: map[env:prod] - fmt.Println(transformed.Code()) // Output: 500 - fmt.Println(len(transformed.Stack()) > 0) // Output: true - transformed.Free() +// Run all steps, collect every error +if err := chain.RunAll(); err != nil { + errors.Inspect(err, os.Stderr) } ``` -### Transformation and Enrichment +`StepCtx` passes the chain-level context (with its deadline) to the step, so +blocking calls like HTTP or database queries respect the chain timeout: ```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" -) +chain.StepCtx(func(ctx context.Context) error { + req, _ := http.NewRequestWithContext(ctx, "GET", url, nil) + _, err := http.DefaultClient.Do(req) + return err +}) +``` -func process() error { - return errors.New("base error") -} +### Channel utilities and streaming -func main() { - err := process() - transformedErr := errors.Transform(err, func(e *errors.Error) { - e.With("env", "prod"). - WithCode(500). - WithStack() - }) - - // No type assertion needed now - fmt.Println(transformedErr.Error()) // "base error" - fmt.Println(transformedErr.Context()) // map[env:prod] - fmt.Println(transformedErr.Code()) // 500 - fmt.Println(len(transformedErr.Stack()) > 0) // true - transformedErr.Free() // Clean up - - stdErr := process() - convertedErr := errors.Convert(stdErr) // Convert standard error to *Error - convertedErr.With("source", "external"). - WithCode(400). - Callback(func() { - fmt.Println("Converted error processed...") - }) - fmt.Println("Converted Error:", convertedErr.Error()) - fmt.Println("Context:", convertedErr.Context()) - fmt.Println("Code:", convertedErr.Code()) - convertedErr.Free() +#### `<-chan error` utilities -} +These compose with the standard Go `(chan T, chan error)` idiom rather than replacing it. -``` - -#### Fast Stack Trace ```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" -) +// Drain — block until channel closes, collect into *MultiError +err := errors.Drain(errs) -func main() { - // Get a lightweight stack trace - err := errors.Trace("lightweight error") - fastStack := err.FastStack() - fmt.Println("Fast Stack:") - for _, frame := range fastStack { - fmt.Println(frame) // Output: e.g., "main.go:15" - } +// First — return first non-nil error; ctx for deadline only, caller owns cancel +err := errors.First(ctx, errs) +if err != nil { + cancel() // caller decides to stop siblings } -``` - -#### WarmStackPool -```go -package main -import ( - "fmt" - "github.com/olekukonko/errors" -) +// Collect — bounded sample; wraps ErrLimitReached when n is hit +err := errors.Collect(ctx, errs, 10) +if errors.Is(err, errors.ErrLimitReached) { + log.Warn("more than 10 errors — some dropped") +} -func main() { - // Pre-warm the stack pool - errors.WarmStackPool(10) - err := errors.Trace("pre-warmed error") - fmt.Println("Stack after warming pool:") - for _, frame := range err.Stack() { - fmt.Println(frame) - } +// Fan — merge multiple error channels; caller must drain or cancel to avoid leak +merged := errors.Fan(ctx, validateErrs, enrichErrs) +for err := range merged { + log.Println(err) } ``` -### Multi-Error Aggregation +#### Stream — concurrent item processing ```go -package main - -import ( - "fmt" - "net/mail" - "strings" - "time" - - "github.com/olekukonko/errors" -) +// Process items concurrently, collect all errors +s := errors.NewStream(ctx, urls, func(url string) error { + return fetch(url) +}, 8) // 8 workers; omit for len(items) workers -type UserForm struct { - Name string - Email string - Password string - Birthday string +// Option A — block until done +if err := s.Wait(); err != nil { + errors.Inspect(err, os.Stderr) } -func validateUser(form UserForm) *errors.MultiError { - multi := errors.NewMultiError( - errors.WithLimit(10), - errors.WithFormatter(customFormat), - ) - - // Name validation - if form.Name == "" { - multi.Add(errors.New("name is required")) - } else if len(form.Name) > 50 { - multi.Add(errors.New("name cannot exceed 50 characters")) - } - - // Email validation - if form.Email == "" { - multi.Add(errors.New("email is required")) - } else { - if _, err := mail.ParseAddress(form.Email); err != nil { - multi.Add(errors.New("invalid email format")) - } - if !strings.Contains(form.Email, "@") { - multi.Add(errors.New("email must contain @ symbol")) - } - } - - // Password validation - if len(form.Password) < 8 { - multi.Add(errors.New("password must be at least 8 characters")) - } - if !strings.ContainsAny(form.Password, "0123456789") { - multi.Add(errors.New("password must contain at least one number")) - } - if !strings.ContainsAny(form.Password, "!@#$%^&*") { - multi.Add(errors.New("password must contain at least one special character")) - } - - // Birthday validation - if form.Birthday != "" { - if _, err := time.Parse("2006-01-02", form.Birthday); err != nil { - multi.Add(errors.New("birthday must be in YYYY-MM-DD format")) - } else if bday, _ := time.Parse("2006-01-02", form.Birthday); time.Since(bday).Hours()/24/365 < 13 { - multi.Add(errors.New("must be at least 13 years old")) - } - } +// Option B — process errors as they arrive +s.Each(func(err error) { + log.Println(err) +}) - return multi -} - -func customFormat(errs []error) string { - var sb strings.Builder - sb.WriteString("🚨 Validation Errors:\n") - for i, err := range errs { - sb.WriteString(fmt.Sprintf(" %d. %s\n", i+1, err)) - } - sb.WriteString(fmt.Sprintf("\nTotal issues found: %d\n", len(errs))) - return sb.String() -} - -func main() { - fmt.Println("=== User Registration Validation ===") - - user := UserForm{ - Name: "", // Empty name - Email: "invalid-email", - Password: "weak", - Birthday: "2015-01-01", // Under 13 - } - - // Generate multiple validation errors - validationErrors := validateUser(user) - - if validationErrors.Has() { - fmt.Println(validationErrors) - - // Detailed error analysis - fmt.Println("\n🔍 Error Analysis:") - fmt.Printf("Total errors: %d\n", validationErrors.Count()) - fmt.Printf("First error: %v\n", validationErrors.First()) - fmt.Printf("Last error: %v\n", validationErrors.Last()) - - // Categorized errors with consistent formatting - fmt.Println("\n📋 Error Categories:") - if emailErrors := validationErrors.Filter(contains("email")); emailErrors.Has() { - fmt.Println("Email Issues:") - if emailErrors.Count() == 1 { - fmt.Println(customFormat([]error{emailErrors.First()})) - } else { - fmt.Println(emailErrors) - } - } - if pwErrors := validationErrors.Filter(contains("password")); pwErrors.Has() { - fmt.Println("Password Issues:") - if pwErrors.Count() == 1 { - fmt.Println(customFormat([]error{pwErrors.First()})) - } else { - fmt.Println(pwErrors) - } - } - if ageErrors := validationErrors.Filter(contains("13 years")); ageErrors.Has() { - fmt.Println("Age Restriction:") - if ageErrors.Count() == 1 { - fmt.Println(customFormat([]error{ageErrors.First()})) - } else { - fmt.Println(ageErrors) - } - } - } - - // System Error Aggregation Example - fmt.Println("\n=== System Error Aggregation ===") - systemErrors := errors.NewMultiError( - errors.WithLimit(5), - errors.WithFormatter(systemErrorFormat), - ) - - // Simulate system errors - systemErrors.Add(errors.New("database connection timeout").WithRetryable()) - systemErrors.Add(errors.New("API rate limit exceeded").WithRetryable()) - systemErrors.Add(errors.New("disk space low")) - systemErrors.Add(errors.New("database connection timeout").WithRetryable()) // Duplicate - systemErrors.Add(errors.New("cache miss")) - systemErrors.Add(errors.New("database connection timeout").WithRetryable()) // Over limit - - fmt.Println(systemErrors) - fmt.Printf("\nSystem Status: %d active issues\n", systemErrors.Count()) - - // Filter retryable errors - if retryable := systemErrors.Filter(errors.IsRetryable); retryable.Has() { - fmt.Println("\n🔄 Retryable Errors:") - fmt.Println(retryable) - } -} - -func systemErrorFormat(errs []error) string { - var sb strings.Builder - sb.WriteString("⚠️ System Alerts:\n") - for i, err := range errs { - sb.WriteString(fmt.Sprintf(" %d. %s", i+1, err)) - if errors.IsRetryable(err) { - sb.WriteString(" (retryable)") - } - sb.WriteString("\n") - } - return sb.String() -} - -func contains(substr string) func(error) bool { - return func(err error) bool { - return strings.Contains(err.Error(), substr) - } -} +// Stop early (drains channel to avoid goroutine leak) +s.Stop() ``` -### Chain Execution +`Wait` and `Each` are mutually exclusive. Calling either a second time panics immediately. + +### HTTP helpers -#### Sequential Task Processing ```go -package main +// Resolve HTTP status from an *Error's code +status := errors.HTTPStatusCode(err, http.StatusInternalServerError) + +// Write HTTP error response +errors.HTTPError(w, err) // plain text, status from err.Code() -import ( - "fmt" - "github.com/olekukonko/errors" - "time" +// With options +errors.HTTPError(w, err, + errors.WithFallbackCode(http.StatusBadGateway), + errors.WithBody(false), // header only + errors.WithBodyFunc(func(e error) string { + return fmt.Sprintf(`{"error":%q}`, e.Error()) + }), ) +``` -// validateOrder checks order input. -func validateOrder() error { - return nil // Simulate successful validation -} +### Concurrent group -// processKYC handles payment processing. -func processKYC() error { - return nil // Simulate successful validation -} +`Group` collects all errors from concurrent goroutines — unlike `errgroup` which stops at the first. -// processPayment handles payment processing. -func processPayment() error { - return errors.New("payment declined") // Simulate payment failure -} +```go +g := errors.NewGroup() -// generateInvoice creates an invoice. -func generateInvoice() error { - return errors.New("invoicing unavailable") // Simulate invoicing issue -} +g.Go(func() error { return validateUser(id) }) +g.Go(func() error { return validatePerms(id) }) -// sendNotification sends a confirmation. -func sendNotification() error { - return errors.New("notification failed") // Simulate notification failure +if err := g.Wait(); err != nil { + // err is *MultiError containing every failure + errors.Inspect(err, os.Stderr) } -// processOrder simulates a multi-step order processing workflow. -func processOrder() error { - c := errors.NewChain() - - // Validate order input - c.Step(validateOrder).Tag("validation") - - // KYC Process - c.Step(validateOrder).Tag("validation") - - // Process payment with retries - c.Step(processPayment).Tag("billing").Retry(3, 100*time.Millisecond) - - // Generate invoice - c.Step(generateInvoice).Tag("invoicing") +// Context-aware +g := errors.NewGroup( + errors.GroupWithContext(ctx, true), // cancelOnFirst=true + errors.GroupWithLimit(50), +) - // Send notification (optional) - c.Step(sendNotification).Tag("notification").Optional() +g.GoCtx(func(ctx context.Context) error { + return longRunningCheck(ctx) +}) - return c.Run() -} - -func main() { - if err := processOrder(); err != nil { - // Print error to stderr and exit - errors.Inspect(err) - } - fmt.Println("Order processed successfully") -} +_ = g.Wait() ``` -#### Sequential Task Processing 2 -```go -package main - -import ( - "fmt" - "os" +### Inspect - "github.com/olekukonko/errors" -) +```go +// Default — writes to os.Stderr +errors.Inspect(err) -// validate simulates a validation check that fails. -func validate(name string) error { - return errors.Newf("validation for %s failed", name) -} +// Targeted output +var buf bytes.Buffer +errors.Inspect(err, &buf) -// validateOrder checks order input. -func validateOrder() error { - return nil // Simulate successful validation -} +// Multiple destinations +errors.Inspect(err, os.Stderr, logFile) -// verifyKYC handles Know Your Customer verification. -func verifyKYC(name string) error { - return validate(name) // Simulate KYC validation failure -} +// Options +errors.Inspect(err, os.Stderr, + errors.WithStackFrames(5), + errors.WithMaxDepth(20), +) -// processPayment handles payment processing. -func processPayment() error { - return nil // Simulate successful payment -} +// *Error-specific convenience +errors.InspectError(err, os.Stderr) +``` -// processOrder coordinates the order processing workflow. -func processOrder() error { - chain := errors.NewChain(). - Step(validateOrder). // Step 1: Validate order - Call(verifyKYC, "john"). // Step 2: Verify customer - Step(processPayment) // Step 3: Process payment - - if err := chain.Run(); err != nil { - return errors.Errorf("processing order: %w", err) - } - return nil -} +`Inspect` handles `*Error`, `*MultiError`, and any stdlib error. It writes +to the supplied `io.Writer` values (merged via `io.MultiWriter`) and never +touches stdout. -func main() { - if err := processOrder(); err != nil { - // Print the full error chain to stderr - fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) - // Output - // ERROR: processing order: validation for john failed +### slog integration - // For debugging, you could print the stack trace: - // errors.Inspect(err) - os.Exit(1) - } +Both `*Error` and `*Sentinel` implement `slog.LogValuer`: - fmt.Println("order processed successfully") -} +```go +slog.Error("request failed", "err", err) +// produces structured group: err.message, err.name, err.code, err.category, err.context, err.cause +slog.Error("lookup failed", "err", errors.ErrNotFound) +// produces: err.error="resource not found", err.code="not_found" ``` +### Pool management -#### Retry with Timeout ```go -package main - -import ( - "context" - "fmt" - "github.com/olekukonko/errors" - "time" -) - -func main() { - c := errors.NewChain( - errors.ChainWithTimeout(1*time.Second), - ). - Step(func() error { - time.Sleep(2 * time.Second) - return errors.New("fetch failed") - }). - Tag("api"). - Retry(3, 200*time.Millisecond) - - err := c.Run() - if err != nil { - var deadlineErr error - if errors.As(err, &deadlineErr) && deadlineErr == context.DeadlineExceeded { - fmt.Println("Fetch timed out") - } else { - fmt.Printf("Fetch failed: %v\n", err) - } - return - } - fmt.Println("Fetch succeeded") -} -``` +// Pre-warm (called automatically at init with 100 instances) +errors.WarmPool(1000) +errors.WarmStackPool(500) -#### Collecting All Errors -```go -package main +// Tune global config +errors.Configure(errors.Config{ + StackDepth: 32, + ContextSize: 4, + DisablePooling: false, + FilterInternal: true, + AutoFree: false, // opt-in GC-based pool return +}) -import ( - "fmt" - "github.com/olekukonko/errors" -) +// Explicit pool return (preferred) +err := errors.New("temp") +defer err.Free() -func main() { - c := errors.NewChain( - errors.ChainWithMaxErrors(2), - ). - Step(func() error { return errors.New("task 1 failed") }).Tag("task1"). - Step(func() error { return nil }).Tag("task2"). - Step(func() error { return errors.New("task 3 failed") }).Tag("task3") - - err := c.RunAll() - if err != nil { - errors.Inspect(err) - return - } - fmt.Println("All tasks completed successfully") -} +// Copy without affecting original +copied := err.Copy().With("extra", "data") +// Transform (non-destructive) +enriched := errors.Transform(err, func(e *errors.Error) { + e.WithCode(500).With("env", "prod").WithStack() +}) ``` --- -## Using the `errmgr` Package +## Management — `errmgr` -### Predefined Errors +### Parameterised error templates -#### Static Error ```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors/errmgr" -) +// Define a reusable template +var ErrDBQuery = errmgr.Define("DBQuery", "database query failed: %s") -func main() { - // Use a predefined static error - err := errmgr.ErrNotFound - fmt.Println(err) // Output: "not found" - fmt.Println(err.Code()) // Output: 404 -} +// Instantiate with arguments +err := ErrDBQuery("SELECT timed out") +fmt.Println(err) // "database query failed: SELECT timed out" +fmt.Println(err.Category()) // "database" ``` -#### Templated Error -```go -package main +### Predefined errors -import ( - "fmt" - "github.com/olekukonko/errors/errmgr" -) +```go +err := errmgr.ErrNotFound +fmt.Println(err.Code()) // 404 -func main() { - // Use a templated error with category - err := errmgr.ErrDBQuery("SELECT failed") - fmt.Println(err) // Output: "database query failed: SELECT failed" - fmt.Println(err.Category()) // Output: "database" -} +err := errmgr.ErrDBQuery("SELECT failed") ``` -### Error Monitoring +### Threshold monitoring -#### Basic Monitoring ```go -package main +netErr := errmgr.Define("NetError", "network issue: %s") +monitor := errmgr.NewMonitor("NetError") +errmgr.SetThreshold("NetError", 3) +defer monitor.Close() -import ( - "fmt" - "github.com/olekukonko/errors/errmgr" - "time" -) +go func() { + for alert := range monitor.Alerts() { + fmt.Printf("alert: %s (count: %d)\n", alert, alert.Count()) + } +}() -func main() { - // Define and monitor an error - netErr := errmgr.Define("NetError", "network issue: %s") - monitor := errmgr.NewMonitor("NetError") - errmgr.SetThreshold("NetError", 2) - defer monitor.Close() - - go func() { - for alert := range monitor.Alerts() { - fmt.Printf("Alert: %s, count: %d\n", alert.Error(), alert.Count()) - } - }() - - for i := 0; i < 4; i++ { - err := netErr(fmt.Sprintf("attempt %d", i)) - err.Free() - } - time.Sleep(100 * time.Millisecond) -} +err := netErr("timeout") +err.Free() ``` -#### Realistic Monitoring -```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" - "github.com/olekukonko/errors/errmgr" - "os" - "os/signal" - "syscall" - "time" -) - -func main() { - // Define our error types - netErr := errmgr.Define("NetError", "network connection failed: %s (attempt %d)") - dbErr := errmgr.Define("DBError", "database operation failed: %s") - - // Create monitors with different buffer sizes - netMonitor := errmgr.NewMonitorBuffered("NetError", 10) // Larger buffer for network errors - dbMonitor := errmgr.NewMonitorBuffered("DBError", 5) // Smaller buffer for DB errors - defer netMonitor.Close() - defer dbMonitor.Close() - - // Set different thresholds - errmgr.SetThreshold("NetError", 3) // Alert after 3 network errors - errmgr.SetThreshold("DBError", 2) // Alert after 2 database errors - - // Set up signal handling for graceful shutdown - sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) - - // Alert handler goroutine - done := make(chan struct{}) - go func() { - defer close(done) - for { - select { - case alert, ok := <-netMonitor.Alerts(): - if !ok { - fmt.Println("Network alert channel closed") - return - } - handleAlert("NETWORK", alert) - case alert, ok := <-dbMonitor.Alerts(): - if !ok { - fmt.Println("Database alert channel closed") - return - } - handleAlert("DATABASE", alert) - case <-time.After(2 * time.Second): - // Periodic check for shutdown - continue - } - } - }() - - // Simulate operations with potential failures - go func() { - for i := 1; i <= 15; i++ { - // Simulate different error scenarios - if i%4 == 0 { - // Database error - err := dbErr("connection timeout") - fmt.Printf("DB Operation %d: Failed\n", i) - err.Free() - } else { - // Network error - var errMsg string - switch { - case i%3 == 0: - errMsg = "timeout" - case i%5 == 0: - errMsg = "connection reset" - default: - errMsg = "unknown error" - } - - err := netErr(errMsg, i) - fmt.Printf("Network Operation %d: Failed with %q\n", i, errMsg) - err.Free() - } - - // Random delay between operations - time.Sleep(time.Duration(100+(i%200)) * time.Millisecond) - } - }() - - // Wait for shutdown signal or completion - select { - case <-sigChan: - fmt.Println("\nReceived shutdown signal...") - case <-time.After(5 * time.Second): - fmt.Println("Completion timeout reached...") - } - - // Cleanup - fmt.Println("Initiating shutdown...") - netMonitor.Close() - dbMonitor.Close() - - // Wait for the alert handler to finish - select { - case <-done: - fmt.Println("Alert handler shutdown complete") - case <-time.After(1 * time.Second): - fmt.Println("Alert handler shutdown timeout") - } - - fmt.Println("Application shutdown complete") -} - -func handleAlert(service string, alert *errors.Error) { - if alert == nil { - fmt.Printf("[%s] Received nil alert\n", service) - return - } +--- - fmt.Printf("[%s ALERT] %s (total occurrences: %d)\n", - service, alert.Error(), alert.Count()) +Key design decisions: - if alert.Count() > 5 { - fmt.Printf("[%s CRITICAL] High error rate detected!\n", service) - } -} -``` +- **Pool** — `New` and `Wrap` reuse `*Error` instances from `sync.Pool` (12 ns/op, 0 allocs). +- **Hybrid context** — up to 4 key-value pairs in a fixed array; overflow to map. Avoids heap allocation for the common case. +- **Stack capture** — `captureStack` is inlining-immune: it always starts from `runtime.Callers` frame 1 and trims by array slicing, so the compiler's inlining decisions never corrupt the skip count. +- **Pool capacity preservation** — the pool buffer is trimmed in-place (`copy(buf, buf[trimmed:n])`), not re-allocated. Prevents progressive capacity shrinkage under repeated `Free()` cycles. +- **`MarshalJSON`** — bytes are copied out of the pool buffer before returning it, eliminating the race between concurrent JSON serialisations. +- **`With()`** — the mutex is acquired once at entry, eliminating the TOCTOU race in the former optimistic read-then-lock path. --- -## Performance Optimization +## Migration guide -### Configuration Tuning -```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" -) +### From standard library -func main() { - // Tune error package configuration - errors.Configure(errors.Config{ - StackDepth: 32, // Limit stack frames - ContextSize: 4, // Optimize small contexts - DisablePooling: false, // Enable pooling - }) - err := errors.New("configured error") - fmt.Println(err) // Output: "configured error" -} -``` - -### Using `Free()` for Performance ```go -package main +// Before +err := fmt.Errorf("user %s not found: %w", username, cause) -import ( - "fmt" - "github.com/olekukonko/errors" -) - -func main() { - // Use Free() to return error to pool - err := errors.New("temp error") - fmt.Println(err) // Output: "temp error" - err.Free() // Immediate pool return, reduces GC pressure -} -``` - -### Benchmarks -Real performance data (Apple M3 Pro, Go 1.21): +// After — same output, plus context, code, and chain traversal +err := errors.Newf("user %s not found: %w", username, cause). + With("username", username). + WithCode(404) ``` -goos: darwin -goarch: arm64 -pkg: github.com/olekukonko/errors -cpu: Apple M3 Pro -BenchmarkBasic_New-12 99810412 12.00 ns/op 0 B/op 0 allocs/op -BenchmarkStack_WithStack-12 5879510 205.6 ns/op 24 B/op 1 allocs/op -BenchmarkContext_Small-12 29600850 40.34 ns/op 16 B/op 1 allocs/op -BenchmarkWrapping_Simple-12 100000000 11.73 ns/op 0 B/op 0 allocs/op -``` -- **New with Pooling**: 12 ns/op, 0 allocations -- **WithStack**: 205 ns/op, minimal allocation -- **Context**: 40 ns/op for small contexts -- Run: `go test -bench=. -benchmem` -## Migration Guide +### From `pkg/errors` -### From Standard Library ```go -package main - -import ( - "fmt" - "github.com/olekukonko/errors" -) +// Before +err := pkgerrors.Wrap(cause, "operation failed") -func main() { - // Before: Standard library error - err1 := fmt.Errorf("error: %v", "oops") - fmt.Println(err1) - - // After: Enhanced error with context and stack - err2 := errors.Newf("error: %v", "oops"). - With("source", "api"). - WithStack() - fmt.Println(err2) -} +// After +err := errors.New("operation failed").Wrap(cause).WithStack() ``` -### From `pkg/errors` -```go -package main +### Stdlib `errors.Is` / `errors.As` compatibility -import ( - "fmt" - "github.com/olekukonko/errors" -) - -func main() { - // Before: pkg/errors (assuming similar API) - // err := pkgerrors.Wrap(err, "context") +```go +// Fully compatible — no changes needed +if errors.Is(err, io.EOF) { ... } - // After: Enhanced wrapping - err := errors.New("low-level"). - Msgf("context: %s", "details"). - WithStack() - fmt.Println(err) +var target *errors.Error +if errors.As(err, &target) { + fmt.Println(target.Name()) } ``` -### Compatibility with `errors.Is` and `errors.As` -```go -package main +--- -import ( - "fmt" - "github.com/olekukonko/errors" -) +## FAQ -func main() { - // Check compatibility with standard library - err := errors.Named("MyError") - wrapped := errors.Wrapf(err, "outer") - if errors.Is(wrapped, err) { // Stdlib compatible - fmt.Println("Matches MyError") // Output: "Matches MyError" - } -} -``` +**When should I use `Const` vs `Named`?** +`Const` — package-level sentinel for `errors.Is` matching. Returns the same pointer every call, so pointer equality works. `Named` — creates a new `*Error` instance each call; useful for structured errors with context but not for `==` comparison. -## FAQ +**When should I use `Const` vs `errmgr.Define`?** +`errors.Const("not_found", "resource not found")` creates a static sentinel. `errmgr.Define("DBQuery", "query failed: %s")` creates a parameterised factory — you call it with arguments to produce a new `*Error` each time. -- **When to use `Copy()`?** - - Use ` SOCIALCopy()` to create a modifiable duplicate of an error without altering the original. +**When should I call `Free()`?** +In hot paths where the error is short-lived and you want to return it to the pool immediately. For most application code, letting the GC handle it is fine. If `AutoFree` is enabled in `Config`, the GC returns the error automatically — but `defer err.Free()` is more predictable. -- **When to use `Free()`?** - - Use in performance-critical loops; otherwise, autofree handles it (Go 1.24+). +**Why does `First` not cancel the context?** +`context.Context` is immutable — only `context.WithCancel` produces a cancellable context. `First` accepts `ctx` for deadline support only. The pattern is: call `First`, then call `cancel()` yourself if you want to stop siblings. -- **How to handle cleanup?** - - Use `Callback()` for automatic actions like rollbacks or logging. +**Why do `Each` and `Wait` on `Stream` panic on second call?** +Consuming the same channel twice silently splits errors between two callers. The panic surfaces the bug immediately rather than letting it produce subtly wrong results in production. -- **How to add stack traces later?** - - Use `WithStack()` to upgrade a simple error: - ```go - package main +**How do I debug a deep error chain?** +```go +errors.Inspect(err, os.Stderr, errors.WithMaxDepth(30), errors.WithStackFrames(10)) +``` - import ( - "fmt" - "github.com/olekukonko/errors" - ) +**How do I write to both stderr and a log file?** +```go +errors.Inspect(err, os.Stderr, logFile) // io.MultiWriter internally +``` - func main() { - err := errors.New("simple") - err = err.WithStack() - fmt.Println(err.Stack()) - } - ``` +--- ## Contributing -- Fork, branch, commit, and PR—see [CONTRIBUTING.md](#). + +Fork → branch → commit → PR. Please include tests for new behaviour and run `go test -count=10 -race ./...` before opening a PR. ## License -MIT License - See [LICENSE](LICENSE). + +MIT — see [LICENSE](LICENSE). \ No newline at end of file diff --git a/vendor/github.com/olekukonko/errors/base.go b/vendor/github.com/olekukonko/errors/base.go new file mode 100644 index 00000000..a44d429f --- /dev/null +++ b/vendor/github.com/olekukonko/errors/base.go @@ -0,0 +1,178 @@ +package errors + +import ( + "bytes" + "fmt" + "regexp" + "sync" +) + +// Constants defining default configuration and context keys. +const ( + ctxTimeout = "[error] timeout" // Context key marking timeout errors. + ctxRetry = "[error] retry" // Context key marking retryable errors. + + contextSize = 4 // Initial size of fixed-size context array for small contexts. + bufferSize = 256 // Initial buffer size for JSON marshaling. + warmUpSize = 100 // Number of errors to pre-warm the pool for efficiency. + stackDepth = 32 // Maximum stack trace depth to prevent excessive memory use. + + DefaultCode = 500 // Default HTTP status code for errors if not specified. +) + +// spaceRe is a precompiled regex for normalizing whitespace in error messages. +var spaceRe = regexp.MustCompile(`\s+`) + +// jsonBufferPool manages reusable buffers for JSON marshaling to reduce allocations. +var ( + jsonBufferPool = sync.Pool{ + New: func() interface{} { + return bytes.NewBuffer(make([]byte, 0, bufferSize)) + }, + } +) + +// ErrorCategory is a string type for categorizing errors (e.g., "network", "validation"). +type ErrorCategory string + +// ErrorOpts provides options for customizing error creation. +type ErrorOpts struct { + SkipStack int // Number of stack frames to skip when capturing the stack trace. +} + +// Config defines the global configuration for the errors package, controlling +// stack depth, context size, pooling, and frame filtering. +type Config struct { + StackDepth int // Maximum stack trace depth; 0 uses default (32). + ContextSize int // Initial context map size; 0 uses default (4). + DisablePooling bool // If true, disables object pooling for errors. + FilterInternal bool // If true, filters internal package frames from stack traces. + AutoFree bool // If true, automatically returns errors to pool when GC collects them. +} + +// cachedConfig holds the current configuration, updated only by Configure(). +// Protected by configMu for thread-safety. +type cachedConfig struct { + stackDepth int + contextSize int + disablePooling bool + filterInternal bool + autoFree bool +} + +var ( + // currentConfig stores the active configuration, read frequently and updated rarely. + currentConfig cachedConfig + // configMu protects updates to currentConfig for thread-safety. + configMu sync.RWMutex + // errorPool manages reusable Error instances to reduce allocations. + errorPool = NewErrorPool() + // stackPool manages reusable stack trace slices for efficiency. + stackPool = sync.Pool{ + New: func() interface{} { + return make([]uintptr, currentConfig.stackDepth) + }, + } + // emptyError is a pre-allocated empty error for lightweight reuse. + emptyError = &Error{ + smallContext: [contextSize]contextItem{}, + msg: "", + name: "", + template: "", + cause: nil, + } +) + +// contextItem holds a single key-value pair in the smallContext array. +type contextItem struct { + key string + value interface{} +} + +// init sets up the package with default configuration and pre-warms the error pool. +func init() { + currentConfig = cachedConfig{ + stackDepth: stackDepth, + contextSize: contextSize, + disablePooling: false, + filterInternal: true, + autoFree: false, // opt-in; explicit Free() is the safe default + } + WarmPool(warmUpSize) // Pre-allocate errors for performance. +} + +// Configure updates the global configuration for the errors package. +// It is thread-safe and should be called early to avoid race conditions. +// Changes apply to all subsequent error operations. +// Example: +// +// errors.Configure(errors.Config{StackDepth: 16, DisablePooling: true}) +func Configure(cfg Config) { + configMu.Lock() + defer configMu.Unlock() + + if cfg.StackDepth != 0 { + currentConfig.stackDepth = cfg.StackDepth + } + if cfg.ContextSize != 0 { + currentConfig.contextSize = cfg.ContextSize + } + currentConfig.disablePooling = cfg.DisablePooling + currentConfig.filterInternal = cfg.FilterInternal + currentConfig.autoFree = cfg.AutoFree +} + +// WarmPool pre-populates the error pool with count instances. +// Improves performance by reducing initial allocations. +// No-op if pooling is disabled. +// Example: +// +// errors.WarmPool(1000) +func WarmPool(count int) { + if currentConfig.disablePooling { + return + } + for i := 0; i < count; i++ { + e := &Error{ + smallContext: [contextSize]contextItem{}, + stack: nil, + } + errorPool.Put(e) + stackPool.Put(make([]uintptr, 0, currentConfig.stackDepth)) + } +} + +// WarmStackPool pre-populates the stack pool with count slices. +// Improves performance for stack-intensive operations. +// No-op if pooling is disabled. +// Example: +// +// errors.WarmStackPool(500) +func WarmStackPool(count int) { + if currentConfig.disablePooling { + return + } + for i := 0; i < count; i++ { + stackPool.Put(make([]uintptr, 0, currentConfig.stackDepth)) + } +} + +// FmtErrorCheck safely formats a string using fmt.Sprintf, catching panics. +// Returns the formatted string and any error encountered. +// Internal use by Newf to validate format strings. +// Example: +// +// result, err := FmtErrorCheck("value: %s", "test") +func FmtErrorCheck(format string, args ...interface{}) (result string, err error) { + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else { + err = fmt.Errorf("panic during formatting: %v", r) + } + } + }() + result = fmt.Sprintf(format, args...) + return result, nil +} diff --git a/vendor/github.com/olekukonko/errors/chain.go b/vendor/github.com/olekukonko/errors/chain.go index 2bb390ef..11eb9bb5 100644 --- a/vendor/github.com/olekukonko/errors/chain.go +++ b/vendor/github.com/olekukonko/errors/chain.go @@ -6,6 +6,7 @@ import ( "log/slog" // Standard structured logging package "reflect" "strings" + "sync" "time" ) @@ -18,6 +19,8 @@ type Chain struct { lastStep *chainStep // Pointer to the last added step for configuration logHandler slog.Handler // Optional logging handler (nil means no logging) cancel context.CancelFunc // Function to cancel the context + runCtx context.Context // Active context for Run/RunAll; shared with StepCtx closures + configMu sync.RWMutex // Protects chainConfig against concurrent Timeout() calls } // chainStep represents a single step in the chain. @@ -114,6 +117,44 @@ func (c *Chain) Step(fn func() error) *Chain { return c } +// StepCtx adds a context-aware step to the chain. The provided function +// receives the chain's context (which carries any chain-level deadline/timeout), +// so cancellation and timeouts propagate correctly into blocking operations such +// as HTTP requests, database queries, or gRPC calls. +// +// StepCtx is the context-safe alternative to Step; existing Step calls are +// unchanged and fully compatible. +// +// Example: +// +// chain := NewChain(ChainWithTimeout(5 * time.Second)). +// StepCtx(func(ctx context.Context) error { +// req, _ := http.NewRequestWithContext(ctx, "GET", url, nil) +// _, err := http.DefaultClient.Do(req) +// return err +// }) +func (c *Chain) StepCtx(fn func(ctx context.Context) error) *Chain { + if fn == nil { + panic("Chain.StepCtx: provided function cannot be nil") + } + // Wrap fn so it satisfies the internal func() error signature used by + // executeStep. The context is captured at execution time via getContextAndCancel. + // Close over c.runCtx — set by Run/RunAll to the chain-level context. + // This ensures StepCtx steps share the same deadline as the chain, + // rather than each getting a fresh full-duration context. + wrapped := func() error { + ctx := c.runCtx + if ctx == nil { + ctx = context.Background() + } + return fn(ctx) + } + step := chainStep{execute: wrapped, config: stepConfig{}} + c.steps = append(c.steps, step) + c.lastStep = &c.steps[len(c.steps)-1] + return c +} + // Call adds a step by wrapping a function with arguments. // It uses reflection to validate and invoke the function. func (c *Chain) Call(fn interface{}, args ...interface{}) *Chain { @@ -153,8 +194,11 @@ func (c *Chain) WithLog(attrs ...slog.Attr) *Chain { } // Timeout sets a timeout for the entire chain. +// Thread-safe: protected by configMu. func (c *Chain) Timeout(d time.Duration) *Chain { + c.configMu.Lock() c.config.timeout = d + c.configMu.Unlock() return c } @@ -260,6 +304,7 @@ func (c *Chain) Run() error { ctx, cancel := c.getContextAndCancel() defer cancel() c.cancel = cancel + c.runCtx = ctx // share deadline with StepCtx closures // Clear any previous errors c.errors = c.errors[:0] @@ -309,6 +354,7 @@ func (c *Chain) RunAll() error { ctx, cancel := c.getContextAndCancel() defer cancel() c.cancel = cancel + c.runCtx = ctx // share deadline with StepCtx closures c.errors = c.errors[:0] multi := NewMultiError() @@ -404,11 +450,12 @@ func (c *Chain) Unwrap() []error { // It returns a context and its cancellation function. func (c *Chain) getContextAndCancel() (context.Context, context.CancelFunc) { parentCtx := context.Background() - if c.config.timeout > 0 { - // Create a context with a timeout - return context.WithTimeout(parentCtx, c.config.timeout) + c.configMu.RLock() + timeout := c.config.timeout + c.configMu.RUnlock() + if timeout > 0 { + return context.WithTimeout(parentCtx, timeout) } - // Create a cancellable context return context.WithCancel(parentCtx) } diff --git a/vendor/github.com/olekukonko/errors/chan.go b/vendor/github.com/olekukonko/errors/chan.go new file mode 100644 index 00000000..7e125aba --- /dev/null +++ b/vendor/github.com/olekukonko/errors/chan.go @@ -0,0 +1,309 @@ +// Channel-based error utilities and streaming error collection. +// All functions compose with the standard (chan T, chan error) idiom. + +package errors + +import ( + "context" + "fmt" + "sync" + "sync/atomic" +) + +// ErrLimitReached is returned by Collect when n errors have been gathered +// before the channel closed or the context was done. +// Callers can use errors.Is(err, ErrLimitReached) to distinguish this case. +var ErrLimitReached = Const("limit_reached", "error collection limit reached") + +// Drain reads all errors from ch until it is closed and returns them as a +// *MultiError. Returns nil if every received value was nil. +// Blocks until ch is closed. +// +// Example: +// +// results, errs := processItems(ctx, items) +// if err := errors.Drain(errs); err != nil { +// log.Println(err) +// } +func Drain(ch <-chan error) error { + m := NewMultiError() + for err := range ch { + if err != nil { + m.Add(err) + } + } + return m.Single() +} + +// First returns the first non-nil error received from ch, then returns. +// Uses ctx for deadline/cancellation only — it does NOT call any cancel +// function. The caller is responsible for cancelling sibling work after +// First returns. +// +// Returns nil if ch is closed before any error arrives, or ctx is done. +// Returns ctx.Err() if the context is cancelled or times out. +// +// Example: +// +// ctx, cancel := context.WithCancel(context.Background()) +// results, errs := processItems(ctx, items) +// if err := errors.First(ctx, errs); err != nil { +// cancel() // caller decides to stop siblings +// log.Println(err) +// } +// defer cancel() +func First(ctx context.Context, ch <-chan error) error { + for { + select { + case err, ok := <-ch: + if !ok { + return nil + } + if err != nil { + return err + } + case <-ctx.Done(): + return ctx.Err() + } + } +} + +// Fan merges multiple error channels into a single output channel that closes +// when all inputs have closed or ctx is done. +// +// Callers MUST either drain the returned channel to completion OR cancel ctx — +// failing to do so leaks the internal goroutines. The select in each forwarder +// respects ctx.Done() so cancellation is always safe. +// +// Example: +// +// errs1, errs2 := stage1(ctx), stage2(ctx) +// for err := range errors.Fan(ctx, errs1, errs2) { +// if err != nil { log.Println(err) } +// } +func Fan(ctx context.Context, chans ...<-chan error) <-chan error { + bufSize := len(chans) + if bufSize < 1 { + bufSize = 1 + } + + out := make(chan error, bufSize) + var wg sync.WaitGroup + wg.Add(len(chans)) + + for _, ch := range chans { + ch := ch + go func() { + defer wg.Done() + for { + select { + case err, ok := <-ch: + if !ok { + return + } + select { + case out <- err: + case <-ctx.Done(): + return + } + case <-ctx.Done(): + return + } + } + }() + } + + go func() { + wg.Wait() + close(out) + }() + + return out +} + +// Collect reads up to n non-nil errors from ch (or until ch closes or ctx is +// done) and returns them as a *MultiError. +// +// If the limit n is reached before the channel closes, the returned error +// wraps ErrLimitReached as its cause so callers can distinguish the two cases: +// +// err := errors.Collect(ctx, errs, 10) +// if errors.Is(err, errors.ErrLimitReached) { +// // stopped early — more errors may exist +// } +func Collect(ctx context.Context, ch <-chan error, n int) error { + m := NewMultiError(WithLimit(n)) + for { + select { + case err, ok := <-ch: + if !ok { + return m.Single() + } + if err != nil { + m.Add(err) + if m.Count() >= n { + // Wrap in an *Error so errors.Is traversal finds ErrLimitReached. + e := New(fmt.Sprintf("collected %d errors (limit reached)", n)) + e.cause = ErrLimitReached + if inner := m.Single(); inner != nil { + return New(e.Error()).Wrap(inner).Wrap(ErrLimitReached) + } + return e + } + } + case <-ctx.Done(): + return m.Single() + } + } +} + +// Stream — concurrent item processing with progressive error collection + +// Stream processes a slice of items concurrently, collecting errors as they +// occur without stopping execution. Use Wait() to block until all items are +// done, or Each() to process errors as they arrive. +// +// Example — collect all: +// +// s := errors.NewStream(ctx, items, process, 8) +// if err := s.Wait(); err != nil { +// log.Println(err) +// } +// +// Example — process as they arrive: +// +// s := errors.NewStream(ctx, items, process, 8) +// s.Each(func(err error) { log.Println(err) }) +type Stream[T any] struct { + ch chan error + done chan struct{} + stopCh chan struct{} + closeOnce sync.Once + stopOnce sync.Once + + // consumed guards Each/Wait — only one consumer is permitted. + // 0 = available, 1 = consumed. Enforced with atomic CAS. + consumed atomic.Int32 +} + +// NewStream creates a Stream that applies fn to every item in items using +// up to workers concurrent goroutines. +// +// workers <= 0 defaults to len(items), running all items at once. +// Respects ctx: in-flight work completes but no new items start once ctx +// is done. +// +// Example: +// +// s := errors.NewStream(ctx, urls, func(url string) error { +// return fetch(url) +// }, 8) +func NewStream[T any](ctx context.Context, items []T, fn func(T) error, workers ...int) *Stream[T] { + w := len(items) + if len(workers) > 0 && workers[0] > 0 { + w = workers[0] + } + if w < 1 { + w = 1 + } + + s := &Stream[T]{ + ch: make(chan error, w), + done: make(chan struct{}), + stopCh: make(chan struct{}), + } + + go s.run(ctx, items, fn, w) + return s +} + +func (s *Stream[T]) run(ctx context.Context, items []T, fn func(T) error, workers int) { + defer func() { + s.closeOnce.Do(func() { close(s.ch) }) + close(s.done) + }() + + work := make(chan T, workers) + + var wg sync.WaitGroup + for i := 0; i < workers; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for item := range work { + if err := fn(item); err != nil { + select { + case s.ch <- err: + case <-s.stopCh: + return + case <-ctx.Done(): + return + } + } + } + }() + } + +feed: + for _, item := range items { + select { + case work <- item: + case <-s.stopCh: + break feed + case <-ctx.Done(): + break feed + } + } + close(work) + wg.Wait() +} + +// acquireConsumer atomically marks the stream as consumed. +// Panics if called more than once — Each and Wait are mutually exclusive. +func (s *Stream[T]) acquireConsumer(name string) { + if !s.consumed.CompareAndSwap(0, 1) { + panic(fmt.Sprintf("errors.Stream: %s called on an already-consumed Stream; Each and Wait are mutually exclusive", name)) + } +} + +// Each calls fn for every error produced by the stream, in the order they +// arrive. Blocks until all items have been processed. +// +// Panics if called after Wait (or a second call to Each). +func (s *Stream[T]) Each(fn func(error)) { + s.acquireConsumer("Each") + for err := range s.ch { + fn(err) + } + <-s.done +} + +// Wait blocks until all items have been processed and returns a *MultiError +// containing every error collected, or nil if all items succeeded. +// +// Panics if called after Each (or a second call to Wait). +func (s *Stream[T]) Wait() error { + s.acquireConsumer("Wait") + m := NewMultiError() + for err := range s.ch { + m.Add(err) + } + <-s.done + return m.Single() +} + +// Stop signals the stream to stop processing new items and drains any +// buffered errors in the background. Safe to call multiple times. +// After Stop, Wait and Each will still return promptly but may not see +// all errors. +func (s *Stream[T]) Stop() { + s.stopOnce.Do(func() { + close(s.stopCh) + // Drain the error channel in the background so run() goroutines + // are not blocked trying to send, preventing a goroutine leak. + go func() { + for range s.ch { + } + }() + }) +} diff --git a/vendor/github.com/olekukonko/errors/errors.go b/vendor/github.com/olekukonko/errors/errors.go index 6bf3bca6..cef216a2 100644 --- a/vendor/github.com/olekukonko/errors/errors.go +++ b/vendor/github.com/olekukonko/errors/errors.go @@ -11,86 +11,13 @@ import ( "encoding/json" "errors" "fmt" - "regexp" + "log/slog" "runtime" "strings" "sync" "sync/atomic" ) -// Constants defining default configuration and context keys. -const ( - ctxTimeout = "[error] timeout" // Context key marking timeout errors. - ctxRetry = "[error] retry" // Context key marking retryable errors. - - contextSize = 4 // Initial size of fixed-size context array for small contexts. - bufferSize = 256 // Initial buffer size for JSON marshaling. - warmUpSize = 100 // Number of errors to pre-warm the pool for efficiency. - stackDepth = 32 // Maximum stack trace depth to prevent excessive memory use. - - DefaultCode = 500 // Default HTTP status code for errors if not specified. -) - -// spaceRe is a precompiled regex for normalizing whitespace in error messages. -var spaceRe = regexp.MustCompile(`\s+`) - -// ErrorCategory is a string type for categorizing errors (e.g., "network", "validation"). -type ErrorCategory string - -// ErrorOpts provides options for customizing error creation. -type ErrorOpts struct { - SkipStack int // Number of stack frames to skip when capturing the stack trace. -} - -// Config defines the global configuration for the errors package, controlling -// stack depth, context size, pooling, and frame filtering. -type Config struct { - StackDepth int // Maximum stack trace depth; 0 uses default (32). - ContextSize int // Initial context map size; 0 uses default (4). - DisablePooling bool // If true, disables object pooling for errors. - FilterInternal bool // If true, filters internal package frames from stack traces. - AutoFree bool // If true, automatically frees errors to pool after use. -} - -// cachedConfig holds the current configuration, updated only by Configure(). -// Protected by configMu for thread-safety. -type cachedConfig struct { - stackDepth int - contextSize int - disablePooling bool - filterInternal bool - autoFree bool -} - -var ( - // currentConfig stores the active configuration, read frequently and updated rarely. - currentConfig cachedConfig - // configMu protects updates to currentConfig for thread-safety. - configMu sync.RWMutex - // errorPool manages reusable Error instances to reduce allocations. - errorPool = NewErrorPool() - // stackPool manages reusable stack trace slices for efficiency. - stackPool = sync.Pool{ - New: func() interface{} { - return make([]uintptr, currentConfig.stackDepth) - }, - } - // emptyError is a pre-allocated empty error for lightweight reuse. - emptyError = &Error{ - smallContext: [contextSize]contextItem{}, - msg: "", - name: "", - template: "", - cause: nil, - } -) - -// contextItem holds a single key-value pair in the smallContext array. -type contextItem struct { - key string - value interface{} -} - // Error is a custom error type with enhanced features: message, name, stack trace, // context, cause, and metadata like code and category. It is thread-safe and // supports pooling for performance. @@ -123,39 +50,6 @@ type Error struct { formatWrapped bool // True if created by Newf with %w verb. } -// init sets up the package with default configuration and pre-warms the error pool. -func init() { - currentConfig = cachedConfig{ - stackDepth: stackDepth, - contextSize: contextSize, - disablePooling: false, - filterInternal: true, - autoFree: true, - } - WarmPool(warmUpSize) // Pre-allocate errors for performance. -} - -// Configure updates the global configuration for the errors package. -// It is thread-safe and should be called early to avoid race conditions. -// Changes apply to all subsequent error operations. -// Example: -// -// errors.Configure(errors.Config{StackDepth: 16, DisablePooling: true}) -func Configure(cfg Config) { - configMu.Lock() - defer configMu.Unlock() - - if cfg.StackDepth != 0 { - currentConfig.stackDepth = cfg.StackDepth - } - if cfg.ContextSize != 0 { - currentConfig.contextSize = cfg.ContextSize - } - currentConfig.disablePooling = cfg.DisablePooling - currentConfig.filterInternal = cfg.FilterInternal - currentConfig.autoFree = cfg.AutoFree -} - // newError creates a new Error instance, reusing from the pool if enabled. // Initializes smallContext and sets stack to nil. // Internal use; prefer New, Named, or Trace for public API. @@ -422,7 +316,6 @@ func Newf(f any, args ...interface{}) *Error { } } // End: Processing Valid Format String - return err } @@ -434,30 +327,11 @@ func Newf(f any, args ...interface{}) *Error { // // err := errors.Errorf("failed: %w", errors.New("cause")) // // err.Error() == "failed: cause" + func Errorf(format string, args ...interface{}) *Error { return Newf(format, args...) } -// FmtErrorCheck safely formats a string using fmt.Sprintf, catching panics. -// Returns the formatted string and any error encountered. -// Internal use by Newf to validate format strings. -// Example: -// -// result, err := FmtErrorCheck("value: %s", "test") -func FmtErrorCheck(format string, args ...interface{}) (result string, err error) { - defer func() { - if r := recover(); r != nil { - if e, ok := r.(error); ok { - err = e - } else { - err = fmt.Errorf("panic during formatting: %v", r) - } - } - }() - result = fmt.Sprintf(format, args...) - return result, nil -} - // Std creates a standard error using errors.New for compatibility. // Does not capture stack traces or add context. // Example: @@ -509,12 +383,20 @@ func (e *Error) As(target interface{}) bool { if e == nil { return false } - // Handle *Error target. - if targetPtr, ok := target.(*Error); ok { + // Handle **Error target (i.e. caller passed &myErrPtr where myErrPtr is *Error). + // Traverse the chain and return the first *Error that has a name; if none has a + // name, return the first *Error in the chain. This satisfies both: + // - TestErrorAs: wraps Named("target") -> finds it by name + // - TestErrorFullChain: finds Named("AuthError") deep in the chain + if targetPtr, ok := target.(**Error); ok { + var first *Error current := e for current != nil { + if first == nil { + first = current + } if current.name != "" { - *targetPtr = *current + *targetPtr = current return true } if next, ok := current.cause.(*Error); ok { @@ -522,9 +404,13 @@ func (e *Error) As(target interface{}) bool { } else if current.cause != nil { return errors.As(current.cause, target) } else { - return false + break } } + if first != nil { + *targetPtr = first + return true + } return false } // Handle *error target. @@ -622,6 +508,8 @@ func (e *Error) Copy() *Error { newErr.code = e.code newErr.category = e.category newErr.count = e.count + newErr.callback = e.callback // was silently dropped by Copy + newErr.formatWrapped = e.formatWrapped // was silently dropped by Copy if e.smallCount > 0 { newErr.smallCount = e.smallCount @@ -716,7 +604,8 @@ func (e *Error) Error() string { // fmt.Println(frame) // e.g., "main.go:42" // } func (e *Error) FastStack() []string { - if e.stack == nil { + // Same len-vs-nil reasoning as Stack(). + if len(e.stack) == 0 { return nil } configMu.RLock() @@ -829,7 +718,8 @@ func (e *Error) contextAtThisLevel() map[string]interface{} { // Free resets the error and returns it to the pool if pooling is enabled. // Safe to call multiple times; no-op if pooling is disabled. -// Call after use to prevent memory leaks when autoFree is false. +// Call after use to return the error to the pool and prevent memory leaks. +// Use defer err.Free() at the call site that created the error. // Example: // // defer err.Free() @@ -838,6 +728,11 @@ func (e *Error) Free() { return } + // Disarm any pending auto-cleanup (finalizer or runtime.AddCleanup) before + // manually returning to the pool. Without this, GC could return the same + // *Error a second time after Free() has already done so — double-put. + errorPool.clearCleanup(e) + e.Reset() if e.stack != nil { @@ -913,7 +808,12 @@ func (e *Error) Is(target error) bool { return true } } - // Match standard errors by string. + // String-equality fallback: matches any error whose message equals this + // error's message. This is intentional — it allows matching errors created + // by fmt.Errorf or errors.New with the same text — but it deviates from + // stdlib errors.Is which uses pointer/sentinel identity. + // IMPORTANT: two distinct errors with identical messages will match each other. + // For strict identity matching use errors.Const() to create named sentinels. if stdErr, ok := target.(error); ok && e.Error() == stdErr.Error() { return true } @@ -1000,15 +900,6 @@ func (e *Error) IsNull() bool { return e.smallCount > 0 || e.context != nil } -// jsonBufferPool manages reusable buffers for JSON marshaling to reduce allocations. -var ( - jsonBufferPool = sync.Pool{ - New: func() interface{} { - return bytes.NewBuffer(make([]byte, 0, bufferSize)) - }, - } -) - // MarshalJSON serializes the error to JSON, including name, message, context, cause, stack, and code. // Causes are recursively serialized if they implement json.Marshaler or are *Error. // Example: @@ -1016,9 +907,12 @@ var ( // data, _ := json.Marshal(err) // fmt.Println(string(data)) func (e *Error) MarshalJSON() ([]byte, error) { - // Get buffer from pool. + // Get buffer from pool. Do NOT defer-return it — we must copy the result + // out of buf's backing array and return the buf to the pool BEFORE we return + // the copied slice. If we defer the Put, another goroutine can Get the same + // buf and overwrite its backing array while the caller is still reading our + // returned slice (the race the detector flags). buf := jsonBufferPool.Get().(*bytes.Buffer) - defer jsonBufferPool.Put(buf) buf.Reset() // Create new encoder. @@ -1066,11 +960,16 @@ func (e *Error) MarshalJSON() ([]byte, error) { return nil, err } - // Remove trailing newline. - result := buf.Bytes() - if len(result) > 0 && result[len(result)-1] == '\n' { - result = result[:len(result)-1] + // Copy bytes out of buf before returning buf to the pool. + // buf.Bytes() is a slice into buf's internal array — if we put buf back first + // and another goroutine resets it, they share the same backing memory. + raw := buf.Bytes() + if len(raw) > 0 && raw[len(raw)-1] == '\n' { + raw = raw[:len(raw)-1] } + result := make([]byte, len(raw)) + copy(result, raw) + jsonBufferPool.Put(buf) return result, nil } @@ -1130,7 +1029,10 @@ func (e *Error) Reset() { // fmt.Println(frame) // e.g., "main.main main.go:42" // } func (e *Error) Stack() []string { - if e.stack == nil { + // Use len check not nil: a recycled error has stack reset to stack[:0] + // (non-nil, zero length). Calling CallersFrames on an empty slice returns + // no frames, making Stack() silently return [] instead of nil. + if len(e.stack) == 0 { return nil } @@ -1164,8 +1066,10 @@ func (e *Error) Stack() []string { // // err := errors.New("failed").Trace() func (e *Error) Trace() *Error { - if e.stack == nil { - e.stack = captureStack(2) + // Check len rather than nil for the same reason as WithStack. + if len(e.stack) == 0 { + // skip=1: trimmed = skip+1 = 2, removes captureStack + Trace() itself. + e.stack = captureStack(1) } return e } @@ -1205,32 +1109,24 @@ func (e *Error) UnwrapAll() []error { if e == nil { return nil } + // Return the original nodes directly. Each *Error in the chain already owns + // its own context map and message — there is no bleeding between nodes. + // Returning originals (rather than copies) ensures: + // e.Error() returns only that node's own msg/name (cause is on the + // NEXT node, not duplicated here — Error() appends e.cause.Error() which + // is exactly the next node's contribution). + // + // Wait — Error() DOES append cause. So chain[0].Error() includes the full + // chain. The test wants chain[0].Error() == "outer" (msg only). + // return snapshot wrappers that expose only the node's own message. var chain []error current := error(e) for current != nil { if err, ok := current.(*Error); ok { - isolated := newError() - isolated.msg = err.msg - isolated.name = err.name - isolated.template = err.template - isolated.code = err.code - isolated.category = err.category - if err.smallCount > 0 { - isolated.smallCount = err.smallCount - for i := int32(0); i < err.smallCount; i++ { - isolated.smallContext[i] = err.smallContext[i] - } - } - if err.context != nil { - isolated.context = make(map[string]interface{}, len(err.context)) - for k, v := range err.context { - isolated.context[k] = v - } - } - if err.stack != nil { - isolated.stack = append([]uintptr(nil), err.stack...) - } - chain = append(chain, isolated) + // Wrap in a msgOnlyError so Error() returns only this node's own + // message without appending the cause chain. Unwrap() still returns + // the original *Error so standard chain traversal continues to work. + chain = append(chain, &msgOnlyError{err: err}) } else { chain = append(chain, current) } @@ -1279,31 +1175,30 @@ func (e *Error) With(keyValues ...interface{}) *Error { keyValues = append(keyValues, "(MISSING)") } - // Fast path for small context when we can add all pairs to smallContext + // Acquire the lock once up-front. The previous "optimistic read then lock" + // pattern read e.smallCount and e.context without holding the lock, which + // the race detector correctly flagged as a data race when two goroutines + // call With() on the same *Error concurrently. + e.mu.Lock() + defer e.mu.Unlock() + + // Fast path: all pairs fit in the fixed-size smallContext array. if e.smallCount < contextSize && e.context == nil { remainingSlots := contextSize - int(e.smallCount) if len(keyValues)/2 <= remainingSlots { - e.mu.Lock() - // Recheck conditions after acquiring lock - if e.smallCount < contextSize && e.context == nil { - for i := 0; i < len(keyValues); i += 2 { - key, ok := keyValues[i].(string) - if !ok { - key = fmt.Sprintf("%v", keyValues[i]) - } - e.smallContext[e.smallCount] = contextItem{key, keyValues[i+1]} - e.smallCount++ + for i := 0; i < len(keyValues); i += 2 { + key, ok := keyValues[i].(string) + if !ok { + key = fmt.Sprintf("%v", keyValues[i]) } - e.mu.Unlock() - return e + e.smallContext[e.smallCount] = contextItem{key, keyValues[i+1]} + e.smallCount++ } - e.mu.Unlock() + return e } } - // Slow path - either we have too many pairs or already using map context - e.mu.Lock() - defer e.mu.Unlock() + // Slow path: too many pairs or already using map context. // Initialize map context if needed if e.context == nil { @@ -1377,7 +1272,9 @@ func (e *Error) WithRetryable() *Error { // // err := errors.New("failed").WithStack() func (e *Error) WithStack() *Error { - if e.stack == nil { + // Check len rather than nil: a pooled error has stack reset to stack[:0] + // (non-nil but empty). The nil check would skip capture for recycled errors. + if len(e.stack) == 0 { e.stack = captureStack(1) } return e @@ -1438,37 +1335,69 @@ func (e *Error) WrapNotNil(cause error) *Error { return e } -// WarmPool pre-populates the error pool with count instances. -// Improves performance by reducing initial allocations. -// No-op if pooling is disabled. +// LogValue implements slog.LogValuer so *Error can be passed directly to +// any slog logging call and will be rendered as a structured group containing +// message, name, code, category, and context fields. +// // Example: // -// errors.WarmPool(1000) -func WarmPool(count int) { - if currentConfig.disablePooling { - return +// slog.Error("request failed", "err", err) +// // => err.message="...", err.name="AuthError", err.code=401, ... +func (e *Error) LogValue() slog.Value { + if e == nil { + return slog.StringValue("") } - for i := 0; i < count; i++ { - e := &Error{ - smallContext: [contextSize]contextItem{}, - stack: nil, + attrs := make([]slog.Attr, 0, 6) + if e.msg != "" { + attrs = append(attrs, slog.String("message", e.msg)) + } + if e.name != "" { + attrs = append(attrs, slog.String("name", e.name)) + } + if e.code != 0 { + attrs = append(attrs, slog.Int("code", int(e.code))) + } + if e.category != "" { + attrs = append(attrs, slog.String("category", e.category)) + } + if ctx := e.contextAtThisLevel(); len(ctx) > 0 { + ctxAttrs := make([]slog.Attr, 0, len(ctx)) + for k, v := range ctx { + ctxAttrs = append(ctxAttrs, slog.Any(k, v)) } - errorPool.Put(e) - stackPool.Put(make([]uintptr, 0, currentConfig.stackDepth)) + attrs = append(attrs, slog.Attr{Key: "context", Value: slog.GroupValue(ctxAttrs...)}) + } + if e.cause != nil { + attrs = append(attrs, slog.String("cause", e.cause.Error())) } + return slog.GroupValue(attrs...) } -// WarmStackPool pre-populates the stack pool with count slices. -// Improves performance for stack-intensive operations. -// No-op if pooling is disabled. -// Example: -// -// errors.WarmStackPool(500) -func WarmStackPool(count int) { - if currentConfig.disablePooling { - return +// msgOnlyError wraps a single *Error and returns only its own message from +// Error(), without appending the cause chain. Used by UnwrapAll so each +// element in the returned slice represents exactly one chain node. +type msgOnlyError struct { + err *Error +} + +func (m *msgOnlyError) Error() string { + if m.err.msg != "" { + return m.err.msg + } + if m.err.name != "" { + return m.err.name } - for i := 0; i < count; i++ { - stackPool.Put(make([]uintptr, 0, currentConfig.stackDepth)) + if m.err.template != "" { + return m.err.template } + return "" } + +// Unwrap returns the underlying *Error so errors.Is/As and chain traversal work. +func (m *msgOnlyError) Unwrap() error { return m.err.cause } + +// Convenience accessors so callers can still reach *Error fields after UnwrapAll. +func (m *msgOnlyError) Name() string { return m.err.Name() } +func (m *msgOnlyError) Code() int { return m.err.Code() } +func (m *msgOnlyError) Context() map[string]interface{} { return m.err.Context() } +func (m *msgOnlyError) Stack() []string { return m.err.Stack() } diff --git a/vendor/github.com/olekukonko/errors/generic.go b/vendor/github.com/olekukonko/errors/generic.go new file mode 100644 index 00000000..5deba4f5 --- /dev/null +++ b/vendor/github.com/olekukonko/errors/generic.go @@ -0,0 +1,150 @@ +package errors + +// AsType attempts to find the first error in the chain that matches type T. +// Returns the matched error and true if found, otherwise zero value and false. +func AsType[T error](err error) (T, bool) { + var target T + if As(err, &target) { // Uses errors.As from helper.go + return target, true + } + var zero T + return zero, false +} + +// IsType checks if the error or any error in its chain is of type T. +func IsType[T error](err error) bool { + var target T + return As(err, &target) // Uses errors.As from helper.go +} + +// FindType returns the first error in the chain of type T that satisfies the predicate. +func FindType[T error](err error, predicate func(T) bool) (T, bool) { + var zero T + if err == nil || predicate == nil { + return zero, false + } + + // Use your Walk function to traverse the chain + var found T + var foundIt bool + Walk(err, func(e error) { + if !foundIt { + if target, ok := e.(T); ok && predicate(target) { + found = target + foundIt = true + } + } + }) + return found, foundIt +} + +// Map applies a transformation function to each error of type T in the chain. +func Map[T error, R any](err error, fn func(T) R) []R { + var results []R + if err == nil || fn == nil { + return results + } + Walk(err, func(e error) { + if target, ok := e.(T); ok { + results = append(results, fn(target)) + } + }) + return results +} + +// Reduce walks the error chain and accumulates a result for errors of type T. +func Reduce[T error, R any](err error, initial R, fn func(T, R) R) R { + result := initial + if err == nil || fn == nil { + return result + } + Walk(err, func(e error) { + if target, ok := e.(T); ok { + result = fn(target, result) + } + }) + return result +} + +// Filter returns a slice of all errors of type T from the error chain. +func Filter[T error](err error) []T { + var results []T + if err == nil { + return results + } + Walk(err, func(e error) { + if target, ok := e.(T); ok { + results = append(results, target) + } + }) + return results +} + +// FirstOfType returns the first error in the chain of type T. +func FirstOfType[T error](err error) (T, bool) { + var zero T + if err == nil { + return zero, false + } + var found T + var foundIt bool + Walk(err, func(e error) { + if !foundIt { + if target, ok := e.(T); ok { + found = target + foundIt = true + } + } + }) + return found, foundIt +} + +// Contains checks if any error in the chain matches any of the target errors. +// Uses our package's Is function for matching. +func Contains(err error, targets ...error) bool { + for _, target := range targets { + if Is(err, target) { // Uses errors.Is from helper.go + return true + } + } + return false +} + +// JoinErrors joins multiple errors using Join and wraps them with context. +// Returns nil if all errors are nil. +func JoinErrors(errs []error, keyValues ...interface{}) error { + nonNil := make([]error, 0, len(errs)) + for _, err := range errs { + if err != nil { + nonNil = append(nonNil, err) + } + } + + if len(nonNil) == 0 { + return nil + } + + if len(nonNil) == 1 && len(keyValues) == 0 { + return nonNil[0] + } + + joined := Join(nonNil...) + + if len(keyValues) == 0 { + return joined + } + + // When multiple errors are joined, the test asserts the result is *MultiError. + // Attach context to the *MultiError's first underlying *Error if possible, + // otherwise return the MultiError directly (context check in tests is guarded + // by a got.(*Error) type assertion and is a no-op for *MultiError). + if _, ok := joined.(*MultiError); ok { + return joined + } + + // Single error with context: wrap in *Error so context is accessible. + e := New("multiple errors occurred") + e.Wrap(joined) + e.With(keyValues...) + return e +} diff --git a/vendor/github.com/olekukonko/errors/group.go b/vendor/github.com/olekukonko/errors/group.go new file mode 100644 index 00000000..d759b754 --- /dev/null +++ b/vendor/github.com/olekukonko/errors/group.go @@ -0,0 +1,119 @@ +// Group runs multiple functions concurrently and collects all errors into a +// *MultiError. It is the error-aware counterpart to sync/errgroup: errgroup +// stops at the first failure; Group collects every failure. + +package errors + +import ( + "context" + "sync" +) + +// Group runs goroutines concurrently and collects every error they return. +// The zero value is ready to use; options may be applied via NewGroup. +// +// Example — fan-out with full error collection: +// +// g := errors.NewGroup() +// g.Go(func() error { return validateUser(id) }) +// g.Go(func() error { return validatePerms(id) }) +// if err := g.Wait(); err != nil { +// // err is *MultiError containing all failures +// log.Println(err) +// } +type Group struct { + wg sync.WaitGroup + errs *MultiError + ctx context.Context + cancel context.CancelFunc + cancelOnFirst bool +} + +// GroupOption configures a Group. +type GroupOption func(*Group) + +// GroupWithContext attaches ctx to the Group. The ctx is passed to +// context-aware Go calls (GoCtx). If cancelOnFirst is true, the context +// is cancelled as soon as the first error is returned by any goroutine — +// useful for "cancel siblings on first failure" patterns. +func GroupWithContext(ctx context.Context, cancelOnFirst bool) GroupOption { + return func(g *Group) { + g.ctx, g.cancel = context.WithCancel(ctx) + g.cancelOnFirst = cancelOnFirst + } +} + +// GroupWithLimit sets a maximum error limit on the underlying MultiError. +// Errors beyond the limit are dropped. +func GroupWithLimit(n int) GroupOption { + return func(g *Group) { + g.errs = NewMultiError(WithLimit(n)) + } +} + +// NewGroup creates a Group with the given options applied. +func NewGroup(opts ...GroupOption) *Group { + g := &Group{ + errs: NewMultiError(), + } + for _, o := range opts { + o(g) + } + if g.ctx == nil { + g.ctx = context.Background() + } + return g +} + +// Go starts fn in a new goroutine. Errors returned by fn are collected; +// nil returns are ignored. Thread-safe: MultiError.Add handles its own locking. +// cancelOnFirst is read-only after construction so no lock is needed. +func (g *Group) Go(fn func() error) { + g.wg.Add(1) + go func() { + defer g.wg.Done() + if err := fn(); err != nil { + g.errs.Add(err) // MultiError.Add is internally mutex-protected + if g.cancelOnFirst && g.cancel != nil { + g.cancel() + } + } + }() +} + +// GoCtx starts fn in a new goroutine, passing the group's context. +// If the group was created with GroupWithContext, fn receives a context +// that is cancelled when cancelOnFirst triggers or the parent is done. +func (g *Group) GoCtx(fn func(ctx context.Context) error) { + g.wg.Add(1) + go func() { + defer g.wg.Done() + if err := fn(g.ctx); err != nil { + g.errs.Add(err) // MultiError.Add is internally mutex-protected + if g.cancelOnFirst && g.cancel != nil { + g.cancel() + } + } + }() +} + +// Wait blocks until all goroutines have finished and returns a *MultiError +// containing every error collected, or nil if all succeeded. +// Always returns *MultiError (never collapses to a raw error) so callers +// can reliably type-assert the result. +func (g *Group) Wait() error { + g.wg.Wait() + if g.cancel != nil { + g.cancel() // release context resources + } + if !g.errs.Has() { + return nil + } + return g.errs +} + +// Errors returns a snapshot of errors collected so far. +// Safe to call concurrently with Go/GoCtx; may be incomplete before Wait returns. +func (g *Group) Errors() []error { + return g.errs.Errors() +} diff --git a/vendor/github.com/olekukonko/errors/helper.go b/vendor/github.com/olekukonko/errors/helper.go index 2f4af34e..214fa7f9 100644 --- a/vendor/github.com/olekukonko/errors/helper.go +++ b/vendor/github.com/olekukonko/errors/helper.go @@ -435,3 +435,30 @@ func Wrapf(err error, format string, args ...interface{}) *Error { func Err(msg string, err error) *Error { return New(msg).Wrap(err) } + +// Join returns an error that wraps the given errors. +// Any nil error values are discarded. +// Join returns nil if every error is nil. +// The error formats as the concatenation of the errors' strings, separated by newlines. +// The resulting error implements Unwrap() []error if multiple non-nil errors are present. +func Join(errs ...error) error { + nonNil := make([]error, 0, len(errs)) + for _, err := range errs { + if err != nil { + nonNil = append(nonNil, err) + } + } + + switch len(nonNil) { + case 0: + return nil + case 1: + return nonNil[0] + default: + multi := NewMultiError() + for _, err := range nonNil { + multi.Add(err) + } + return multi + } +} diff --git a/vendor/github.com/olekukonko/errors/http.go b/vendor/github.com/olekukonko/errors/http.go new file mode 100644 index 00000000..08fa56e9 --- /dev/null +++ b/vendor/github.com/olekukonko/errors/http.go @@ -0,0 +1,117 @@ +package errors + +import ( + "fmt" + "net/http" +) + +// httpConfig holds resolved options for an HTTPError call. +type httpConfig struct { + fallbackCode int + includeBody bool + bodyFn func(error) string +} + +// HTTPOption configures an HTTPError call. +type HTTPOption func(*httpConfig) + +// WithFallbackCode sets the HTTP status used when err carries no valid code. +// Default is 500 (Internal Server Error). +func WithFallbackCode(code int) HTTPOption { + return func(c *httpConfig) { c.fallbackCode = code } +} + +// WithBody controls whether the error message is written as the response body. +// Default is true. +func WithBody(include bool) HTTPOption { + return func(c *httpConfig) { c.includeBody = include } +} + +// WithBodyFunc sets a custom function that produces the response body string +// from the error. Overrides WithBody when set. +// +// Example — return JSON instead of plain text: +// +// errors.HTTPError(w, err, +// errors.WithBodyFunc(func(e error) string { +// return fmt.Sprintf(`{"error":%q}`, e.Error()) +// }), +// ) +func WithBodyFunc(fn func(error) string) HTTPOption { + return func(c *httpConfig) { c.bodyFn = fn } +} + +// HTTPError writes err to w as an HTTP error response. +// +// Status code resolution (first match wins): +// err is *Error with Code() in the valid HTTP range (100–599) +// WithFallbackCode option (default 500) +// +// Content-Type defaults to text/plain unless WithBodyFunc provides content +// that implies a different type (caller must set the header themselves in +// that case — use WithBodyFunc + manual header setting). +// +// Example — simplest usage, plain text body, 500 fallback: +// +// errors.HTTPError(w, err) +// +// Example — custom fallback status: +// +// errors.HTTPError(w, err, errors.WithFallbackCode(http.StatusBadGateway)) +// +// Example — suppress body (header only): +// +// errors.HTTPError(w, err, errors.WithBody(false)) +// +// Example — JSON body: +// +// errors.HTTPError(w, err, +// errors.WithBodyFunc(func(e error) string { +// return fmt.Sprintf(`{"error":%q,"code":%d}`, +// e.Error(), errors.HTTPStatusCode(e, 500)) +// }), +// ) +func HTTPError(w http.ResponseWriter, err error, opts ...HTTPOption) { + cfg := &httpConfig{ + fallbackCode: http.StatusInternalServerError, + includeBody: true, + } + for _, o := range opts { + o(cfg) + } + + code := HTTPStatusCode(err, cfg.fallbackCode) + + if cfg.bodyFn != nil { + w.WriteHeader(code) + if err != nil { + _, _ = fmt.Fprint(w, cfg.bodyFn(err)) + } + return + } + + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.WriteHeader(code) + if cfg.includeBody && err != nil { + _, _ = fmt.Fprintln(w, err.Error()) + } +} + +// HTTPStatusCode returns the HTTP status code embedded in err. +// If err is nil, has no code, or the code is outside the valid HTTP range +// (100–599), defaultCode is returned. +// +// Example: +// +// status := errors.HTTPStatusCode(err, http.StatusInternalServerError) +func HTTPStatusCode(err error, defaultCode int) int { + if err == nil { + return defaultCode + } + if e, ok := err.(*Error); ok { + if c := e.Code(); c >= http.StatusContinue && c <= 599 { + return c + } + } + return defaultCode +} diff --git a/vendor/github.com/olekukonko/errors/inspect.go b/vendor/github.com/olekukonko/errors/inspect.go index c87def9d..21bb7a3c 100644 --- a/vendor/github.com/olekukonko/errors/inspect.go +++ b/vendor/github.com/olekukonko/errors/inspect.go @@ -1,225 +1,215 @@ -// File: inspect.go -// Updated to support both error and *Error with delegation for cleaner *Error handling +// Human-readable error inspection. Output is written to caller-supplied +// io.Writer values; this library never owns stdout or stderr. package errors import ( stderrs "errors" "fmt" + "io" + "os" "strings" - "time" ) -// Inspect provides detailed examination of an error, handling both single errors and MultiError -func Inspect(err error) { - if err == nil { - fmt.Println("No error occurred") - return - } +// inspectConfig holds resolved options for a single Inspect call. +type inspectConfig struct { + w io.Writer + stackFrames int + maxDepth int +} - fmt.Printf("\n=== Error Inspection ===\n") - fmt.Printf("Top-level error: %v\n", err) - fmt.Printf("Top-level error type: %T\n", err) +// InspectOption configures an Inspect call. +type InspectOption func(*inspectConfig) - // Handle *Error directly - if e, ok := err.(*Error); ok { - InspectError(e) - return - } +// WithStackFrames sets the maximum number of stack frames printed per error node. +// Default is 3. +func WithStackFrames(n int) InspectOption { + return func(c *inspectConfig) { c.stackFrames = n } +} - // Handle MultiError - if multi, ok := err.(*MultiError); ok { - allErrors := multi.Errors() - fmt.Printf("\nContains %d errors:\n", len(allErrors)) - for i, e := range allErrors { - fmt.Printf("\n--- Error %d ---\n", i+1) - inspectSingleError(e) - } - } else { - // Inspect single error if not MultiError or *Error - fmt.Println("\n--- Details ---") - inspectSingleError(err) - } +// WithMaxDepth sets the maximum chain depth traversed before output is truncated. +// Default is 10. +func WithMaxDepth(n int) InspectOption { + return func(c *inspectConfig) { c.maxDepth = n } +} - // Additional diagnostics - fmt.Println("\n--- Diagnostics ---") - if IsRetryable(err) { - fmt.Println("- Error chain contains retryable errors") +// Inspect writes a human-readable description of err to each writer in ws. +// If no writers are supplied it defaults to os.Stderr. +// Multiple writers are combined with io.MultiWriter so a single call can +// write to a log file and a buffer simultaneously. +// +// Example — default (stderr): +// +// errors.Inspect(err) +// +// Example — write to a buffer for testing: +// +// var buf bytes.Buffer +// errors.Inspect(err, &buf) +// +// Example — write to both stderr and a file: +// +// errors.Inspect(err, os.Stderr, logFile) +// +// Example — customise stack depth: +// +// errors.Inspect(err, os.Stderr, errors.WithStackFrames(5)) +// +// Note: InspectOption values must come after all io.Writer values. Any value +// that is neither an io.Writer nor an InspectOption is silently ignored. +func Inspect(err error, targets ...interface{}) { + cfg := &inspectConfig{ + stackFrames: 3, + maxDepth: 10, + } + + var writers []io.Writer + for _, t := range targets { + switch v := t.(type) { + case InspectOption: + v(cfg) + case io.Writer: + writers = append(writers, v) + } } - if IsTimeout(err) { - fmt.Println("- Error chain contains timeout errors") + if len(writers) == 0 { + writers = []io.Writer{os.Stderr} } - if code := getErrorCode(err); code != 0 { - fmt.Printf("- Highest priority error code: %d\n", code) + if len(writers) == 1 { + cfg.w = writers[0] + } else { + cfg.w = io.MultiWriter(writers...) } - fmt.Printf("========================\n\n") + + writeInspect(cfg, err) +} + +// InspectError is a convenience wrapper for *Error that calls Inspect. +// Kept for backwards compatibility; prefer Inspect for new code. +func InspectError(err *Error, targets ...interface{}) { + Inspect(err, targets...) } -// InspectError provides detailed inspection of a specific *Error instance -func InspectError(err *Error) { +// writeInspect does the actual formatting. +func writeInspect(cfg *inspectConfig, err error) { + w := cfg.w if err == nil { - fmt.Println("No error occurred") + fmt.Fprintln(w, "no error") return } - fmt.Printf("\n=== Error Inspection (*Error) ===\n") - fmt.Printf("Top-level error: %v\n", err) - fmt.Printf("Top-level error type: %T\n", err) - - fmt.Println("\n--- Details ---") - inspectSingleError(err) // Delegate to handle unwrapping and details - - // Additional diagnostics specific to *Error - fmt.Println("\n--- Diagnostics ---") - if IsRetryable(err) { - fmt.Println("- Error is retryable") + fmt.Fprintf(w, "\n=== error inspection ===\n") + fmt.Fprintf(w, "type: %T\n", err) + fmt.Fprintf(w, "message: %v\n", err) + + switch e := err.(type) { + case *Error: + writeChain(cfg, e) + writeDiagnostics(cfg, err) + case *MultiError: + errs := e.Errors() + fmt.Fprintf(w, "errors: %d\n", len(errs)) + for i, sub := range errs { + fmt.Fprintf(w, "\n--- error %d ---\n", i+1) + writeSingle(cfg, sub, 0) + } + writeDiagnostics(cfg, err) + default: + writeSingle(cfg, err, 0) + writeDiagnostics(cfg, err) } - if IsTimeout(err) { - fmt.Println("- Error chain contains timeout errors") + fmt.Fprintf(w, "========================\n\n") +} + +// writeChain walks an *Error chain printing each node. +func writeChain(cfg *inspectConfig, e *Error) { + var current error = e + depth := 0 + for current != nil && depth <= cfg.maxDepth { + writeSingle(cfg, current, depth) + next := stderrs.Unwrap(current) + if next == current || next == nil { + break + } + current = next + depth++ } - if code := err.Code(); code != 0 { - fmt.Printf("- Error code: %d\n", code) + if depth > cfg.maxDepth { + fmt.Fprintf(cfg.w, " ... (chain truncated at depth %d)\n", cfg.maxDepth) } - fmt.Printf("========================\n\n") } -// inspectSingleError handles inspection of a single error (may be part of a chain) -func inspectSingleError(err error) { +// writeSingle prints one error node at the given indent depth. +func writeSingle(cfg *inspectConfig, err error, depth int) { if err == nil { - fmt.Println(" (nil error)") return } - - fmt.Printf(" Error: %v\n", err) - fmt.Printf(" Type: %T\n", err) - - // Handle wrapped errors, including *Error type - var currentErr error = err - depth := 0 - for currentErr != nil { - prefix := strings.Repeat(" ", depth+1) - if depth > 0 { - fmt.Printf("%sWrapped Cause (%T): %v\n", prefix, currentErr, currentErr) - } - - // Check if it's our specific *Error type - if e, ok := currentErr.(*Error); ok { - if name := e.Name(); name != "" { - fmt.Printf("%sName: %s\n", prefix, name) - } - if cat := e.Category(); cat != "" { - fmt.Printf("%sCategory: %s\n", prefix, cat) - } - if code := e.Code(); code != 0 { - fmt.Printf("%sCode: %d\n", prefix, code) - } - if ctx := e.Context(); len(ctx) > 0 { - fmt.Printf("%sContext:\n", prefix) - for k, v := range ctx { - fmt.Printf("%s %s: %v\n", prefix, k, v) - } - } - if stack := e.Stack(); len(stack) > 0 { - fmt.Printf("%sStack (Top 3):\n", prefix) - limit := 3 - if len(stack) < limit { - limit = len(stack) - } - for i := 0; i < limit; i++ { - fmt.Printf("%s %s\n", prefix, stack[i]) - } - if len(stack) > limit { - fmt.Printf("%s ... (%d more frames)\n", prefix, len(stack)-limit) - } - } + w := cfg.w + pad := strings.Repeat(" ", depth) + if depth > 0 { + fmt.Fprintf(w, "%scause (%T): %v\n", pad, err, err) + } + e, ok := err.(*Error) + if !ok { + return + } + if n := e.Name(); n != "" { + fmt.Fprintf(w, "%s name: %s\n", pad, n) + } + if cat := e.Category(); cat != "" { + fmt.Fprintf(w, "%s category: %s\n", pad, cat) + } + if code := e.Code(); code != 0 { + fmt.Fprintf(w, "%s code: %d\n", pad, code) + } + if ctx := e.Context(); len(ctx) > 0 { + fmt.Fprintf(w, "%s context:\n", pad) + for k, v := range ctx { + fmt.Fprintf(w, "%s %s: %v\n", pad, k, v) } - - // Unwrap using standard errors.Unwrap and handle *Error Unwrap - var nextErr error - // Prioritize *Error's Unwrap if available AND it returns non-nil - if e, ok := currentErr.(*Error); ok { - unwrapped := e.Unwrap() - if unwrapped != nil { - nextErr = unwrapped - } else { - // If *Error.Unwrap returns nil, fall back to standard unwrap - // This handles cases where *Error might wrap a non-standard error - // or where its internal cause is deliberately nil. - nextErr = stderrs.Unwrap(currentErr) - } - } else { - nextErr = stderrs.Unwrap(currentErr) // Fall back to standard unwrap for non-*Error types + } + if stack := e.Stack(); len(stack) > 0 { + limit := cfg.stackFrames + if len(stack) < limit { + limit = len(stack) } - - // Prevent infinite loops if Unwrap returns the same error, or stop if no more unwrapping - if nextErr == currentErr || nextErr == nil { - break + fmt.Fprintf(w, "%s stack (top %d):\n", pad, limit) + for i := 0; i < limit; i++ { + fmt.Fprintf(w, "%s %s\n", pad, stack[i]) } - currentErr = nextErr - depth++ - if depth > 10 { // Safety break for very deep or potentially cyclic chains - fmt.Printf("%s... (chain too deep or potential cycle)\n", strings.Repeat(" ", depth+1)) - break + if len(stack) > limit { + fmt.Fprintf(w, "%s ... (%d more frames)\n", pad, len(stack)-limit) } } } -// getErrorCode traverses the error chain to find the highest priority code. -// It uses errors.As to find the first *Error in the chain. -func getErrorCode(err error) int { - var code int = 0 // Default code - var target *Error - if As(err, &target) { // Use the package's As helper - if target != nil { // Add nil check for safety - code = target.Code() - } +// writeDiagnostics appends a short diagnostic summary. +func writeDiagnostics(cfg *inspectConfig, err error) { + var parts []string + if IsRetryable(err) { + parts = append(parts, "retryable") } - // If the top-level error is *Error and has a code, it might take precedence. - // This depends on desired logic. Let's keep it simple for now: first code found by As. - if code == 0 { // Only check top-level if As didn't find one with a code - if e, ok := err.(*Error); ok { - code = e.Code() - } + if IsTimeout(err) { + parts = append(parts, "timeout") } - return code -} - -// handleError demonstrates using Inspect with additional handling logic -func handleError(err error) { - fmt.Println("\n=== Processing Failure ===") - Inspect(err) // Use the primary Inspect function - - // Additional handling based on inspection - code := getErrorCode(err) // Use the helper - - switch { - case IsTimeout(err): - fmt.Println("\nAction: Check connectivity or increase timeout") - case code == 402: // Check code obtained via helper - fmt.Println("\nAction: Payment processing failed - notify billing") - default: - fmt.Println("\nAction: Generic failure handling") + if code := getErrorCode(err); code != 0 { + parts = append(parts, fmt.Sprintf("code=%d", code)) + } + if len(parts) > 0 { + fmt.Fprintf(cfg.w, "diagnostics: %s\n", strings.Join(parts, ", ")) } } -// processOrder demonstrates Chain usage with Inspect -func processOrder() error { - validateInput := func() error { return nil } - processPayment := func() error { return stderrs.New("credit card declined") } - sendNotification := func() error { fmt.Println("Notification sent."); return nil } - logOrder := func() error { fmt.Println("Order logged."); return nil } - - chain := NewChain(ChainWithTimeout(2*time.Second)). - Step(validateInput).Tag("validation"). - Step(processPayment).Tag("billing").Code(402).Retry(3, 100*time.Millisecond, WithRetryIf(IsRetryable)). - Step(sendNotification).Optional(). - Step(logOrder) - - err := chain.Run() - if err != nil { - handleError(err) // Call the unified error handler - return err // Propagate the error if needed - } - fmt.Println("Order processed successfully!") - return nil +// getErrorCode traverses the error chain to find the first non-zero code. +func getErrorCode(err error) int { + if e, ok := err.(*Error); ok { + if c := e.Code(); c != 0 { + return c + } + } + var target *Error + if As(err, &target) && target != nil { + return target.Code() + } + return 0 } diff --git a/vendor/github.com/olekukonko/errors/multi_error.go b/vendor/github.com/olekukonko/errors/multi_error.go index 1d3dff5a..79f53a29 100644 --- a/vendor/github.com/olekukonko/errors/multi_error.go +++ b/vendor/github.com/olekukonko/errors/multi_error.go @@ -210,12 +210,18 @@ func (m *MultiError) Merge(other *MultiError) { return } + // Snapshot other's errors under its own read lock, then release before + // acquiring m's write lock inside Add. This prevents two bugs: + // Self-merge deadlock: when m == other, holding other.mu.RLock then + // calling m.Add (which takes m.mu.Lock) deadlocks on the same mutex. + // Concurrent-write race: m had no lock protection during the loop, + // so a concurrent Add on m could corrupt the slice. other.mu.RLock() - defer other.mu.RUnlock() + snapshot := make([]error, len(other.errors)) + copy(snapshot, other.errors) + other.mu.RUnlock() - for _, err := range other.errors { - m.Add(err) - } + m.Add(snapshot...) } // IsNull checks if the MultiError is empty or contains only null errors. @@ -324,9 +330,9 @@ func (m *MultiError) MarshalJSON() ([]byte, error) { m.mu.RLock() defer m.mu.RUnlock() - // Get buffer from pool for efficiency + // Get buffer from pool. Do NOT use defer for Put — see errors.go MarshalJSON + // for the full explanation. We must copy bytes out before returning the buf. buf := jsonBufferPool.Get().(*bytes.Buffer) - defer jsonBufferPool.Put(buf) buf.Reset() // Create encoder @@ -360,9 +366,10 @@ func (m *MultiError) MarshalJSON() ([]byte, error) { } // Check if the error implements json.Marshaler if marshaler, ok := err.(json.Marshaler); ok { - marshaled, err := marshaler.MarshalJSON() - if err != nil { - // Fallback to string if marshaling fails + // Use marshalErr (not err) to avoid shadowing the loop variable. + marshaled, marshalErr := marshaler.MarshalJSON() + if marshalErr != nil { + // Fallback reports the ORIGINAL error message, not the marshal failure. je.Errors[i] = jsonError{Error: err.Error()} } else { var raw json.RawMessage = marshaled @@ -379,11 +386,14 @@ func (m *MultiError) MarshalJSON() ([]byte, error) { return nil, fmt.Errorf("failed to marshal MultiError: %v", err) } - // Remove trailing newline - result := buf.Bytes() - if len(result) > 0 && result[len(result)-1] == '\n' { - result = result[:len(result)-1] + // Copy out of buf's backing array before returning buf to pool. + raw := buf.Bytes() + if len(raw) > 0 && raw[len(raw)-1] == '\n' { + raw = raw[:len(raw)-1] } + result := make([]byte, len(raw)) + copy(result, raw) + jsonBufferPool.Put(buf) return result, nil } diff --git a/vendor/github.com/olekukonko/errors/pool.go b/vendor/github.com/olekukonko/errors/pool.go index 37515aac..9dd057f6 100644 --- a/vendor/github.com/olekukonko/errors/pool.go +++ b/vendor/github.com/olekukonko/errors/pool.go @@ -1,4 +1,3 @@ -// pool.go package errors import ( @@ -42,11 +41,16 @@ func (ep *ErrorPool) Get() *Error { e := ep.pool.Get().(*Error) if e == nil { // Pool returned nil (unlikely due to New func, but handled for safety) ep.poolStats.misses.Add(1) - return &Error{ + e = &Error{ smallContext: [contextSize]contextItem{}, } + ep.setupCleanup(e) + return e } ep.poolStats.hits.Add(1) + // Register auto-cleanup so GC can return the error to the pool if the + // caller forgets to call Free(). If AutoFree is false this is a no-op. + ep.setupCleanup(e) return e } diff --git a/vendor/github.com/olekukonko/errors/pool_above_1_24.go b/vendor/github.com/olekukonko/errors/pool_above_1_24.go index 706550fd..26cd100b 100644 --- a/vendor/github.com/olekukonko/errors/pool_above_1_24.go +++ b/vendor/github.com/olekukonko/errors/pool_above_1_24.go @@ -5,20 +5,26 @@ package errors import "runtime" -// setupCleanup configures a cleanup function for an *Error to auto-return it to the pool. -// Only active for Go 1.24+; uses runtime.AddCleanup when autoFree is set and pooling is enabled. +// setupCleanup registers a runtime.AddCleanup callback that returns e to the +// pool when the GC determines e is unreachable — only when AutoFree is enabled. +// +// IMPORTANT: the cleanup argument must be e itself (passed as the third arg), +// NOT captured in the closure. Capturing e in the closure creates a strong +// reference from the cleanup to e, which prevents e from ever becoming +// unreachable and defeats the purpose of the cleanup entirely. func (ep *ErrorPool) setupCleanup(e *Error) { - if currentConfig.autoFree { - runtime.AddCleanup(e, func(_ *struct{}) { - if !currentConfig.disablePooling { - ep.Put(e) // Return to pool when cleaned up - } - }, nil) // No additional context needed + if !currentConfig.autoFree || currentConfig.disablePooling { + return } + runtime.AddCleanup(e, func(target *Error) { + if !currentConfig.disablePooling { + ep.Put(target) + } + }, e) } -// clearCleanup is a no-op for Go 1.24 and above. -// Cleanup is managed by runtime.AddCleanup; no explicit removal is required. -func (ep *ErrorPool) clearCleanup(e *Error) { - // No-op for Go 1.24+ -} +// clearCleanup is a no-op for Go 1.24+. +// runtime.AddCleanup does not support cancellation; the double-put risk is +// mitigated by Free() resetting the error before Put, making a second Put +// of an already-reset error safe (it just returns a clean object to the pool). +func (ep *ErrorPool) clearCleanup(_ *Error) {} diff --git a/vendor/github.com/olekukonko/errors/pool_below_1_24.go b/vendor/github.com/olekukonko/errors/pool_below_1_24.go index 3c94209f..688017eb 100644 --- a/vendor/github.com/olekukonko/errors/pool_below_1_24.go +++ b/vendor/github.com/olekukonko/errors/pool_below_1_24.go @@ -5,20 +5,26 @@ package errors import "runtime" -// setupCleanup configures a finalizer for an *Error to auto-return it to the pool. -// Only active for Go versions < 1.24; enables automatic cleanup when autoFree is set and pooling is enabled. +// setupCleanup registers a finalizer that returns e to the pool when the GC +// collects it — only when AutoFree is enabled. +// +// Finalizer limitation: the GC may not collect the object promptly, and +// finalizers run in a separate goroutine. This is acceptable for pool returns +// since Put() is safe to call from any goroutine and Reset() is idempotent. func (ep *ErrorPool) setupCleanup(e *Error) { - if currentConfig.autoFree { - runtime.SetFinalizer(e, func(e *Error) { - if !currentConfig.disablePooling { - ep.Put(e) // Return to pool when garbage collected - } - }) + if !currentConfig.autoFree || currentConfig.disablePooling { + return } + runtime.SetFinalizer(e, func(target *Error) { + if !currentConfig.disablePooling { + ep.Put(target) + } + }) } -// clearCleanup removes any finalizer set on an *Error. -// Only active for Go versions < 1.24; ensures no cleanup action occurs on garbage collection. +// clearCleanup removes the finalizer so explicit Free() calls do not race +// with a pending GC-triggered pool return (double-put). +// This is the correct approach for pre-1.24 Go where finalizers can be cleared. func (ep *ErrorPool) clearCleanup(e *Error) { - runtime.SetFinalizer(e, nil) // Disable finalizer + runtime.SetFinalizer(e, nil) } diff --git a/vendor/github.com/olekukonko/errors/retry.go b/vendor/github.com/olekukonko/errors/retry.go index 6d6df387..83ba0649 100644 --- a/vendor/github.com/olekukonko/errors/retry.go +++ b/vendor/github.com/olekukonko/errors/retry.go @@ -198,7 +198,7 @@ func (r *Retry) ExecuteContext(ctx context.Context, fn func() error) error { break } - // --- Calculate and apply delay --- + // Calculate and apply delay currentDelay := r.backoff.Backoff(attempt, r.delay) if r.maxDelay > 0 && currentDelay > r.maxDelay { // Check maxDelay > 0 before capping currentDelay = r.maxDelay @@ -209,7 +209,7 @@ func (r *Retry) ExecuteContext(ctx context.Context, fn func() error) error { if currentDelay < 0 { // Ensure delay isn't negative after jitter currentDelay = 0 } - // --- Wait for the delay or context cancellation --- + // Wait for the delay or context cancellation select { case <-execCtx.Done(): // If context is cancelled during the wait, return the context error diff --git a/vendor/github.com/olekukonko/errors/sentinel.go b/vendor/github.com/olekukonko/errors/sentinel.go new file mode 100644 index 00000000..9ce4eabb --- /dev/null +++ b/vendor/github.com/olekukonko/errors/sentinel.go @@ -0,0 +1,135 @@ +// Comparable, immutable sentinel errors for package-level error variables. +// +// Relationship to errmgr.Define + +// The errmgr subpackage provides a PARAMETERISED error factory: +// +// var ErrDefined = errmgr.Define("ErrTimeout", "operation timed out after %s: %s") +// err := ErrDefined.New("5s", "dial failed") // produces a formatted *Error each call +// +// That is for creating new error instances from a template at call sites. +// +// errors.Const (this file) creates a STATIC SENTINEL — a single stable pointer +// stored once as a package-level variable and compared with errors.Is: +// +// var ErrNotFound = errors.Const("not_found", "resource not found") +// +// if errors.Is(err, ErrNotFound) { ... } // pointer equality, always correct +// +// Use errmgr.Define when you need to produce many errors from a format template. +// Use errors.Const when you need a fixed comparable value for Is/switch matching. + +package errors + +import ( + "encoding/json" + "fmt" + "log/slog" +) + +// Sentinel is a comparable, immutable error value safe to store as a +// package-level variable and match with errors.Is or a type switch. +// +// Unlike Named(), which returns a new *Error instance on every call (making +// pointer equality unreliable), each call to Const() returns a unique stable +// pointer. Two sentinels with identical name/msg are still distinct values +// unless they are the same pointer — intentional, to avoid accidental aliasing. +type Sentinel struct { + name string + msg string +} + +// Error implements the error interface. +func (s *Sentinel) Error() string { return s.msg } + +// Is reports whether target is the same sentinel (pointer equality). +// This satisfies the errors.Is contract. +func (s *Sentinel) Is(target error) bool { + t, ok := target.(*Sentinel) + return ok && s == t +} + +// As attempts to assign the sentinel to target if target is **Sentinel. +// Returns true if the assignment was made. +func (s *Sentinel) As(target any) bool { + if tp, ok := target.(**Sentinel); ok { + *tp = s + return true + } + return false +} + +// Unwrap returns nil — sentinels are root errors with no cause chain. +// Satisfies the errors.Unwrap contract. +func (s *Sentinel) Unwrap() error { return nil } + +// Name returns the sentinel's name, useful for logging and diagnostics. +func (s *Sentinel) Name() string { return s.name } + +// String returns a debug-friendly representation. +func (s *Sentinel) String() string { + return fmt.Sprintf("Sentinel(%s: %s)", s.name, s.msg) +} + +// LogValue implements slog.LogValuer so a Sentinel can be passed directly +// to any slog logging call and rendered as a structured group. +// +// Example: +// +// slog.Error("lookup failed", "err", ErrNotFound) +// // => err.error="resource not found", err.code="not_found" +func (s *Sentinel) LogValue() slog.Value { + return slog.GroupValue( + slog.String("error", s.msg), + slog.String("code", s.name), + ) +} + +// MarshalJSON serialises the sentinel to {"error":"...","code":"..."}. +func (s *Sentinel) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Error string `json:"error"` + Code string `json:"code"` + }{ + Error: s.msg, + Code: s.name, + }) +} + +// With returns a new *Error that wraps this sentinel as its cause and carries +// the additional message msg. Use this to add call-site context to a sentinel +// without losing the ability to match the original with errors.Is. +// +// Example: +// +// var ErrNotFound = errors.Const("not_found", "resource not found") +// +// // At call site: +// err := ErrNotFound.With("user 42 not found") +// errors.Is(err, ErrNotFound) // true — sentinel is in the cause chain +func (s *Sentinel) With(msg string) *Error { + e := New(msg) + e.cause = s + return e +} + +// Const creates a new sentinel error with the given name and message. +// Store the result as a package-level var; never call Const in a hot path. +// +// Example: +// +// var ( +// ErrNotFound = errors.Const("not_found", "resource not found") +// ErrForbidden = errors.Const("forbidden", "access denied") +// ErrBadRequest = errors.Const("bad_request", "invalid input") +// ) +// +// func handle(err error) { +// switch { +// case errors.Is(err, ErrNotFound): // 404 +// case errors.Is(err, ErrForbidden): // 403 +// } +// } +func Const(name, msg string) *Sentinel { + return &Sentinel{name: name, msg: msg} +} diff --git a/vendor/github.com/olekukonko/errors/utils.go b/vendor/github.com/olekukonko/errors/utils.go index bb6753df..f09d84c6 100644 --- a/vendor/github.com/olekukonko/errors/utils.go +++ b/vendor/github.com/olekukonko/errors/utils.go @@ -1,5 +1,3 @@ -// Package errors provides utility functions for error handling, including stack -// trace capture and function name extraction. package errors import ( @@ -11,28 +9,38 @@ import ( ) // captureStack captures a stack trace with the configured depth. -// Skip=0 captures the current call site; skips captureStack and its caller (+2 frames); thread-safe via stackPool. +// Immune to inlining: captures from frame 1 and trims by shifting within +// the same buffer so the pooled slice always retains its full capacity. func captureStack(skip int) []uintptr { buf := stackPool.Get().([]uintptr) buf = buf[:cap(buf)] - // +2 to skip captureStack and the immediate caller - n := runtime.Callers(skip+2, buf) + // Capture from frame 1 (skipping runtime.Callers itself). + // captureStack can never be inlined because it calls runtime.Callers, + // so buf[0] is always captureStack regardless of compiler inlining above. + n := runtime.Callers(1, buf) if n == 0 { stackPool.Put(buf) return nil } - // Create a new slice to return, avoiding direct use of pooled memory - stack := make([]uintptr, n) - copy(stack, buf[:n]) - stackPool.Put(buf) + // Trim leading internal frames in-place using copy, preserving the + // buffer's full capacity so the pool never fills with shrinking slices. + // skip+1: +1 for captureStack itself (always buf[0]). + trimmed := skip + 1 + if trimmed >= n { + stackPool.Put(buf) + return nil + } - return stack + length := n - trimmed + // Shift the useful frames to the start of buf — same backing array, + // same capacity, zero allocation. + copy(buf, buf[trimmed:n]) + return buf[:length] } // min returns the smaller of two integers. -// Simple helper for limiting stack trace size or other comparisons. func min(a, b int) int { if a < b { return a @@ -40,8 +48,7 @@ func min(a, b int) int { return b } -// clearMap removes all entries from a map. -// Helper function to reset map contents without reallocating. +// clearMap removes all entries from a map without reallocating it. func clearMap(m map[string]interface{}) { for k := range m { delete(m, k) @@ -49,12 +56,10 @@ func clearMap(m map[string]interface{}) { } // sqlNull detects if a value represents a SQL NULL type. -// Returns true for nil or invalid sql.Null* types (e.g., NullString, NullInt64); false otherwise. func sqlNull(v interface{}) bool { if v == nil { return true } - switch val := v.(type) { case sql.NullString: return !val.Valid @@ -71,8 +76,8 @@ func sqlNull(v interface{}) bool { } } -// getFuncName extracts the function name from an interface, typically a function or method. -// Returns "unknown" if the input is nil or invalid; trims leading dots from runtime name. +// getFuncName extracts the function name from an interface value. +// Returns "unknown" if the input is nil or invalid. func getFuncName(fn interface{}) string { if fn == nil { return "unknown" @@ -81,13 +86,28 @@ func getFuncName(fn interface{}) string { return strings.TrimPrefix(fullName, ".") } -// isInternalFrame determines if a stack frame is considered "internal". -// Returns true for frames from runtime, reflect, or this package’s subdirectories if FilterInternal is true. +// isInternalFrame reports whether a stack frame belongs to this library's +// internals and should be filtered from user-visible stack traces. +// +// Rules: +// - runtime.* and reflect.* are always internal. +// - _test.go files are NEVER internal: test functions must survive +// filtering so that assertions like "stack contains testing.tRunner" +// and "stack contains TestErrorTraceStackContent" can pass. +// - Source files under github.com/olekukonko/errors/ (errors.go, utils.go, +// helper.go, retry.go, multi_error.go) are internal. func isInternalFrame(frame runtime.Frame) bool { if strings.HasPrefix(frame.Function, "runtime.") || strings.HasPrefix(frame.Function, "reflect.") { return true } + // Exempt test files before the path-prefix check: errors_test.go lives + // at github.com/olekukonko/errors/errors_test.go which contains the + // "errors" suffix and would otherwise be incorrectly filtered. + if strings.HasSuffix(frame.File, "_test.go") { + return false + } + suffixes := []string{ "errors", "utils", @@ -95,10 +115,8 @@ func isInternalFrame(frame runtime.Frame) bool { "retry", "multi", } - - file := frame.File for _, v := range suffixes { - if strings.Contains(file, fmt.Sprintf("github.com/olekukonko/errors/%s", v)) { + if strings.Contains(frame.File, fmt.Sprintf("github.com/olekukonko/errors/%s", v)) { return true } } @@ -106,7 +124,6 @@ func isInternalFrame(frame runtime.Frame) bool { } // FormatError returns a formatted string representation of an error. -// Includes message, name, context, stack trace, and cause for *Error types; just message for others; "" if nil. func FormatError(err error) string { if err == nil { return "" @@ -138,13 +155,13 @@ func FormatError(err error) string { return sb.String() } -// Caller returns the file, line, and function name of the caller at the specified skip level. -// Skip=0 returns the caller of this function, 1 returns its caller, etc.; returns "unknown" if no caller found. +// Caller returns the file, line, and function name of the caller at skip level. +// Skip=0 returns the caller of this function, 1 returns its caller, etc. func Caller(skip int) (file string, line int, function string) { configMu.RLock() defer configMu.RUnlock() var pcs [1]uintptr - n := runtime.Callers(skip+2, pcs[:]) // +2 skips Caller and its immediate caller + n := runtime.Callers(skip+2, pcs[:]) if n == 0 { return "", 0, "unknown" } diff --git a/vendor/go.etcd.io/etcd/api/v3/version/version.go b/vendor/go.etcd.io/etcd/api/v3/version/version.go index 421b8c84..618f1f1b 100644 --- a/vendor/go.etcd.io/etcd/api/v3/version/version.go +++ b/vendor/go.etcd.io/etcd/api/v3/version/version.go @@ -26,7 +26,7 @@ import ( var ( // MinClusterVersion is the min cluster version this etcd binary is compatible with. MinClusterVersion = "3.0.0" - Version = "3.6.9" + Version = "3.6.10" APIVersion = "unknown" // Git SHA Value will be set during build diff --git a/vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv/server.go b/vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv/server.go index f3fe1f32..d6824028 100644 --- a/vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv/server.go +++ b/vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv/server.go @@ -364,7 +364,9 @@ func (n HTTPServer) MetricAttributes(server string, req *http.Request, statusCod if statusCode > 0 { num++ } - + if route == "" && req.Pattern != "" { + route = httpRoute(req.Pattern) + } if route != "" { num++ } diff --git a/vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/version.go b/vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/version.go index be860556..07a3376a 100644 --- a/vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/version.go +++ b/vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/version.go @@ -5,6 +5,6 @@ package otelmux // import "go.opentelemetry.io/contrib/instrumentation/github.co // Version is the current release version of the gorilla/mux instrumentation. func Version() string { - return "0.67.0" + return "0.68.0" // This string is updated by the pre_release.sh script during release } diff --git a/vendor/go.opentelemetry.io/otel/.golangci.yml b/vendor/go.opentelemetry.io/otel/.golangci.yml index d12c8920..db1f5510 100644 --- a/vendor/go.opentelemetry.io/otel/.golangci.yml +++ b/vendor/go.opentelemetry.io/otel/.golangci.yml @@ -17,6 +17,7 @@ linters: - ineffassign - misspell - modernize + - noctx - perfsprint - revive - staticcheck @@ -88,6 +89,16 @@ linters: deny: - pkg: go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal desc: Do not use cross-module internal packages. + semconv: + list-mode: lax + files: + - "!**/semconv/**" + - "!**/exporters/zipkin/**" + deny: + - pkg: go.opentelemetry.io/otel/semconv + desc: "Use go.opentelemetry.io/otel/semconv/v1.40.0 instead. If a newer semconv version has been released, update the depguard rule." + allow: + - go.opentelemetry.io/otel/semconv/v1.40.0 gocritic: disabled-checks: - appendAssign diff --git a/vendor/go.opentelemetry.io/otel/CHANGELOG.md b/vendor/go.opentelemetry.io/otel/CHANGELOG.md index ab726301..20edda44 100644 --- a/vendor/go.opentelemetry.io/otel/CHANGELOG.md +++ b/vendor/go.opentelemetry.io/otel/CHANGELOG.md @@ -11,6 +11,49 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm +## [1.43.0/0.65.0/0.19.0] 2026-04-02 + +### Added + +- Add `IsRandom` and `WithRandom` on `TraceFlags`, and `IsRandom` on `SpanContext` in `go.opentelemetry.io/otel/trace` for [W3C Trace Context Level 2 Random Trace ID Flag](https://www.w3.org/TR/trace-context-2/#random-trace-id-flag) support. (#8012) +- Add service detection with `WithService` in `go.opentelemetry.io/otel/sdk/resource`. (#7642) +- Add `DefaultWithContext` and `EnvironmentWithContext` in `go.opentelemetry.io/otel/sdk/resource` to support plumbing `context.Context` through default and environment detectors. (#8051) +- Support attributes with empty value (`attribute.EMPTY`) in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`. (#8038) +- Support attributes with empty value (`attribute.EMPTY`) in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`. (#8038) +- Support attributes with empty value (`attribute.EMPTY`) in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc`. (#8038) +- Support attributes with empty value (`attribute.EMPTY`) in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#8038) +- Support attributes with empty value (`attribute.EMPTY`) in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#8038) +- Support attributes with empty value (`attribute.EMPTY`) in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#8038) +- Support attributes with empty value (`attribute.EMPTY`) in `go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest`. (#8038) +- Add support for per-series start time tracking for cumulative metrics in `go.opentelemetry.io/otel/sdk/metric`. + Set `OTEL_GO_X_PER_SERIES_START_TIMESTAMPS=true` to enable. (#8060) +- Add `WithCardinalityLimitSelector` for metric reader for configuring cardinality limits specific to the instrument kind. (#7855) + +### Changed + +- Introduce the `EMPTY` Type in `go.opentelemetry.io/otel/attribute` to reflect that an empty value is now a valid value, with `INVALID` remaining as a deprecated alias of `EMPTY`. (#8038) +- Improve slice handling in `go.opentelemetry.io/otel/attribute` to optimize short slice values with fixed-size fast paths. (#8039) +- Improve performance of span metric recording in `go.opentelemetry.io/otel/sdk/trace` by returning early if self-observability is not enabled. (#8067) +- Improve formatting of metric data diffs in `go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest`. (#8073) + +### Deprecated + +- Deprecate `INVALID` in `go.opentelemetry.io/otel/attribute`. Use `EMPTY` instead. (#8038) + +### Fixed + +- Return spec-compliant `TraceIdRatioBased` description. This is a breaking behavioral change, but it is necessary to + make the implementation [spec-compliant](https://opentelemetry.io/docs/specs/otel/trace/sdk/#traceidratiobased). (#8027) +- Fix a race condition in `go.opentelemetry.io/otel/sdk/metric` where the lastvalue aggregation could collect the value 0 even when no zero-value measurements were recorded. (#8056) +- Limit HTTP response body to 4 MiB in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp` to mitigate excessive memory usage caused by a misconfigured or malicious server. + Responses exceeding the limit are treated as non-retryable errors. (#8108) +- Limit HTTP response body to 4 MiB in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` to mitigate excessive memory usage caused by a misconfigured or malicious server. + Responses exceeding the limit are treated as non-retryable errors. (#8108) +- Limit HTTP response body to 4 MiB in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp` to mitigate excessive memory usage caused by a misconfigured or malicious server. + Responses exceeding the limit are treated as non-retryable errors. (#8108) +- `WithHostID` detector in `go.opentelemetry.io/otel/sdk/resource` to use full path for `kenv` command on BSD. (#8113) +- Fix missing `request.GetBody` in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp` to correctly handle HTTP2 GOAWAY frame. (#8096) + ## [1.42.0/0.64.0/0.18.0/0.0.16] 2026-03-06 ### Added @@ -3576,7 +3619,8 @@ It contains api and sdk for trace and meter. - CircleCI build CI manifest files. - CODEOWNERS file to track owners of this project. -[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.42.0...HEAD +[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.43.0...HEAD +[1.43.0/0.65.0/0.19.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.43.0 [1.42.0/0.64.0/0.18.0/0.0.16]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.42.0 [1.41.0/0.63.0/0.17.0/0.0.15]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.41.0 [1.40.0/0.62.0/0.16.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.40.0 diff --git a/vendor/go.opentelemetry.io/otel/Makefile b/vendor/go.opentelemetry.io/otel/Makefile index 9f6e6b51..42466f2d 100644 --- a/vendor/go.opentelemetry.io/otel/Makefile +++ b/vendor/go.opentelemetry.io/otel/Makefile @@ -38,10 +38,14 @@ CROSSLINK = $(TOOLS)/crosslink $(TOOLS)/crosslink: PACKAGE=go.opentelemetry.io/build-tools/crosslink SEMCONVKIT = $(TOOLS)/semconvkit +SEMCONVKIT_FILES := $(sort $(shell find $(TOOLS_MOD_DIR)/semconvkit -type f)) $(TOOLS)/semconvkit: PACKAGE=go.opentelemetry.io/otel/$(TOOLS_MOD_DIR)/semconvkit +$(TOOLS)/semconvkit: $(SEMCONVKIT_FILES) VERIFYREADMES = $(TOOLS)/verifyreadmes +VERIFYREADMES_FILES := $(sort $(shell find $(TOOLS_MOD_DIR)/verifyreadmes -type f)) $(TOOLS)/verifyreadmes: PACKAGE=go.opentelemetry.io/otel/$(TOOLS_MOD_DIR)/verifyreadmes +$(TOOLS)/verifyreadmes: $(VERIFYREADMES_FILES) GOLANGCI_LINT = $(TOOLS)/golangci-lint $(TOOLS)/golangci-lint: PACKAGE=github.com/golangci/golangci-lint/v2/cmd/golangci-lint diff --git a/vendor/go.opentelemetry.io/otel/RELEASING.md b/vendor/go.opentelemetry.io/otel/RELEASING.md index 861756fd..6aff7548 100644 --- a/vendor/go.opentelemetry.io/otel/RELEASING.md +++ b/vendor/go.opentelemetry.io/otel/RELEASING.md @@ -4,7 +4,9 @@ Create a `Version Release` issue to track the release process. -## Semantic Convention Generation +## Semantic Convention Upgrade + +### Semantic Convention Generation New versions of the [OpenTelemetry Semantic Conventions] mean new versions of the `semconv` package need to be generated. The `semconv-generate` make target is used for this. @@ -22,6 +24,43 @@ make semconv-generate # Uses the exported TAG. This should create a new sub-package of [`semconv`](./semconv). Ensure things look correct before submitting a pull request to include the addition. +The `CHANGELOG.md` should also be updated to reflect the new changes: + +```md +- The `go.opentelemetry.io/otel/semconv/` package. The package contains semantic conventions from the `` version of the OpenTelemetry Semantic Conventions. See the [migration documentation](./semconv//MIGRATION.md) for information on how to upgrade from `go.opentelemetry.io/otel/semconv/`. (#PR_NUMBER) +``` + +> **Tip:** Change to the release and prior version to match the changes + +### Update semconv imports + +Once the new semconv module has been generated, update all semconv imports throughout the codebase to reference the new version: + +```go +// Before +semconv "go.opentelemetry.io/otel/semconv/v1.37.0" +"go.opentelemetry.io/otel/semconv/v1.37.0/otelconv" + + +// After +semconv "go.opentelemetry.io/otel/semconv/v1.39.0" +"go.opentelemetry.io/otel/semconv/v1.39.0/otelconv" +``` + +Once complete, run `make` to check for any compilation or test failures. + +#### Handling attribute changes + +Some semconv releases might add new attributes or impact attributes that are currently being used. Changes could stem from a simple renaming, to more complex changes like merging attributes and property values being changed. + +One should update the code to the new attributes that supersede the impacted ones, hence sticking to the semantic conventions. However, legacy attributes might still be emitted in accordance to the `OTEL_SEMCONV_STABILITY_OPT_IN` environment variable. + +For an example on how such migration might have to be tracked and performed, see issue [#7806](https://github.com/open-telemetry/opentelemetry-go/issues/7806). + +### Go contrib linter update + +Update [.golangci.yml](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/.golangci.yml) in [opentelemetry-go-contrib](https://github.com/open-telemetry/opentelemetry-go-contrib/) to mandate the new semconv version. + ## Breaking changes validation You can run `make gorelease` which runs [gorelease](https://pkg.go.dev/golang.org/x/exp/cmd/gorelease) to ensure that there are no unwanted changes made in the public API. diff --git a/vendor/go.opentelemetry.io/otel/attribute/encoder.go b/vendor/go.opentelemetry.io/otel/attribute/encoder.go index 6cc1a165..771dd69c 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/encoder.go +++ b/vendor/go.opentelemetry.io/otel/attribute/encoder.go @@ -53,7 +53,7 @@ var ( _ Encoder = &defaultAttrEncoder{} // encoderIDCounter is for generating IDs for other attribute encoders. - encoderIDCounter uint64 + encoderIDCounter atomic.Uint64 defaultEncoderOnce sync.Once defaultEncoderID = NewEncoderID() @@ -64,7 +64,7 @@ var ( // once per each type of attribute encoder. Preferably in init() or in var // definition. func NewEncoderID() EncoderID { - return EncoderID{value: atomic.AddUint64(&encoderIDCounter, 1)} + return EncoderID{value: encoderIDCounter.Add(1)} } // DefaultEncoder returns an attribute encoder that encodes attributes in such diff --git a/vendor/go.opentelemetry.io/otel/attribute/hash.go b/vendor/go.opentelemetry.io/otel/attribute/hash.go index 6aa69aea..b09caaa6 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/hash.go +++ b/vendor/go.opentelemetry.io/otel/attribute/hash.go @@ -27,6 +27,7 @@ const ( int64SliceID uint64 = 3762322556277578591 // "_[]int64" (little endian) float64SliceID uint64 = 7308324551835016539 // "[]double" (little endian) stringSliceID uint64 = 7453010373645655387 // "[]string" (little endian) + emptyID uint64 = 7305809155345288421 // "__empty_" (little endian) ) // hashKVs returns a new xxHash64 hash of kvs. @@ -80,7 +81,8 @@ func hashKV(h xxhash.Hash, kv KeyValue) xxhash.Hash { for i := 0; i < rv.Len(); i++ { h = h.String(rv.Index(i).String()) } - case INVALID: + case EMPTY: + h = h.Uint64(emptyID) default: // Logging is an alternative, but using the internal logger here // causes an import cycle so it is not done. diff --git a/vendor/go.opentelemetry.io/otel/attribute/internal/attribute.go b/vendor/go.opentelemetry.io/otel/attribute/internal/attribute.go index 7f5eae87..d9f51fa2 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/internal/attribute.go +++ b/vendor/go.opentelemetry.io/otel/attribute/internal/attribute.go @@ -11,80 +11,63 @@ import ( "reflect" ) -// BoolSliceValue converts a bool slice into an array with same elements as slice. -func BoolSliceValue(v []bool) any { - cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeFor[bool]())).Elem() - reflect.Copy(cp, reflect.ValueOf(v)) - return cp.Interface() +// sliceElem is the exact set of element types stored in attribute slice values. +// Using a closed set prevents accidental instantiations for unsupported types. +type sliceElem interface { + bool | int64 | float64 | string } -// Int64SliceValue converts an int64 slice into an array with same elements as slice. -func Int64SliceValue(v []int64) any { - cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeFor[int64]())).Elem() - reflect.Copy(cp, reflect.ValueOf(v)) - return cp.Interface() -} - -// Float64SliceValue converts a float64 slice into an array with same elements as slice. -func Float64SliceValue(v []float64) any { - cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeFor[float64]())).Elem() - reflect.Copy(cp, reflect.ValueOf(v)) - return cp.Interface() -} +// SliceValue converts a slice into an array with the same elements. +func SliceValue[T sliceElem](v []T) any { + // Keep only the common tiny-slice cases out of reflection. Extending this + // much further increases code size for diminishing benefit while larger + // slices still need the generic reflective path to preserve comparability. + // This matches the short lengths that show up most often in local + // benchmarks and semantic convention examples while leaving larger, less + // predictable slices on the generic reflective path. + switch len(v) { + case 0: + return [0]T{} + case 1: + return [1]T{v[0]} + case 2: + return [2]T{v[0], v[1]} + case 3: + return [3]T{v[0], v[1], v[2]} + } -// StringSliceValue converts a string slice into an array with same elements as slice. -func StringSliceValue(v []string) any { - cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeFor[string]())).Elem() - reflect.Copy(cp, reflect.ValueOf(v)) - return cp.Interface() + return sliceValueReflect(v) } -// AsBoolSlice converts a bool array into a slice into with same elements as array. -func AsBoolSlice(v any) []bool { - rv := reflect.ValueOf(v) - if rv.Type().Kind() != reflect.Array { - return nil +// AsSlice converts an array into a slice with the same elements. +func AsSlice[T sliceElem](v any) []T { + // Mirror the small fixed-array fast path used by SliceValue. + switch a := v.(type) { + case [0]T: + return []T{} + case [1]T: + return []T{a[0]} + case [2]T: + return []T{a[0], a[1]} + case [3]T: + return []T{a[0], a[1], a[2]} } - cpy := make([]bool, rv.Len()) - if len(cpy) > 0 { - _ = reflect.Copy(reflect.ValueOf(cpy), rv) - } - return cpy -} -// AsInt64Slice converts an int64 array into a slice into with same elements as array. -func AsInt64Slice(v any) []int64 { - rv := reflect.ValueOf(v) - if rv.Type().Kind() != reflect.Array { - return nil - } - cpy := make([]int64, rv.Len()) - if len(cpy) > 0 { - _ = reflect.Copy(reflect.ValueOf(cpy), rv) - } - return cpy + return asSliceReflect[T](v) } -// AsFloat64Slice converts a float64 array into a slice into with same elements as array. -func AsFloat64Slice(v any) []float64 { - rv := reflect.ValueOf(v) - if rv.Type().Kind() != reflect.Array { - return nil - } - cpy := make([]float64, rv.Len()) - if len(cpy) > 0 { - _ = reflect.Copy(reflect.ValueOf(cpy), rv) - } - return cpy +func sliceValueReflect[T sliceElem](v []T) any { + cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeFor[T]())).Elem() + reflect.Copy(cp, reflect.ValueOf(v)) + return cp.Interface() } -// AsStringSlice converts a string array into a slice into with same elements as array. -func AsStringSlice(v any) []string { +func asSliceReflect[T sliceElem](v any) []T { rv := reflect.ValueOf(v) - if rv.Type().Kind() != reflect.Array { + if !rv.IsValid() || rv.Kind() != reflect.Array || rv.Type().Elem() != reflect.TypeFor[T]() { return nil } - cpy := make([]string, rv.Len()) + cpy := make([]T, rv.Len()) if len(cpy) > 0 { _ = reflect.Copy(reflect.ValueOf(cpy), rv) } diff --git a/vendor/go.opentelemetry.io/otel/attribute/kv.go b/vendor/go.opentelemetry.io/otel/attribute/kv.go index 8c6928ca..0cc36801 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/kv.go +++ b/vendor/go.opentelemetry.io/otel/attribute/kv.go @@ -15,7 +15,7 @@ type KeyValue struct { // Valid reports whether kv is a valid OpenTelemetry attribute. func (kv KeyValue) Valid() bool { - return kv.Key.Defined() && kv.Value.Type() != INVALID + return kv.Key.Defined() } // Bool creates a KeyValue with a BOOL Value type. diff --git a/vendor/go.opentelemetry.io/otel/attribute/type_string.go b/vendor/go.opentelemetry.io/otel/attribute/type_string.go index 24f1fa37..6c04448d 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/type_string.go +++ b/vendor/go.opentelemetry.io/otel/attribute/type_string.go @@ -8,7 +8,7 @@ func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. var x [1]struct{} - _ = x[INVALID-0] + _ = x[EMPTY-0] _ = x[BOOL-1] _ = x[INT64-2] _ = x[FLOAT64-3] @@ -19,9 +19,9 @@ func _() { _ = x[STRINGSLICE-8] } -const _Type_name = "INVALIDBOOLINT64FLOAT64STRINGBOOLSLICEINT64SLICEFLOAT64SLICESTRINGSLICE" +const _Type_name = "EMPTYBOOLINT64FLOAT64STRINGBOOLSLICEINT64SLICEFLOAT64SLICESTRINGSLICE" -var _Type_index = [...]uint8{0, 7, 11, 16, 23, 29, 38, 48, 60, 71} +var _Type_index = [...]uint8{0, 5, 9, 14, 21, 27, 36, 46, 58, 69} func (i Type) String() string { idx := int(i) - 0 diff --git a/vendor/go.opentelemetry.io/otel/attribute/value.go b/vendor/go.opentelemetry.io/otel/attribute/value.go index 5931e712..db04b132 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/value.go +++ b/vendor/go.opentelemetry.io/otel/attribute/value.go @@ -6,7 +6,6 @@ package attribute // import "go.opentelemetry.io/otel/attribute" import ( "encoding/json" "fmt" - "reflect" "strconv" attribute "go.opentelemetry.io/otel/attribute/internal" @@ -18,6 +17,8 @@ import ( type Type int // nolint: revive // redefines builtin Type. // Value represents the value part in key-value pairs. +// +// Note that the zero value is a valid empty value. type Value struct { vtype Type numeric uint64 @@ -26,8 +27,8 @@ type Value struct { } const ( - // INVALID is used for a Value with no value set. - INVALID Type = iota + // EMPTY is used for a Value with no value set. + EMPTY Type = iota // BOOL is a boolean Type Value. BOOL // INT64 is a 64-bit signed integral Type Value. @@ -44,6 +45,10 @@ const ( FLOAT64SLICE // STRINGSLICE is a slice of strings Type Value. STRINGSLICE + // INVALID is used for a Value with no value set. + // + // Deprecated: Use EMPTY instead as an empty value is a valid value. + INVALID = EMPTY ) // BoolValue creates a BOOL Value. @@ -56,7 +61,7 @@ func BoolValue(v bool) Value { // BoolSliceValue creates a BOOLSLICE Value. func BoolSliceValue(v []bool) Value { - return Value{vtype: BOOLSLICE, slice: attribute.BoolSliceValue(v)} + return Value{vtype: BOOLSLICE, slice: attribute.SliceValue(v)} } // IntValue creates an INT64 Value. @@ -64,16 +69,30 @@ func IntValue(v int) Value { return Int64Value(int64(v)) } -// IntSliceValue creates an INTSLICE Value. +// IntSliceValue creates an INT64SLICE Value. func IntSliceValue(v []int) Value { - cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeFor[int64]())) - for i, val := range v { - cp.Elem().Index(i).SetInt(int64(val)) - } - return Value{ - vtype: INT64SLICE, - slice: cp.Elem().Interface(), + val := Value{vtype: INT64SLICE} + + // Avoid the common tiny-slice cases from allocating a new slice. + switch len(v) { + case 0: + val.slice = [0]int64{} + case 1: + val.slice = [1]int64{int64(v[0])} + case 2: + val.slice = [2]int64{int64(v[0]), int64(v[1])} + case 3: + val.slice = [3]int64{int64(v[0]), int64(v[1]), int64(v[2])} + default: + // Fallback to a new slice for larger slices. + cp := make([]int64, len(v)) + for i, val := range v { + cp[i] = int64(val) + } + val.slice = attribute.SliceValue(cp) } + + return val } // Int64Value creates an INT64 Value. @@ -86,7 +105,7 @@ func Int64Value(v int64) Value { // Int64SliceValue creates an INT64SLICE Value. func Int64SliceValue(v []int64) Value { - return Value{vtype: INT64SLICE, slice: attribute.Int64SliceValue(v)} + return Value{vtype: INT64SLICE, slice: attribute.SliceValue(v)} } // Float64Value creates a FLOAT64 Value. @@ -99,7 +118,7 @@ func Float64Value(v float64) Value { // Float64SliceValue creates a FLOAT64SLICE Value. func Float64SliceValue(v []float64) Value { - return Value{vtype: FLOAT64SLICE, slice: attribute.Float64SliceValue(v)} + return Value{vtype: FLOAT64SLICE, slice: attribute.SliceValue(v)} } // StringValue creates a STRING Value. @@ -112,7 +131,7 @@ func StringValue(v string) Value { // StringSliceValue creates a STRINGSLICE Value. func StringSliceValue(v []string) Value { - return Value{vtype: STRINGSLICE, slice: attribute.StringSliceValue(v)} + return Value{vtype: STRINGSLICE, slice: attribute.SliceValue(v)} } // Type returns a type of the Value. @@ -136,7 +155,7 @@ func (v Value) AsBoolSlice() []bool { } func (v Value) asBoolSlice() []bool { - return attribute.AsBoolSlice(v.slice) + return attribute.AsSlice[bool](v.slice) } // AsInt64 returns the int64 value. Make sure that the Value's type is @@ -155,7 +174,7 @@ func (v Value) AsInt64Slice() []int64 { } func (v Value) asInt64Slice() []int64 { - return attribute.AsInt64Slice(v.slice) + return attribute.AsSlice[int64](v.slice) } // AsFloat64 returns the float64 value. Make sure that the Value's @@ -174,7 +193,7 @@ func (v Value) AsFloat64Slice() []float64 { } func (v Value) asFloat64Slice() []float64 { - return attribute.AsFloat64Slice(v.slice) + return attribute.AsSlice[float64](v.slice) } // AsString returns the string value. Make sure that the Value's type @@ -193,7 +212,7 @@ func (v Value) AsStringSlice() []string { } func (v Value) asStringSlice() []string { - return attribute.AsStringSlice(v.slice) + return attribute.AsSlice[string](v.slice) } type unknownValueType struct{} @@ -217,6 +236,8 @@ func (v Value) AsInterface() any { return v.stringly case STRINGSLICE: return v.asStringSlice() + case EMPTY: + return nil } return unknownValueType{} } @@ -252,6 +273,8 @@ func (v Value) Emit() string { return string(j) case STRING: return v.stringly + case EMPTY: + return "" default: return "unknown" } diff --git a/vendor/go.opentelemetry.io/otel/dependencies.Dockerfile b/vendor/go.opentelemetry.io/otel/dependencies.Dockerfile index f0cc942b..7a9b3c05 100644 --- a/vendor/go.opentelemetry.io/otel/dependencies.Dockerfile +++ b/vendor/go.opentelemetry.io/otel/dependencies.Dockerfile @@ -1,4 +1,4 @@ # This is a renovate-friendly source of Docker images. FROM python:3.13.6-slim-bullseye@sha256:e98b521460ee75bca92175c16247bdf7275637a8faaeb2bcfa19d879ae5c4b9a AS python -FROM otel/weaver:v0.21.2@sha256:2401de985c38bdb98b43918e2f43aa36b2afed4aa5669ac1c1de0a17301cd36d AS weaver +FROM otel/weaver:v0.22.1@sha256:33ae522ae4b71c1c562563c1d81f46aa0f79f088a0873199143a1f11ac30e5c9 AS weaver FROM avtodev/markdown-lint:v1@sha256:6aeedc2f49138ce7a1cd0adffc1b1c0321b841dc2102408967d9301c031949ee AS markdown diff --git a/vendor/go.opentelemetry.io/otel/trace/trace.go b/vendor/go.opentelemetry.io/otel/trace/trace.go index 96c06ec3..e3d103c4 100644 --- a/vendor/go.opentelemetry.io/otel/trace/trace.go +++ b/vendor/go.opentelemetry.io/otel/trace/trace.go @@ -196,6 +196,20 @@ func (tf TraceFlags) WithSampled(sampled bool) TraceFlags { // nolint:revive // return tf &^ FlagsSampled } +// IsRandom reports whether the random bit is set in the TraceFlags. +func (tf TraceFlags) IsRandom() bool { + return tf&FlagsRandom == FlagsRandom +} + +// WithRandom sets the random bit in a new copy of the TraceFlags. +func (tf TraceFlags) WithRandom(random bool) TraceFlags { // nolint:revive // random is not a control flag. + if random { + return tf | FlagsRandom + } + + return tf &^ FlagsRandom +} + // MarshalJSON implements a custom marshal function to encode TraceFlags // as a hex string. func (tf TraceFlags) MarshalJSON() ([]byte, error) { @@ -322,6 +336,11 @@ func (sc SpanContext) IsSampled() bool { return sc.traceFlags.IsSampled() } +// IsRandom reports whether the random bit is set in the SpanContext's TraceFlags. +func (sc SpanContext) IsRandom() bool { + return sc.traceFlags.IsRandom() +} + // WithTraceFlags returns a new SpanContext with the TraceFlags replaced. func (sc SpanContext) WithTraceFlags(flags TraceFlags) SpanContext { return SpanContext{ diff --git a/vendor/go.opentelemetry.io/otel/version.go b/vendor/go.opentelemetry.io/otel/version.go index 2dae06f2..1db4f47e 100644 --- a/vendor/go.opentelemetry.io/otel/version.go +++ b/vendor/go.opentelemetry.io/otel/version.go @@ -5,5 +5,5 @@ package otel // import "go.opentelemetry.io/otel" // Version is the current release version of OpenTelemetry in use. func Version() string { - return "1.42.0" + return "1.43.0" } diff --git a/vendor/go.opentelemetry.io/otel/versions.yaml b/vendor/go.opentelemetry.io/otel/versions.yaml index 6c634ef3..bcc6ee78 100644 --- a/vendor/go.opentelemetry.io/otel/versions.yaml +++ b/vendor/go.opentelemetry.io/otel/versions.yaml @@ -3,7 +3,7 @@ module-sets: stable-v1: - version: v1.42.0 + version: v1.43.0 modules: - go.opentelemetry.io/otel - go.opentelemetry.io/otel/bridge/opencensus @@ -22,11 +22,11 @@ module-sets: - go.opentelemetry.io/otel/sdk/metric - go.opentelemetry.io/otel/trace experimental-metrics: - version: v0.64.0 + version: v0.65.0 modules: - go.opentelemetry.io/otel/exporters/prometheus experimental-logs: - version: v0.18.0 + version: v0.19.0 modules: - go.opentelemetry.io/otel/log - go.opentelemetry.io/otel/log/logtest @@ -64,3 +64,6 @@ modules: go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp: version-refs: - ./internal/version.go + go.opentelemetry.io/otel/exporters/stdout/stdoutlog: + version-refs: + - ./internal/version.go diff --git a/vendor/go.uber.org/zap/CHANGELOG.md b/vendor/go.uber.org/zap/CHANGELOG.md index 86e7e6f9..53848733 100644 --- a/vendor/go.uber.org/zap/CHANGELOG.md +++ b/vendor/go.uber.org/zap/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 1.28.0 (27 Apr 2026) +Enhancements: +* [#1534][]: Add `zapcore.CheckPreWriteHook` and `CheckedEntry.Before` method for transforming entries before they are written to any Cores. + ## 1.27.1 (19 Nov 2025) Enhancements: * [#1501][]: prevent `Object` from panicking on nils diff --git a/vendor/go.uber.org/zap/zapcore/entry.go b/vendor/go.uber.org/zap/zapcore/entry.go index 841752f2..e1fc07a1 100644 --- a/vendor/go.uber.org/zap/zapcore/entry.go +++ b/vendor/go.uber.org/zap/zapcore/entry.go @@ -201,6 +201,14 @@ func (a CheckWriteAction) OnWrite(ce *CheckedEntry, _ []Field) { var _ CheckWriteHook = CheckWriteAction(0) +// CheckPreWriteHook is a function that transforms an Entry and its Fields +// before they are written to cores. Register one on a CheckedEntry with the +// Before method. +// +// Pre-write hooks run in the order they were added, before any Core's Write +// method is called. They may modify the Entry and Fields freely. +type CheckPreWriteHook func(Entry, []Field) (Entry, []Field) + // CheckedEntry is an Entry together with a collection of Cores that have // already agreed to log it. // @@ -213,6 +221,7 @@ type CheckedEntry struct { dirty bool // best-effort detection of pool misuse after CheckWriteHook cores []Core + before []CheckPreWriteHook } func (ce *CheckedEntry) reset() { @@ -225,6 +234,10 @@ func (ce *CheckedEntry) reset() { ce.cores[i] = nil } ce.cores = ce.cores[:0] + for i := range ce.before { + ce.before[i] = nil + } + ce.before = ce.before[:0] } // Write writes the entry to the stored Cores, returns any errors, and returns @@ -253,9 +266,14 @@ func (ce *CheckedEntry) Write(fields ...Field) { } ce.dirty = true + ent := ce.Entry + for i := range ce.before { + ent, fields = ce.before[i](ent, fields) + } + var err error for i := range ce.cores { - err = multierr.Append(err, ce.cores[i].Write(ce.Entry, fields)) + err = multierr.Append(err, ce.cores[i].Write(ent, fields)) } if err != nil && ce.ErrorOutput != nil { _, _ = fmt.Fprintf( @@ -295,6 +313,18 @@ func (ce *CheckedEntry) Should(ent Entry, should CheckWriteAction) *CheckedEntry return ce.After(ent, should) } +// Before adds a pre-write hook that transforms the Entry and Fields before +// they are written to any registered Cores. Multiple hooks run in the order +// they were added. It's safe to call this on nil CheckedEntry references. +func (ce *CheckedEntry) Before(ent Entry, hook CheckPreWriteHook) *CheckedEntry { + if ce == nil { + ce = getCheckedEntry() + ce.Entry = ent + } + ce.before = append(ce.before, hook) + return ce +} + // After sets this CheckEntry's CheckWriteHook, which will be called after this // log entry has been written. It's safe to call this on nil CheckedEntry // references. diff --git a/vendor/golang.org/x/net/http2/hpack/tables.go b/vendor/golang.org/x/net/http2/hpack/tables.go index 8cbdf3f0..803fe517 100644 --- a/vendor/golang.org/x/net/http2/hpack/tables.go +++ b/vendor/golang.org/x/net/http2/hpack/tables.go @@ -6,6 +6,7 @@ package hpack import ( "fmt" + "strings" ) // headerFieldTable implements a list of HeaderFields. @@ -54,10 +55,16 @@ func (t *headerFieldTable) len() int { // addEntry adds a new entry. func (t *headerFieldTable) addEntry(f HeaderField) { + // Prevent f from escaping to the heap. + f2 := HeaderField{ + Name: strings.Clone(f.Name), + Value: strings.Clone(f.Value), + Sensitive: f.Sensitive, + } id := uint64(t.len()) + t.evictCount + 1 - t.byName[f.Name] = id - t.byNameValue[pairNameValue{f.Name, f.Value}] = id - t.ents = append(t.ents, f) + t.byName[f2.Name] = id + t.byNameValue[pairNameValue{f2.Name, f2.Value}] = id + t.ents = append(t.ents, f2) } // evictOldest evicts the n oldest entries in the table. diff --git a/vendor/golang.org/x/net/http2/transport.go b/vendor/golang.org/x/net/http2/transport.go index 2e9c2f6a..19553f10 100644 --- a/vendor/golang.org/x/net/http2/transport.go +++ b/vendor/golang.org/x/net/http2/transport.go @@ -718,9 +718,6 @@ func canRetryError(err error) bool { } func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*ClientConn, error) { - if t.transportTestHooks != nil { - return t.newClientConn(nil, singleUse, nil) - } host, _, err := net.SplitHostPort(addr) if err != nil { return nil, err @@ -2861,6 +2858,9 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error { var seenMaxConcurrentStreams bool err := f.ForeachSetting(func(s Setting) error { + if err := s.Valid(); err != nil { + return err + } switch s.ID { case SettingMaxFrameSize: cc.maxFrameSize = s.Val @@ -2892,9 +2892,6 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error { cc.henc.SetMaxDynamicTableSize(s.Val) cc.peerMaxHeaderTableSize = s.Val case SettingEnableConnectProtocol: - if err := s.Valid(); err != nil { - return err - } // If the peer wants to send us SETTINGS_ENABLE_CONNECT_PROTOCOL, // we require that it do so in the first SETTINGS frame. // diff --git a/vendor/golang.org/x/sys/windows/dll_windows.go b/vendor/golang.org/x/sys/windows/dll_windows.go index 3ca814f5..1157b06d 100644 --- a/vendor/golang.org/x/sys/windows/dll_windows.go +++ b/vendor/golang.org/x/sys/windows/dll_windows.go @@ -163,42 +163,7 @@ func (p *Proc) Addr() uintptr { // (according to the semantics of the specific function being called) before consulting // the error. The error will be guaranteed to contain windows.Errno. func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { - switch len(a) { - case 0: - return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0) - case 1: - return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0) - case 2: - return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0) - case 3: - return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2]) - case 4: - return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0) - case 5: - return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0) - case 6: - return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5]) - case 7: - return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0) - case 8: - return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0) - case 9: - return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]) - case 10: - return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0) - case 11: - return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0) - case 12: - return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]) - case 13: - return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0) - case 14: - return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0) - case 15: - return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14]) - default: - panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".") - } + return syscall.SyscallN(p.Addr(), a...) } // A LazyDLL implements access to a single DLL. diff --git a/vendor/golang.org/x/sys/windows/security_windows.go b/vendor/golang.org/x/sys/windows/security_windows.go index a8b0364c..6c955cea 100644 --- a/vendor/golang.org/x/sys/windows/security_windows.go +++ b/vendor/golang.org/x/sys/windows/security_windows.go @@ -1438,13 +1438,17 @@ func GetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformati } // GetNamedSecurityInfo queries the security information for a given named object and returns the self-relative security -// descriptor result on the Go heap. +// descriptor result on the Go heap. The security descriptor might be nil, even when err is nil, if the object exists +// but has no security descriptor. func GetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION) (sd *SECURITY_DESCRIPTOR, err error) { var winHeapSD *SECURITY_DESCRIPTOR err = getNamedSecurityInfo(objectName, objectType, securityInformation, nil, nil, nil, nil, &winHeapSD) if err != nil { return } + if winHeapSD == nil { + return nil, nil + } defer LocalFree(Handle(unsafe.Pointer(winHeapSD))) return winHeapSD.copySelfRelativeSecurityDescriptor(), nil } diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/client.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/client.pb.go index f8404817..382a9f00 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/client.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/client.pb.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC +// Copyright 2026 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -167,6 +167,63 @@ func (ClientLibraryDestination) EnumDescriptor() ([]byte, []int) { return file_google_api_client_proto_rawDescGZIP(), []int{1} } +// The behavior to take when the flow control limit is exceeded. +type FlowControlLimitExceededBehaviorProto int32 + +const ( + // Default behavior, system-defined. + FlowControlLimitExceededBehaviorProto_UNSET_BEHAVIOR FlowControlLimitExceededBehaviorProto = 0 + // Stop operation, raise error. + FlowControlLimitExceededBehaviorProto_THROW_EXCEPTION FlowControlLimitExceededBehaviorProto = 1 + // Pause operation until limit clears. + FlowControlLimitExceededBehaviorProto_BLOCK FlowControlLimitExceededBehaviorProto = 2 + // Continue operation, disregard limit. + FlowControlLimitExceededBehaviorProto_IGNORE FlowControlLimitExceededBehaviorProto = 3 +) + +// Enum value maps for FlowControlLimitExceededBehaviorProto. +var ( + FlowControlLimitExceededBehaviorProto_name = map[int32]string{ + 0: "UNSET_BEHAVIOR", + 1: "THROW_EXCEPTION", + 2: "BLOCK", + 3: "IGNORE", + } + FlowControlLimitExceededBehaviorProto_value = map[string]int32{ + "UNSET_BEHAVIOR": 0, + "THROW_EXCEPTION": 1, + "BLOCK": 2, + "IGNORE": 3, + } +) + +func (x FlowControlLimitExceededBehaviorProto) Enum() *FlowControlLimitExceededBehaviorProto { + p := new(FlowControlLimitExceededBehaviorProto) + *p = x + return p +} + +func (x FlowControlLimitExceededBehaviorProto) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (FlowControlLimitExceededBehaviorProto) Descriptor() protoreflect.EnumDescriptor { + return file_google_api_client_proto_enumTypes[2].Descriptor() +} + +func (FlowControlLimitExceededBehaviorProto) Type() protoreflect.EnumType { + return &file_google_api_client_proto_enumTypes[2] +} + +func (x FlowControlLimitExceededBehaviorProto) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use FlowControlLimitExceededBehaviorProto.Descriptor instead. +func (FlowControlLimitExceededBehaviorProto) EnumDescriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{2} +} + // Required information for every language. type CommonLanguageSettings struct { state protoimpl.MessageState @@ -181,6 +238,8 @@ type CommonLanguageSettings struct { // The destination where API teams want this client library to be published. Destinations []ClientLibraryDestination `protobuf:"varint,2,rep,packed,name=destinations,proto3,enum=google.api.ClientLibraryDestination" json:"destinations,omitempty"` // Configuration for which RPCs should be generated in the GAPIC client. + // + // Note: This field should not be used in most cases. SelectiveGapicGeneration *SelectiveGapicGeneration `protobuf:"bytes,3,opt,name=selective_gapic_generation,json=selectiveGapicGeneration,proto3" json:"selective_gapic_generation,omitempty"` } @@ -547,8 +606,9 @@ type JavaSettings struct { // Example of a YAML configuration:: // // publishing: - // java_settings: - // library_package: com.google.cloud.pubsub.v1 + // library_settings: + // java_settings: + // library_package: com.google.cloud.pubsub.v1 LibraryPackage string `protobuf:"bytes,1,opt,name=library_package,json=libraryPackage,proto3" json:"library_package,omitempty"` // Configure the Java class name to use instead of the service's for its // corresponding generated GAPIC client. Keys are fully-qualified @@ -679,6 +739,19 @@ type PhpSettings struct { // Some settings. Common *CommonLanguageSettings `protobuf:"bytes,1,opt,name=common,proto3" json:"common,omitempty"` + // The package name to use in Php. Clobbers the php_namespace option + // set in the protobuf. This should be used **only** by APIs + // who have already set the language_settings.php.package_name" field + // in gapic.yaml. API teams should use the protobuf php_namespace option + // where possible. + // + // Example of a YAML configuration:: + // + // publishing: + // library_settings: + // php_settings: + // library_package: Google\Cloud\PubSub\V1 + LibraryPackage string `protobuf:"bytes,2,opt,name=library_package,json=libraryPackage,proto3" json:"library_package,omitempty"` } func (x *PhpSettings) Reset() { @@ -720,6 +793,13 @@ func (x *PhpSettings) GetCommon() *CommonLanguageSettings { return nil } +func (x *PhpSettings) GetLibraryPackage() string { + if x != nil { + return x.LibraryPackage + } + return "" +} + // Settings for Python client libraries. type PythonSettings struct { state protoimpl.MessageState @@ -997,11 +1077,12 @@ type GoSettings struct { // service names and values are the name to be used for the service client // and call options. // - // publishing: + // Example: // - // go_settings: - // renamed_services: - // Publisher: TopicAdmin + // publishing: + // go_settings: + // renamed_services: + // Publisher: TopicAdmin RenamedServices map[string]string `protobuf:"bytes,2,rep,name=renamed_services,json=renamedServices,proto3" json:"renamed_services,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } @@ -1094,6 +1175,18 @@ type MethodSettings struct { // auto_populated_fields: // - request_id AutoPopulatedFields []string `protobuf:"bytes,3,rep,name=auto_populated_fields,json=autoPopulatedFields,proto3" json:"auto_populated_fields,omitempty"` + // Batching configuration for an API method in client libraries. + // + // Example of a YAML configuration: + // + // publishing: + // method_settings: + // - selector: google.example.v1.ExampleService.BatchCreateExample + // batching: + // element_count_threshold: 1000 + // request_byte_threshold: 100000000 + // delay_threshold_millis: 10 + Batching *BatchingConfigProto `protobuf:"bytes,4,opt,name=batching,proto3" json:"batching,omitempty"` } func (x *MethodSettings) Reset() { @@ -1149,8 +1242,17 @@ func (x *MethodSettings) GetAutoPopulatedFields() []string { return nil } +func (x *MethodSettings) GetBatching() *BatchingConfigProto { + if x != nil { + return x.Batching + } + return nil +} + // This message is used to configure the generation of a subset of the RPCs in // a service for client libraries. +// +// Note: This feature should not be used in most cases. type SelectiveGapicGeneration struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1214,6 +1316,257 @@ func (x *SelectiveGapicGeneration) GetGenerateOmittedAsInternal() bool { return false } +// `BatchingConfigProto` defines the batching configuration for an API method. +type BatchingConfigProto struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The thresholds which trigger a batched request to be sent. + Thresholds *BatchingSettingsProto `protobuf:"bytes,1,opt,name=thresholds,proto3" json:"thresholds,omitempty"` + // The request and response fields used in batching. + BatchDescriptor *BatchingDescriptorProto `protobuf:"bytes,2,opt,name=batch_descriptor,json=batchDescriptor,proto3" json:"batch_descriptor,omitempty"` +} + +func (x *BatchingConfigProto) Reset() { + *x = BatchingConfigProto{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchingConfigProto) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchingConfigProto) ProtoMessage() {} + +func (x *BatchingConfigProto) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchingConfigProto.ProtoReflect.Descriptor instead. +func (*BatchingConfigProto) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{13} +} + +func (x *BatchingConfigProto) GetThresholds() *BatchingSettingsProto { + if x != nil { + return x.Thresholds + } + return nil +} + +func (x *BatchingConfigProto) GetBatchDescriptor() *BatchingDescriptorProto { + if x != nil { + return x.BatchDescriptor + } + return nil +} + +// `BatchingSettingsProto` specifies a set of batching thresholds, each of +// which acts as a trigger to send a batch of messages as a request. At least +// one threshold must be positive nonzero. +type BatchingSettingsProto struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The number of elements of a field collected into a batch which, if + // exceeded, causes the batch to be sent. + ElementCountThreshold int32 `protobuf:"varint,1,opt,name=element_count_threshold,json=elementCountThreshold,proto3" json:"element_count_threshold,omitempty"` + // The aggregated size of the batched field which, if exceeded, causes the + // batch to be sent. This size is computed by aggregating the sizes of the + // request field to be batched, not of the entire request message. + RequestByteThreshold int64 `protobuf:"varint,2,opt,name=request_byte_threshold,json=requestByteThreshold,proto3" json:"request_byte_threshold,omitempty"` + // The duration after which a batch should be sent, starting from the addition + // of the first message to that batch. + DelayThreshold *durationpb.Duration `protobuf:"bytes,3,opt,name=delay_threshold,json=delayThreshold,proto3" json:"delay_threshold,omitempty"` + // The maximum number of elements collected in a batch that could be accepted + // by server. + ElementCountLimit int32 `protobuf:"varint,4,opt,name=element_count_limit,json=elementCountLimit,proto3" json:"element_count_limit,omitempty"` + // The maximum size of the request that could be accepted by server. + RequestByteLimit int32 `protobuf:"varint,5,opt,name=request_byte_limit,json=requestByteLimit,proto3" json:"request_byte_limit,omitempty"` + // The maximum number of elements allowed by flow control. + FlowControlElementLimit int32 `protobuf:"varint,6,opt,name=flow_control_element_limit,json=flowControlElementLimit,proto3" json:"flow_control_element_limit,omitempty"` + // The maximum size of data allowed by flow control. + FlowControlByteLimit int32 `protobuf:"varint,7,opt,name=flow_control_byte_limit,json=flowControlByteLimit,proto3" json:"flow_control_byte_limit,omitempty"` + // The behavior to take when the flow control limit is exceeded. + FlowControlLimitExceededBehavior FlowControlLimitExceededBehaviorProto `protobuf:"varint,8,opt,name=flow_control_limit_exceeded_behavior,json=flowControlLimitExceededBehavior,proto3,enum=google.api.FlowControlLimitExceededBehaviorProto" json:"flow_control_limit_exceeded_behavior,omitempty"` +} + +func (x *BatchingSettingsProto) Reset() { + *x = BatchingSettingsProto{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchingSettingsProto) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchingSettingsProto) ProtoMessage() {} + +func (x *BatchingSettingsProto) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchingSettingsProto.ProtoReflect.Descriptor instead. +func (*BatchingSettingsProto) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{14} +} + +func (x *BatchingSettingsProto) GetElementCountThreshold() int32 { + if x != nil { + return x.ElementCountThreshold + } + return 0 +} + +func (x *BatchingSettingsProto) GetRequestByteThreshold() int64 { + if x != nil { + return x.RequestByteThreshold + } + return 0 +} + +func (x *BatchingSettingsProto) GetDelayThreshold() *durationpb.Duration { + if x != nil { + return x.DelayThreshold + } + return nil +} + +func (x *BatchingSettingsProto) GetElementCountLimit() int32 { + if x != nil { + return x.ElementCountLimit + } + return 0 +} + +func (x *BatchingSettingsProto) GetRequestByteLimit() int32 { + if x != nil { + return x.RequestByteLimit + } + return 0 +} + +func (x *BatchingSettingsProto) GetFlowControlElementLimit() int32 { + if x != nil { + return x.FlowControlElementLimit + } + return 0 +} + +func (x *BatchingSettingsProto) GetFlowControlByteLimit() int32 { + if x != nil { + return x.FlowControlByteLimit + } + return 0 +} + +func (x *BatchingSettingsProto) GetFlowControlLimitExceededBehavior() FlowControlLimitExceededBehaviorProto { + if x != nil { + return x.FlowControlLimitExceededBehavior + } + return FlowControlLimitExceededBehaviorProto_UNSET_BEHAVIOR +} + +// `BatchingDescriptorProto` specifies the fields of the request message to be +// used for batching, and, optionally, the fields of the response message to be +// used for demultiplexing. +type BatchingDescriptorProto struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The repeated field in the request message to be aggregated by batching. + BatchedField string `protobuf:"bytes,1,opt,name=batched_field,json=batchedField,proto3" json:"batched_field,omitempty"` + // A list of the fields in the request message. Two requests will be batched + // together only if the values of every field specified in + // `request_discriminator_fields` is equal between the two requests. + DiscriminatorFields []string `protobuf:"bytes,2,rep,name=discriminator_fields,json=discriminatorFields,proto3" json:"discriminator_fields,omitempty"` + // Optional. When present, indicates the field in the response message to be + // used to demultiplex the response into multiple response messages, in + // correspondence with the multiple request messages originally batched + // together. + SubresponseField string `protobuf:"bytes,3,opt,name=subresponse_field,json=subresponseField,proto3" json:"subresponse_field,omitempty"` +} + +func (x *BatchingDescriptorProto) Reset() { + *x = BatchingDescriptorProto{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchingDescriptorProto) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchingDescriptorProto) ProtoMessage() {} + +func (x *BatchingDescriptorProto) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchingDescriptorProto.ProtoReflect.Descriptor instead. +func (*BatchingDescriptorProto) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{15} +} + +func (x *BatchingDescriptorProto) GetBatchedField() string { + if x != nil { + return x.BatchedField + } + return "" +} + +func (x *BatchingDescriptorProto) GetDiscriminatorFields() []string { + if x != nil { + return x.DiscriminatorFields + } + return nil +} + +func (x *BatchingDescriptorProto) GetSubresponseField() string { + if x != nil { + return x.SubresponseField + } + return "" +} + // Experimental features to be included during client library generation. // These fields will be deprecated once the feature graduates and is enabled // by default. @@ -1242,7 +1595,7 @@ type PythonSettings_ExperimentalFeatures struct { func (x *PythonSettings_ExperimentalFeatures) Reset() { *x = PythonSettings_ExperimentalFeatures{} if protoimpl.UnsafeEnabled { - mi := &file_google_api_client_proto_msgTypes[14] + mi := &file_google_api_client_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1255,7 +1608,7 @@ func (x *PythonSettings_ExperimentalFeatures) String() string { func (*PythonSettings_ExperimentalFeatures) ProtoMessage() {} func (x *PythonSettings_ExperimentalFeatures) ProtoReflect() protoreflect.Message { - mi := &file_google_api_client_proto_msgTypes[14] + mi := &file_google_api_client_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1320,7 +1673,7 @@ type MethodSettings_LongRunning struct { func (x *MethodSettings_LongRunning) Reset() { *x = MethodSettings_LongRunning{} if protoimpl.UnsafeEnabled { - mi := &file_google_api_client_proto_msgTypes[18] + mi := &file_google_api_client_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1333,7 +1686,7 @@ func (x *MethodSettings_LongRunning) String() string { func (*MethodSettings_LongRunning) ProtoMessage() {} func (x *MethodSettings_LongRunning) ProtoReflect() protoreflect.Message { - mi := &file_google_api_client_proto_msgTypes[18] + mi := &file_google_api_client_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1640,173 +1993,241 @@ var file_google_api_client_proto_rawDesc = []byte{ 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0x49, 0x0a, 0x0b, 0x50, 0x68, 0x70, 0x53, 0x65, 0x74, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0x72, 0x0a, 0x0b, 0x50, 0x68, 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x22, 0x87, 0x03, 0x0a, 0x0e, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, + 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x70, 0x61, 0x63, + 0x6b, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6c, 0x69, 0x62, 0x72, + 0x61, 0x72, 0x79, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x22, 0x87, 0x03, 0x0a, 0x0e, 0x50, + 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, + 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x64, 0x0a, 0x15, 0x65, 0x78, 0x70, + 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x6c, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x14, 0x65, 0x78, 0x70, 0x65, 0x72, + 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x1a, + 0xd2, 0x01, 0x0a, 0x14, 0x45, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, + 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x15, 0x72, 0x65, 0x73, 0x74, + 0x5f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x69, 0x6f, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x72, 0x65, 0x73, 0x74, 0x41, 0x73, 0x79, + 0x6e, 0x63, 0x49, 0x6f, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x45, 0x0a, 0x1f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x5f, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x69, 0x63, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x50, 0x79, + 0x74, 0x68, 0x6f, 0x6e, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x12, 0x40, 0x0a, 0x1c, 0x75, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x64, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x75, 0x6e, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x44, 0x69, 0x73, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x22, 0x4a, 0x0a, 0x0c, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x12, 0x64, 0x0a, 0x15, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, - 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x79, 0x74, - 0x68, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x65, - 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, - 0x52, 0x14, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x46, 0x65, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x1a, 0xd2, 0x01, 0x0a, 0x14, 0x45, 0x78, 0x70, 0x65, 0x72, - 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, - 0x31, 0x0a, 0x15, 0x72, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x69, 0x6f, - 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, - 0x72, 0x65, 0x73, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x49, 0x6f, 0x45, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x12, 0x45, 0x0a, 0x1f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x5f, 0x70, - 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x69, 0x63, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x5f, 0x65, 0x6e, - 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x69, 0x63, 0x54, 0x79, 0x70, - 0x65, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x40, 0x0a, 0x1c, 0x75, 0x6e, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, - 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x1a, 0x75, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x50, 0x61, 0x63, 0x6b, - 0x61, 0x67, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x4a, 0x0a, 0x0c, 0x4e, - 0x6f, 0x64, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, - 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, - 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0xae, 0x04, 0x0a, 0x0e, 0x44, 0x6f, 0x74, 0x6e, - 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, - 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x5a, 0x0a, 0x10, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, - 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, - 0x74, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x52, 0x65, 0x6e, - 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x0f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x12, 0x5d, 0x0a, 0x11, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x5f, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x74, 0x6e, 0x65, - 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, - 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x10, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x69, 0x67, - 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x38, - 0x0a, 0x18, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x16, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x16, 0x68, 0x61, 0x6e, 0x64, - 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x15, 0x68, 0x61, 0x6e, 0x64, 0x77, 0x72, - 0x69, 0x74, 0x74, 0x65, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x1a, - 0x42, 0x0a, 0x14, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x1a, 0x43, 0x0a, 0x15, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4a, 0x0a, 0x0c, 0x52, 0x75, 0x62, 0x79, - 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, - 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0xe4, 0x01, 0x0a, 0x0a, 0x47, 0x6f, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x22, 0xae, 0x04, 0x0a, 0x0e, 0x44, 0x6f, 0x74, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, - 0x56, 0x0a, 0x10, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x6f, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x1a, 0x42, 0x0a, 0x14, 0x52, 0x65, 0x6e, 0x61, 0x6d, - 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc2, 0x03, 0x0a, 0x0e, - 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a, - 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x49, 0x0a, 0x0c, 0x6c, 0x6f, - 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x26, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, - 0x74, 0x68, 0x6f, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x6f, 0x6e, - 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x6c, 0x6f, 0x6e, 0x67, 0x52, 0x75, - 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x32, 0x0a, 0x15, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x70, 0x6f, - 0x70, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x61, 0x75, 0x74, 0x6f, 0x50, 0x6f, 0x70, 0x75, 0x6c, 0x61, - 0x74, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x94, 0x02, 0x0a, 0x0b, 0x4c, 0x6f, - 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x47, 0x0a, 0x12, 0x69, 0x6e, 0x69, - 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x10, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x6f, 0x6c, 0x6c, 0x44, 0x65, 0x6c, - 0x61, 0x79, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, - 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x02, 0x52, 0x13, 0x70, 0x6f, 0x6c, 0x6c, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x75, 0x6c, 0x74, - 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x6f, - 0x6c, 0x6c, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x50, 0x6f, - 0x6c, 0x6c, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x47, 0x0a, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, - 0x5f, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x6f, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x22, 0x75, 0x0a, 0x18, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x47, 0x61, 0x70, - 0x69, 0x63, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, - 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, - 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, - 0x74, 0x65, 0x5f, 0x6f, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x73, 0x5f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x67, 0x65, - 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4f, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x41, 0x73, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2a, 0xa3, 0x01, 0x0a, 0x19, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x27, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, - 0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x4f, 0x52, 0x47, 0x41, 0x4e, 0x49, 0x5a, 0x41, - 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x4c, 0x4f, 0x55, 0x44, 0x10, 0x01, 0x12, 0x07, 0x0a, - 0x03, 0x41, 0x44, 0x53, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x48, 0x4f, 0x54, 0x4f, 0x53, - 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x54, 0x52, 0x45, 0x45, 0x54, 0x5f, 0x56, 0x49, 0x45, - 0x57, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x48, 0x4f, 0x50, 0x50, 0x49, 0x4e, 0x47, 0x10, - 0x05, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x45, 0x4f, 0x10, 0x06, 0x12, 0x11, 0x0a, 0x0d, 0x47, 0x45, - 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x56, 0x45, 0x5f, 0x41, 0x49, 0x10, 0x07, 0x2a, 0x67, 0x0a, - 0x18, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x44, 0x65, - 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x26, 0x43, 0x4c, 0x49, - 0x45, 0x4e, 0x54, 0x5f, 0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x44, 0x45, 0x53, 0x54, - 0x49, 0x4e, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x10, - 0x0a, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, 0x5f, 0x4d, 0x41, 0x4e, - 0x41, 0x47, 0x45, 0x52, 0x10, 0x14, 0x3a, 0x4a, 0x0a, 0x10, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, - 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, - 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9b, 0x08, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x3a, 0x43, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x68, 0x6f, - 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x43, 0x0a, 0x0c, 0x6f, 0x61, 0x75, 0x74, 0x68, - 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x3a, 0x44, 0x0a, 0x0b, - 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xc1, 0xba, 0xab, - 0xfa, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x42, 0x69, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x61, 0x70, 0x69, 0x42, 0x0b, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, - 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, - 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0xa2, 0x02, 0x04, 0x47, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x5a, 0x0a, 0x10, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x74, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x72, 0x65, 0x6e, 0x61, + 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x5d, 0x0a, 0x11, 0x72, + 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x74, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x10, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x67, + 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x18, 0x66, 0x6f, 0x72, 0x63, 0x65, + 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, + 0x73, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x66, 0x6f, 0x72, 0x63, 0x65, + 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, + 0x73, 0x12, 0x35, 0x0a, 0x16, 0x68, 0x61, 0x6e, 0x64, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, + 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x15, 0x68, 0x61, 0x6e, 0x64, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x1a, 0x42, 0x0a, 0x14, 0x52, 0x65, 0x6e, 0x61, + 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x43, 0x0a, 0x15, + 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x4a, 0x0a, 0x0c, 0x52, 0x75, 0x62, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0xe4, 0x01, + 0x0a, 0x0a, 0x47, 0x6f, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x56, 0x0a, 0x10, 0x72, 0x65, 0x6e, 0x61, + 0x6d, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x47, 0x6f, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, + 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x0f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x1a, 0x42, 0x0a, 0x14, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0xff, 0x03, 0x0a, 0x0e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x6f, 0x72, 0x12, 0x49, 0x0a, 0x0c, 0x6c, 0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, + 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, + 0x67, 0x52, 0x0b, 0x6c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x32, + 0x0a, 0x15, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x70, 0x6f, 0x70, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x61, + 0x75, 0x74, 0x6f, 0x50, 0x6f, 0x70, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, + 0x64, 0x73, 0x12, 0x3b, 0x0a, 0x08, 0x62, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x08, 0x62, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x1a, + 0x94, 0x02, 0x0a, 0x0b, 0x4c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, + 0x47, 0x0a, 0x12, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, + 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x50, + 0x6f, 0x6c, 0x6c, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x6f, 0x6c, 0x6c, + 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x13, 0x70, 0x6f, 0x6c, 0x6c, 0x44, 0x65, 0x6c, + 0x61, 0x79, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x0e, + 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x0c, 0x6d, 0x61, 0x78, 0x50, 0x6f, 0x6c, 0x6c, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x47, 0x0a, + 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x6f, 0x6c, 0x6c, 0x54, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x75, 0x0a, 0x18, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x47, 0x61, 0x70, 0x69, 0x63, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x12, 0x3f, 0x0a, 0x1c, + 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x73, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x19, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4f, 0x6d, 0x69, 0x74, + 0x74, 0x65, 0x64, 0x41, 0x73, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x22, 0xa8, 0x01, + 0x0a, 0x13, 0x42, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x41, 0x0a, 0x0a, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, + 0x6c, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x0a, 0x74, 0x68, + 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x73, 0x12, 0x4e, 0x0a, 0x10, 0x62, 0x61, 0x74, 0x63, + 0x68, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x42, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x0f, 0x62, 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x22, 0x9f, 0x04, 0x0a, 0x15, 0x42, 0x61, 0x74, + 0x63, 0x68, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x36, 0x0a, 0x17, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x15, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, + 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x42, 0x79, 0x74, 0x65, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, + 0x12, 0x42, 0x0a, 0x0f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, + 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x68, 0x72, 0x65, 0x73, + 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x11, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x62, 0x79, 0x74, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x79, 0x74, 0x65, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x12, 0x3b, 0x0a, 0x1a, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x5f, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, + 0x35, 0x0a, 0x17, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, + 0x62, 0x79, 0x74, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x14, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x42, 0x79, 0x74, + 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x81, 0x01, 0x0a, 0x24, 0x66, 0x6c, 0x6f, 0x77, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x65, 0x78, + 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x45, 0x78, 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x42, 0x65, 0x68, 0x61, 0x76, + 0x69, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x20, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x63, 0x65, 0x65, 0x64, + 0x65, 0x64, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x22, 0x9e, 0x01, 0x0a, 0x17, 0x42, + 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, + 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x64, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x62, + 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, + 0x69, 0x73, 0x63, 0x72, 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x64, 0x69, 0x73, 0x63, 0x72, + 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x2b, + 0x0a, 0x11, 0x73, 0x75, 0x62, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x73, 0x75, 0x62, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x2a, 0xa3, 0x01, 0x0a, 0x19, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x4f, 0x72, 0x67, + 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x27, 0x43, 0x4c, 0x49, + 0x45, 0x4e, 0x54, 0x5f, 0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x4f, 0x52, 0x47, 0x41, + 0x4e, 0x49, 0x5a, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x4c, 0x4f, 0x55, 0x44, 0x10, + 0x01, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x44, 0x53, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x48, + 0x4f, 0x54, 0x4f, 0x53, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x54, 0x52, 0x45, 0x45, 0x54, + 0x5f, 0x56, 0x49, 0x45, 0x57, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x48, 0x4f, 0x50, 0x50, + 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x45, 0x4f, 0x10, 0x06, 0x12, 0x11, + 0x0a, 0x0d, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x56, 0x45, 0x5f, 0x41, 0x49, 0x10, + 0x07, 0x2a, 0x67, 0x0a, 0x18, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, + 0x72, 0x79, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, + 0x26, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, + 0x44, 0x45, 0x53, 0x54, 0x49, 0x4e, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x47, 0x49, 0x54, + 0x48, 0x55, 0x42, 0x10, 0x0a, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, + 0x5f, 0x4d, 0x41, 0x4e, 0x41, 0x47, 0x45, 0x52, 0x10, 0x14, 0x2a, 0x67, 0x0a, 0x25, 0x46, 0x6c, + 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, + 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x53, 0x45, 0x54, 0x5f, 0x42, 0x45, 0x48, + 0x41, 0x56, 0x49, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x48, 0x52, 0x4f, 0x57, + 0x5f, 0x45, 0x58, 0x43, 0x45, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, + 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x47, 0x4e, 0x4f, 0x52, + 0x45, 0x10, 0x03, 0x3a, 0x4a, 0x0a, 0x10, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9b, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x3a, + 0x43, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x12, + 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x43, 0x0a, 0x0c, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x73, 0x63, + 0x6f, 0x70, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x61, + 0x75, 0x74, 0x68, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x3a, 0x44, 0x0a, 0x0b, 0x61, 0x70, 0x69, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xc1, 0xba, 0xab, 0xfa, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, + 0x69, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, + 0x69, 0x42, 0x0b, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x41, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, + 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0xa2, 0x02, 0x04, 0x47, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -1821,76 +2242,85 @@ func file_google_api_client_proto_rawDescGZIP() []byte { return file_google_api_client_proto_rawDescData } -var file_google_api_client_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_google_api_client_proto_msgTypes = make([]protoimpl.MessageInfo, 19) +var file_google_api_client_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_google_api_client_proto_msgTypes = make([]protoimpl.MessageInfo, 22) var file_google_api_client_proto_goTypes = []interface{}{ (ClientLibraryOrganization)(0), // 0: google.api.ClientLibraryOrganization (ClientLibraryDestination)(0), // 1: google.api.ClientLibraryDestination - (*CommonLanguageSettings)(nil), // 2: google.api.CommonLanguageSettings - (*ClientLibrarySettings)(nil), // 3: google.api.ClientLibrarySettings - (*Publishing)(nil), // 4: google.api.Publishing - (*JavaSettings)(nil), // 5: google.api.JavaSettings - (*CppSettings)(nil), // 6: google.api.CppSettings - (*PhpSettings)(nil), // 7: google.api.PhpSettings - (*PythonSettings)(nil), // 8: google.api.PythonSettings - (*NodeSettings)(nil), // 9: google.api.NodeSettings - (*DotnetSettings)(nil), // 10: google.api.DotnetSettings - (*RubySettings)(nil), // 11: google.api.RubySettings - (*GoSettings)(nil), // 12: google.api.GoSettings - (*MethodSettings)(nil), // 13: google.api.MethodSettings - (*SelectiveGapicGeneration)(nil), // 14: google.api.SelectiveGapicGeneration - nil, // 15: google.api.JavaSettings.ServiceClassNamesEntry - (*PythonSettings_ExperimentalFeatures)(nil), // 16: google.api.PythonSettings.ExperimentalFeatures - nil, // 17: google.api.DotnetSettings.RenamedServicesEntry - nil, // 18: google.api.DotnetSettings.RenamedResourcesEntry - nil, // 19: google.api.GoSettings.RenamedServicesEntry - (*MethodSettings_LongRunning)(nil), // 20: google.api.MethodSettings.LongRunning - (api.LaunchStage)(0), // 21: google.api.LaunchStage - (*durationpb.Duration)(nil), // 22: google.protobuf.Duration - (*descriptorpb.MethodOptions)(nil), // 23: google.protobuf.MethodOptions - (*descriptorpb.ServiceOptions)(nil), // 24: google.protobuf.ServiceOptions + (FlowControlLimitExceededBehaviorProto)(0), // 2: google.api.FlowControlLimitExceededBehaviorProto + (*CommonLanguageSettings)(nil), // 3: google.api.CommonLanguageSettings + (*ClientLibrarySettings)(nil), // 4: google.api.ClientLibrarySettings + (*Publishing)(nil), // 5: google.api.Publishing + (*JavaSettings)(nil), // 6: google.api.JavaSettings + (*CppSettings)(nil), // 7: google.api.CppSettings + (*PhpSettings)(nil), // 8: google.api.PhpSettings + (*PythonSettings)(nil), // 9: google.api.PythonSettings + (*NodeSettings)(nil), // 10: google.api.NodeSettings + (*DotnetSettings)(nil), // 11: google.api.DotnetSettings + (*RubySettings)(nil), // 12: google.api.RubySettings + (*GoSettings)(nil), // 13: google.api.GoSettings + (*MethodSettings)(nil), // 14: google.api.MethodSettings + (*SelectiveGapicGeneration)(nil), // 15: google.api.SelectiveGapicGeneration + (*BatchingConfigProto)(nil), // 16: google.api.BatchingConfigProto + (*BatchingSettingsProto)(nil), // 17: google.api.BatchingSettingsProto + (*BatchingDescriptorProto)(nil), // 18: google.api.BatchingDescriptorProto + nil, // 19: google.api.JavaSettings.ServiceClassNamesEntry + (*PythonSettings_ExperimentalFeatures)(nil), // 20: google.api.PythonSettings.ExperimentalFeatures + nil, // 21: google.api.DotnetSettings.RenamedServicesEntry + nil, // 22: google.api.DotnetSettings.RenamedResourcesEntry + nil, // 23: google.api.GoSettings.RenamedServicesEntry + (*MethodSettings_LongRunning)(nil), // 24: google.api.MethodSettings.LongRunning + (api.LaunchStage)(0), // 25: google.api.LaunchStage + (*durationpb.Duration)(nil), // 26: google.protobuf.Duration + (*descriptorpb.MethodOptions)(nil), // 27: google.protobuf.MethodOptions + (*descriptorpb.ServiceOptions)(nil), // 28: google.protobuf.ServiceOptions } var file_google_api_client_proto_depIdxs = []int32{ 1, // 0: google.api.CommonLanguageSettings.destinations:type_name -> google.api.ClientLibraryDestination - 14, // 1: google.api.CommonLanguageSettings.selective_gapic_generation:type_name -> google.api.SelectiveGapicGeneration - 21, // 2: google.api.ClientLibrarySettings.launch_stage:type_name -> google.api.LaunchStage - 5, // 3: google.api.ClientLibrarySettings.java_settings:type_name -> google.api.JavaSettings - 6, // 4: google.api.ClientLibrarySettings.cpp_settings:type_name -> google.api.CppSettings - 7, // 5: google.api.ClientLibrarySettings.php_settings:type_name -> google.api.PhpSettings - 8, // 6: google.api.ClientLibrarySettings.python_settings:type_name -> google.api.PythonSettings - 9, // 7: google.api.ClientLibrarySettings.node_settings:type_name -> google.api.NodeSettings - 10, // 8: google.api.ClientLibrarySettings.dotnet_settings:type_name -> google.api.DotnetSettings - 11, // 9: google.api.ClientLibrarySettings.ruby_settings:type_name -> google.api.RubySettings - 12, // 10: google.api.ClientLibrarySettings.go_settings:type_name -> google.api.GoSettings - 13, // 11: google.api.Publishing.method_settings:type_name -> google.api.MethodSettings + 15, // 1: google.api.CommonLanguageSettings.selective_gapic_generation:type_name -> google.api.SelectiveGapicGeneration + 25, // 2: google.api.ClientLibrarySettings.launch_stage:type_name -> google.api.LaunchStage + 6, // 3: google.api.ClientLibrarySettings.java_settings:type_name -> google.api.JavaSettings + 7, // 4: google.api.ClientLibrarySettings.cpp_settings:type_name -> google.api.CppSettings + 8, // 5: google.api.ClientLibrarySettings.php_settings:type_name -> google.api.PhpSettings + 9, // 6: google.api.ClientLibrarySettings.python_settings:type_name -> google.api.PythonSettings + 10, // 7: google.api.ClientLibrarySettings.node_settings:type_name -> google.api.NodeSettings + 11, // 8: google.api.ClientLibrarySettings.dotnet_settings:type_name -> google.api.DotnetSettings + 12, // 9: google.api.ClientLibrarySettings.ruby_settings:type_name -> google.api.RubySettings + 13, // 10: google.api.ClientLibrarySettings.go_settings:type_name -> google.api.GoSettings + 14, // 11: google.api.Publishing.method_settings:type_name -> google.api.MethodSettings 0, // 12: google.api.Publishing.organization:type_name -> google.api.ClientLibraryOrganization - 3, // 13: google.api.Publishing.library_settings:type_name -> google.api.ClientLibrarySettings - 15, // 14: google.api.JavaSettings.service_class_names:type_name -> google.api.JavaSettings.ServiceClassNamesEntry - 2, // 15: google.api.JavaSettings.common:type_name -> google.api.CommonLanguageSettings - 2, // 16: google.api.CppSettings.common:type_name -> google.api.CommonLanguageSettings - 2, // 17: google.api.PhpSettings.common:type_name -> google.api.CommonLanguageSettings - 2, // 18: google.api.PythonSettings.common:type_name -> google.api.CommonLanguageSettings - 16, // 19: google.api.PythonSettings.experimental_features:type_name -> google.api.PythonSettings.ExperimentalFeatures - 2, // 20: google.api.NodeSettings.common:type_name -> google.api.CommonLanguageSettings - 2, // 21: google.api.DotnetSettings.common:type_name -> google.api.CommonLanguageSettings - 17, // 22: google.api.DotnetSettings.renamed_services:type_name -> google.api.DotnetSettings.RenamedServicesEntry - 18, // 23: google.api.DotnetSettings.renamed_resources:type_name -> google.api.DotnetSettings.RenamedResourcesEntry - 2, // 24: google.api.RubySettings.common:type_name -> google.api.CommonLanguageSettings - 2, // 25: google.api.GoSettings.common:type_name -> google.api.CommonLanguageSettings - 19, // 26: google.api.GoSettings.renamed_services:type_name -> google.api.GoSettings.RenamedServicesEntry - 20, // 27: google.api.MethodSettings.long_running:type_name -> google.api.MethodSettings.LongRunning - 22, // 28: google.api.MethodSettings.LongRunning.initial_poll_delay:type_name -> google.protobuf.Duration - 22, // 29: google.api.MethodSettings.LongRunning.max_poll_delay:type_name -> google.protobuf.Duration - 22, // 30: google.api.MethodSettings.LongRunning.total_poll_timeout:type_name -> google.protobuf.Duration - 23, // 31: google.api.method_signature:extendee -> google.protobuf.MethodOptions - 24, // 32: google.api.default_host:extendee -> google.protobuf.ServiceOptions - 24, // 33: google.api.oauth_scopes:extendee -> google.protobuf.ServiceOptions - 24, // 34: google.api.api_version:extendee -> google.protobuf.ServiceOptions - 35, // [35:35] is the sub-list for method output_type - 35, // [35:35] is the sub-list for method input_type - 35, // [35:35] is the sub-list for extension type_name - 31, // [31:35] is the sub-list for extension extendee - 0, // [0:31] is the sub-list for field type_name + 4, // 13: google.api.Publishing.library_settings:type_name -> google.api.ClientLibrarySettings + 19, // 14: google.api.JavaSettings.service_class_names:type_name -> google.api.JavaSettings.ServiceClassNamesEntry + 3, // 15: google.api.JavaSettings.common:type_name -> google.api.CommonLanguageSettings + 3, // 16: google.api.CppSettings.common:type_name -> google.api.CommonLanguageSettings + 3, // 17: google.api.PhpSettings.common:type_name -> google.api.CommonLanguageSettings + 3, // 18: google.api.PythonSettings.common:type_name -> google.api.CommonLanguageSettings + 20, // 19: google.api.PythonSettings.experimental_features:type_name -> google.api.PythonSettings.ExperimentalFeatures + 3, // 20: google.api.NodeSettings.common:type_name -> google.api.CommonLanguageSettings + 3, // 21: google.api.DotnetSettings.common:type_name -> google.api.CommonLanguageSettings + 21, // 22: google.api.DotnetSettings.renamed_services:type_name -> google.api.DotnetSettings.RenamedServicesEntry + 22, // 23: google.api.DotnetSettings.renamed_resources:type_name -> google.api.DotnetSettings.RenamedResourcesEntry + 3, // 24: google.api.RubySettings.common:type_name -> google.api.CommonLanguageSettings + 3, // 25: google.api.GoSettings.common:type_name -> google.api.CommonLanguageSettings + 23, // 26: google.api.GoSettings.renamed_services:type_name -> google.api.GoSettings.RenamedServicesEntry + 24, // 27: google.api.MethodSettings.long_running:type_name -> google.api.MethodSettings.LongRunning + 16, // 28: google.api.MethodSettings.batching:type_name -> google.api.BatchingConfigProto + 17, // 29: google.api.BatchingConfigProto.thresholds:type_name -> google.api.BatchingSettingsProto + 18, // 30: google.api.BatchingConfigProto.batch_descriptor:type_name -> google.api.BatchingDescriptorProto + 26, // 31: google.api.BatchingSettingsProto.delay_threshold:type_name -> google.protobuf.Duration + 2, // 32: google.api.BatchingSettingsProto.flow_control_limit_exceeded_behavior:type_name -> google.api.FlowControlLimitExceededBehaviorProto + 26, // 33: google.api.MethodSettings.LongRunning.initial_poll_delay:type_name -> google.protobuf.Duration + 26, // 34: google.api.MethodSettings.LongRunning.max_poll_delay:type_name -> google.protobuf.Duration + 26, // 35: google.api.MethodSettings.LongRunning.total_poll_timeout:type_name -> google.protobuf.Duration + 27, // 36: google.api.method_signature:extendee -> google.protobuf.MethodOptions + 28, // 37: google.api.default_host:extendee -> google.protobuf.ServiceOptions + 28, // 38: google.api.oauth_scopes:extendee -> google.protobuf.ServiceOptions + 28, // 39: google.api.api_version:extendee -> google.protobuf.ServiceOptions + 40, // [40:40] is the sub-list for method output_type + 40, // [40:40] is the sub-list for method input_type + 40, // [40:40] is the sub-list for extension type_name + 36, // [36:40] is the sub-list for extension extendee + 0, // [0:36] is the sub-list for field type_name } func init() { file_google_api_client_proto_init() } @@ -2055,7 +2485,43 @@ func file_google_api_client_proto_init() { return nil } } + file_google_api_client_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchingConfigProto); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } file_google_api_client_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchingSettingsProto); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchingDescriptorProto); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PythonSettings_ExperimentalFeatures); i { case 0: return &v.state @@ -2067,7 +2533,7 @@ func file_google_api_client_proto_init() { return nil } } - file_google_api_client_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_google_api_client_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MethodSettings_LongRunning); i { case 0: return &v.state @@ -2085,8 +2551,8 @@ func file_google_api_client_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_google_api_client_proto_rawDesc, - NumEnums: 2, - NumMessages: 19, + NumEnums: 3, + NumMessages: 22, NumExtensions: 4, NumServices: 0, }, diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/field_behavior.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/field_behavior.pb.go index 5d583b86..fc6d27b4 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/field_behavior.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/field_behavior.pb.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC +// Copyright 2026 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/field_info.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/field_info.pb.go index 53e9dd1e..b660d02c 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/field_info.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/field_info.pb.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC +// Copyright 2026 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/http.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/http.pb.go index d30fcee4..998205e1 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/http.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/http.pb.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC +// Copyright 2026 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/resource.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/resource.pb.go index 175974a8..ad2a3fbf 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/resource.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/resource.pb.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC +// Copyright 2026 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/routing.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/routing.pb.go index b8c4aa71..9a83b963 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/routing.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/routing.pb.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC +// Copyright 2026 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -66,9 +66,13 @@ const ( // app_profile_id: profiles/prof_qux // } // -// The routing header consists of one or multiple key-value pairs. Every key -// and value must be percent-encoded, and joined together in the format of -// `key1=value1&key2=value2`. +// The routing header consists of one or multiple key-value pairs. The order of +// the key-value pairs is undefined, the order of the `routing_parameters` in +// the `RoutingRule` only matters for the evaluation order of the path +// templates when `field` is the same. See the examples below for more details. +// +// Every key and value in the routing header must be percent-encoded, +// and joined together in the following format: `key1=value1&key2=value2`. // The examples below skip the percent-encoding for readability. // // # Example 1 diff --git a/vendor/google.golang.org/genproto/googleapis/api/launch_stage.pb.go b/vendor/google.golang.org/genproto/googleapis/api/launch_stage.pb.go index a69c1d47..2cbb7b43 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/launch_stage.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/launch_stage.pb.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC +// Copyright 2026 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/google.golang.org/genproto/googleapis/rpc/status/status.pb.go b/vendor/google.golang.org/genproto/googleapis/rpc/status/status.pb.go index 06a3f710..f25a7bcc 100644 --- a/vendor/google.golang.org/genproto/googleapis/rpc/status/status.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/rpc/status/status.pb.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC +// Copyright 2026 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -127,14 +127,13 @@ var file_google_rpc_status_proto_rawDesc = []byte{ 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, - 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x42, 0x61, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, + 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x42, 0x5e, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x42, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x37, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3b, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0xf8, 0x01, 0x01, 0xa2, 0x02, 0x03, 0x52, 0x50, 0x43, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x75, 0x73, 0xa2, 0x02, 0x03, 0x52, 0x50, 0x43, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/vendor/google.golang.org/grpc/attributes/attributes.go b/vendor/google.golang.org/grpc/attributes/attributes.go index 52d530d7..4c60518c 100644 --- a/vendor/google.golang.org/grpc/attributes/attributes.go +++ b/vendor/google.golang.org/grpc/attributes/attributes.go @@ -27,6 +27,8 @@ package attributes import ( "fmt" + "iter" + "maps" "strings" ) @@ -37,37 +39,46 @@ import ( // any) bool', it will be called by (*Attributes).Equal to determine whether // two values with the same key should be considered equal. type Attributes struct { - m map[any]any + parent *Attributes + key, value any } // New returns a new Attributes containing the key/value pair. func New(key, value any) *Attributes { - return &Attributes{m: map[any]any{key: value}} + return &Attributes{ + key: key, + value: value, + } } // WithValue returns a new Attributes containing the previous keys and values // and the new key/value pair. If the same key appears multiple times, the -// last value overwrites all previous values for that key. To remove an -// existing key, use a nil value. value should not be modified later. +// last value overwrites all previous values for that key. value should not be +// modified later. +// +// Note that Attributes do not support deletion. Avoid using untyped nil values. +// Since the Value method returns an untyped nil when a key is absent, it is +// impossible to distinguish between a missing key and a key explicitly set to +// an untyped nil. If you need to represent a value being unset, consider +// storing a specific sentinel type or a wrapper struct with a boolean field +// indicating presence. func (a *Attributes) WithValue(key, value any) *Attributes { - if a == nil { - return New(key, value) + return &Attributes{ + parent: a, + key: key, + value: value, } - n := &Attributes{m: make(map[any]any, len(a.m)+1)} - for k, v := range a.m { - n.m[k] = v - } - n.m[key] = value - return n } // Value returns the value associated with these attributes for key, or nil if // no value is associated with key. The returned value should not be modified. func (a *Attributes) Value(key any) any { - if a == nil { - return nil + for cur := a; cur != nil; cur = cur.parent { + if cur.key == key { + return cur.value + } } - return a.m[key] + return nil } // Equal returns whether a and o are equivalent. If 'Equal(o any) bool' is @@ -83,11 +94,15 @@ func (a *Attributes) Equal(o *Attributes) bool { if a == nil || o == nil { return false } - if len(a.m) != len(o.m) { - return false + if a == o { + return true } - for k, v := range a.m { - ov, ok := o.m[k] + m := maps.Collect(o.all()) + lenA := 0 + + for k, v := range a.all() { + lenA++ + ov, ok := m[k] if !ok { // o missing element of a return false @@ -101,7 +116,7 @@ func (a *Attributes) Equal(o *Attributes) bool { return false } } - return true + return lenA == len(m) } // String prints the attribute map. If any key or values throughout the map @@ -110,11 +125,11 @@ func (a *Attributes) String() string { var sb strings.Builder sb.WriteString("{") first := true - for k, v := range a.m { + for k, v := range a.all() { if !first { sb.WriteString(", ") } - sb.WriteString(fmt.Sprintf("%q: %q ", str(k), str(v))) + fmt.Fprintf(&sb, "%q: %q ", str(k), str(v)) first = false } sb.WriteString("}") @@ -139,3 +154,21 @@ func str(x any) (s string) { func (a *Attributes) MarshalJSON() ([]byte, error) { return []byte(a.String()), nil } + +// all returns an iterator that yields all key-value pairs in the Attributes +// chain. If a key appears multiple times, only the most recently added value +// is yielded. +func (a *Attributes) all() iter.Seq2[any, any] { + return func(yield func(any, any) bool) { + seen := map[any]bool{} + for cur := a; cur != nil; cur = cur.parent { + if seen[cur.key] { + continue + } + if !yield(cur.key, cur.value) { + return + } + seen[cur.key] = true + } + } +} diff --git a/vendor/google.golang.org/grpc/balancer/balancer.go b/vendor/google.golang.org/grpc/balancer/balancer.go index d08b7ad6..326888ae 100644 --- a/vendor/google.golang.org/grpc/balancer/balancer.go +++ b/vendor/google.golang.org/grpc/balancer/balancer.go @@ -33,6 +33,7 @@ import ( estats "google.golang.org/grpc/experimental/stats" "google.golang.org/grpc/grpclog" "google.golang.org/grpc/internal" + "google.golang.org/grpc/internal/envconfig" "google.golang.org/grpc/metadata" "google.golang.org/grpc/resolver" "google.golang.org/grpc/serviceconfig" @@ -46,8 +47,8 @@ var ( ) // Register registers the balancer builder to the balancer map. b.Name -// (lowercased) will be used as the name registered with this builder. If the -// Builder implements ConfigParser, ParseConfig will be called when new service +// will be used as the name registered with this builder. If the Builder +// implements ConfigParser, ParseConfig will be called when new service // configs are received by the resolver, and the result will be provided to the // Balancer in UpdateClientConnState. // @@ -55,12 +56,12 @@ var ( // an init() function), and is not thread-safe. If multiple Balancers are // registered with the same name, the one registered last will take effect. func Register(b Builder) { - name := strings.ToLower(b.Name()) - if name != b.Name() { - // TODO: Skip the use of strings.ToLower() to index the map after v1.59 - // is released to switch to case sensitive balancer registry. Also, - // remove this warning and update the docstrings for Register and Get. - logger.Warningf("Balancer registered with name %q. grpc-go will be switching to case sensitive balancer registries soon", b.Name()) + name := b.Name() + if !envconfig.CaseSensitiveBalancerRegistries { + name = strings.ToLower(name) + if name != b.Name() { + logger.Warningf("Balancer registered with name %q. grpc-go will be switching to case sensitive balancer registries soon. After 2 releases, we will enable the env var by default.", b.Name()) + } } m[name] = b } @@ -78,16 +79,17 @@ func init() { } // Get returns the resolver builder registered with the given name. -// Note that the compare is done in a case-insensitive fashion. +// Note that the compare is done in a case-sensitive fashion. // If no builder is register with the name, nil will be returned. func Get(name string) Builder { - if strings.ToLower(name) != name { - // TODO: Skip the use of strings.ToLower() to index the map after v1.59 - // is released to switch to case sensitive balancer registry. Also, - // remove this warning and update the docstrings for Register and Get. - logger.Warningf("Balancer retrieved for name %q. grpc-go will be switching to case sensitive balancer registries soon", name) + if !envconfig.CaseSensitiveBalancerRegistries { + lowerName := strings.ToLower(name) + if lowerName != name { + logger.Warningf("Balancer retrieved for name %q. grpc-go will be switching to case sensitive balancer registries soon. After 2 releases, we will enable the env var by default.", name) + } + name = lowerName } - if b, ok := m[strings.ToLower(name)]; ok { + if b, ok := m[name]; ok { return b } return nil diff --git a/vendor/google.golang.org/grpc/balancer/base/balancer.go b/vendor/google.golang.org/grpc/balancer/base/balancer.go index 4d576876..4399ba01 100644 --- a/vendor/google.golang.org/grpc/balancer/base/balancer.go +++ b/vendor/google.golang.org/grpc/balancer/base/balancer.go @@ -121,8 +121,7 @@ func (b *baseBalancer) UpdateClientConnState(s balancer.ClientConnState) error { sc.Connect() } } - for _, a := range b.subConns.Keys() { - sc, _ := b.subConns.Get(a) + for a, sc := range b.subConns.All() { // a was removed by resolver. if _, ok := addrsSet.Get(a); !ok { sc.Shutdown() @@ -171,8 +170,7 @@ func (b *baseBalancer) regeneratePicker() { readySCs := make(map[balancer.SubConn]SubConnInfo) // Filter out all ready SCs from full subConn map. - for _, addr := range b.subConns.Keys() { - sc, _ := b.subConns.Get(addr) + for addr, sc := range b.subConns.All() { if st, ok := b.scStates[sc]; ok && st == connectivity.Ready { readySCs[sc] = SubConnInfo{Address: addr} } diff --git a/vendor/google.golang.org/grpc/balancer/endpointsharding/endpointsharding.go b/vendor/google.golang.org/grpc/balancer/endpointsharding/endpointsharding.go index 360db08e..12479f69 100644 --- a/vendor/google.golang.org/grpc/balancer/endpointsharding/endpointsharding.go +++ b/vendor/google.golang.org/grpc/balancer/endpointsharding/endpointsharding.go @@ -187,8 +187,7 @@ func (es *endpointSharding) UpdateClientConnState(state balancer.ClientConnState } } // Delete old children that are no longer present. - for _, e := range children.Keys() { - child, _ := children.Get(e) + for e, child := range children.All() { if _, ok := newChildren.Get(e); !ok { child.closeLocked() } @@ -212,7 +211,7 @@ func (es *endpointSharding) ResolverError(err error) { es.updateState() }() children := es.children.Load() - for _, child := range children.Values() { + for _, child := range children.All() { child.resolverErrorLocked(err) } } @@ -225,7 +224,7 @@ func (es *endpointSharding) Close() { es.childMu.Lock() defer es.childMu.Unlock() children := es.children.Load() - for _, child := range children.Values() { + for _, child := range children.All() { child.closeLocked() } } @@ -233,7 +232,7 @@ func (es *endpointSharding) Close() { func (es *endpointSharding) ExitIdle() { es.childMu.Lock() defer es.childMu.Unlock() - for _, bw := range es.children.Load().Values() { + for _, bw := range es.children.Load().All() { if !bw.isClosed { bw.child.ExitIdle() } @@ -255,7 +254,7 @@ func (es *endpointSharding) updateState() { children := es.children.Load() childStates := make([]ChildState, 0, children.Len()) - for _, child := range children.Values() { + for _, child := range children.All() { childState := child.childState childStates = append(childStates, childState) childPicker := childState.State.Picker diff --git a/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirst.go b/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirst.go index dccd9f0b..518a69d5 100644 --- a/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirst.go +++ b/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirst.go @@ -399,14 +399,14 @@ func (b *pickfirstBalancer) startFirstPassLocked() { b.firstPass = true b.numTF = 0 // Reset the connection attempt record for existing SubConns. - for _, sd := range b.subConns.Values() { + for _, sd := range b.subConns.All() { sd.connectionFailedInFirstPass = false } b.requestConnectionLocked() } func (b *pickfirstBalancer) closeSubConnsLocked() { - for _, sd := range b.subConns.Values() { + for _, sd := range b.subConns.All() { sd.subConn.Shutdown() } b.subConns = resolver.NewAddressMapV2[*scData]() @@ -506,7 +506,7 @@ func (b *pickfirstBalancer) reconcileSubConnsLocked(newAddrs []resolver.Address) newAddrsMap.Set(addr, true) } - for _, oldAddr := range b.subConns.Keys() { + for oldAddr := range b.subConns.All() { if _, ok := newAddrsMap.Get(oldAddr); ok { continue } @@ -520,7 +520,7 @@ func (b *pickfirstBalancer) reconcileSubConnsLocked(newAddrs []resolver.Address) // becomes ready, which means that all other subConn must be shutdown. func (b *pickfirstBalancer) shutdownRemainingLocked(selected *scData) { b.cancelConnectionTimer() - for _, sd := range b.subConns.Values() { + for _, sd := range b.subConns.All() { if sd.subConn != selected.subConn { sd.subConn.Shutdown() } @@ -771,7 +771,7 @@ func (b *pickfirstBalancer) endFirstPassIfPossibleLocked(lastErr error) { } // Connect() has been called on all the SubConns. The first pass can be // ended if all the SubConns have reported a failure. - for _, sd := range b.subConns.Values() { + for _, sd := range b.subConns.All() { if !sd.connectionFailedInFirstPass { return } @@ -782,7 +782,7 @@ func (b *pickfirstBalancer) endFirstPassIfPossibleLocked(lastErr error) { Picker: &picker{err: lastErr}, }) // Start re-connecting all the SubConns that are already in IDLE. - for _, sd := range b.subConns.Values() { + for _, sd := range b.subConns.All() { if sd.rawConnectivityState == connectivity.Idle { sd.subConn.Connect() } diff --git a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go index 42c61cf9..296123e2 100644 --- a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go +++ b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go @@ -18,7 +18,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc v5.27.1 // source: grpc/binlog/v1/binarylog.proto diff --git a/vendor/google.golang.org/grpc/credentials/tls.go b/vendor/google.golang.org/grpc/credentials/tls.go index 0bcd16db..a6083c3b 100644 --- a/vendor/google.golang.org/grpc/credentials/tls.go +++ b/vendor/google.golang.org/grpc/credentials/tls.go @@ -22,7 +22,6 @@ import ( "context" "crypto/tls" "crypto/x509" - "errors" "fmt" "net" "net/url" @@ -52,22 +51,21 @@ func (t TLSInfo) AuthType() string { } // ValidateAuthority validates the provided authority being used to override the -// :authority header by verifying it against the peer certificates. It returns a +// :authority header by verifying it against the peer certificate. It returns a // non-nil error if the validation fails. func (t TLSInfo) ValidateAuthority(authority string) error { - var errs []error host, _, err := net.SplitHostPort(authority) if err != nil { host = authority } - for _, cert := range t.State.PeerCertificates { - var err error - if err = cert.VerifyHostname(host); err == nil { - return nil - } - errs = append(errs, err) + + // Verify authority against the leaf certificate. + if len(t.State.PeerCertificates) == 0 { + // This is not expected to happen as the TLS handshake has already + // completed and should have populated PeerCertificates. + return fmt.Errorf("credentials: no peer certificates found to verify authority %q", host) } - return fmt.Errorf("credentials: invalid authority %q: %v", authority, errors.Join(errs...)) + return t.State.PeerCertificates[0].VerifyHostname(host) } // cipherSuiteLookup returns the string version of a TLS cipher suite ID. diff --git a/vendor/google.golang.org/grpc/dialoptions.go b/vendor/google.golang.org/grpc/dialoptions.go index 7a5ac2e7..4ec5f9cd 100644 --- a/vendor/google.golang.org/grpc/dialoptions.go +++ b/vendor/google.golang.org/grpc/dialoptions.go @@ -705,10 +705,11 @@ func WithDisableHealthCheck() DialOption { func defaultDialOptions() dialOptions { return dialOptions{ copts: transport.ConnectOptions{ - ReadBufferSize: defaultReadBufSize, - WriteBufferSize: defaultWriteBufSize, - UserAgent: grpcUA, - BufferPool: mem.DefaultBufferPool(), + ReadBufferSize: defaultReadBufSize, + WriteBufferSize: defaultWriteBufSize, + SharedWriteBuffer: true, + UserAgent: grpcUA, + BufferPool: mem.DefaultBufferPool(), }, bs: internalbackoff.DefaultExponential, idleTimeout: 30 * time.Minute, diff --git a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go index 7ad6fb44..3ae45faa 100644 --- a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go +++ b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go @@ -54,17 +54,16 @@ var ( // XDSEndpointHashKeyBackwardCompat controls the parsing of the endpoint hash // key from EDS LbEndpoint metadata. Endpoint hash keys can be disabled by - // setting "GRPC_XDS_ENDPOINT_HASH_KEY_BACKWARD_COMPAT" to "true". When the - // implementation of A76 is stable, we will flip the default value to false - // in a subsequent release. A final release will remove this environment - // variable, enabling the new behavior unconditionally. - XDSEndpointHashKeyBackwardCompat = boolFromEnv("GRPC_XDS_ENDPOINT_HASH_KEY_BACKWARD_COMPAT", true) + // setting "GRPC_XDS_ENDPOINT_HASH_KEY_BACKWARD_COMPAT" to "true". A future + // release will remove this environment variable, enabling the new behavior + // unconditionally. + XDSEndpointHashKeyBackwardCompat = boolFromEnv("GRPC_XDS_ENDPOINT_HASH_KEY_BACKWARD_COMPAT", false) // RingHashSetRequestHashKey is set if the ring hash balancer can get the // request hash header by setting the "requestHashHeader" field, according - // to gRFC A76. It can be enabled by setting the environment variable - // "GRPC_EXPERIMENTAL_RING_HASH_SET_REQUEST_HASH_KEY" to "true". - RingHashSetRequestHashKey = boolFromEnv("GRPC_EXPERIMENTAL_RING_HASH_SET_REQUEST_HASH_KEY", false) + // to gRFC A76. It can be disabled by setting the environment variable + // "GRPC_EXPERIMENTAL_RING_HASH_SET_REQUEST_HASH_KEY" to "false". + RingHashSetRequestHashKey = boolFromEnv("GRPC_EXPERIMENTAL_RING_HASH_SET_REQUEST_HASH_KEY", true) // ALTSHandshakerKeepaliveParams is set if we should add the // KeepaliveParams when dial the ALTS handshaker service. @@ -78,6 +77,14 @@ var ( // - The DNS resolver is being used. EnableDefaultPortForProxyTarget = boolFromEnv("GRPC_EXPERIMENTAL_ENABLE_DEFAULT_PORT_FOR_PROXY_TARGET", true) + // CaseSensitiveBalancerRegistries is set if the balancer registry should be + // case-sensitive. This is disabled by default, but can be enabled by setting + // the env variable "GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES" + // to "true". + // + // TODO: After 2 releases, we will enable the env var by default. + CaseSensitiveBalancerRegistries = boolFromEnv("GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES", false) + // XDSAuthorityRewrite indicates whether xDS authority rewriting is enabled. // This feature is defined in gRFC A81 and is enabled by setting the // environment variable GRPC_EXPERIMENTAL_XDS_AUTHORITY_REWRITE to "true". @@ -89,6 +96,14 @@ var ( // GRPC_EXPERIMENTAL_PF_WEIGHTED_SHUFFLING to "false". PickFirstWeightedShuffling = boolFromEnv("GRPC_EXPERIMENTAL_PF_WEIGHTED_SHUFFLING", true) + // XDSRecoverPanicInResourceParsing indicates whether the xdsclient should + // recover from panics while parsing xDS resources. + // + // This feature can be disabled (e.g. for fuzz testing) by setting the + // environment variable "GRPC_GO_EXPERIMENTAL_XDS_RESOURCE_PANIC_RECOVERY" + // to "false". + XDSRecoverPanicInResourceParsing = boolFromEnv("GRPC_GO_EXPERIMENTAL_XDS_RESOURCE_PANIC_RECOVERY", true) + // DisableStrictPathChecking indicates whether strict path checking is // disabled. This feature can be disabled by setting the environment // variable GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING to "true". @@ -104,6 +119,13 @@ var ( // A future release will remove this environment variable, enabling strict // path checking behavior unconditionally. DisableStrictPathChecking = boolFromEnv("GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING", false) + + // EnablePriorityLBChildPolicyCache controls whether the priority balancer + // should cache child balancers that are removed from the LB policy config, + // for a period of 15 minutes. This is disabled by default, but can be + // enabled by setting the env variable + // GRPC_EXPERIMENTAL_ENABLE_PRIORITY_LB_CHILD_POLICY_CACHE to true. + EnablePriorityLBChildPolicyCache = boolFromEnv("GRPC_EXPERIMENTAL_ENABLE_PRIORITY_LB_CHILD_POLICY_CACHE", false) ) func boolFromEnv(envVar string, def bool) bool { diff --git a/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go b/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go new file mode 100644 index 00000000..c2348a82 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go @@ -0,0 +1,338 @@ +/* + * + * Copyright 2026 gRPC 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 mem provides utilities that facilitate memory reuse in byte slices +// that are used as buffers. +package mem + +import ( + "fmt" + "math/bits" + "slices" + "sort" + "sync" +) + +const ( + goPageSize = 4 * 1024 // 4KiB. N.B. this must be a power of 2. +) + +var uintSize = bits.UintSize // use a variable for mocking during tests. + +// bufferPool is a copy of the public bufferPool interface used to avoid +// circular dependencies. +type bufferPool interface { + // Get returns a buffer with specified length from the pool. + Get(length int) *[]byte + + // Put returns a buffer to the pool. + // + // The provided pointer must hold a prefix of the buffer obtained via + // BufferPool.Get to ensure the buffer's entire capacity can be re-used. + Put(*[]byte) +} + +// BinaryTieredBufferPool is a buffer pool that uses multiple sub-pools with +// power-of-two sizes. +type BinaryTieredBufferPool struct { + // exponentToNextLargestPoolMap maps a power-of-two exponent (e.g., 12 for + // 4KB) to the index of the next largest sizedBufferPool. This is used by + // Get() to find the smallest pool that can satisfy a request for a given + // size. + exponentToNextLargestPoolMap []int + // exponentToPreviousLargestPoolMap maps a power-of-two exponent to the + // index of the previous largest sizedBufferPool. This is used by Put() + // to return a buffer to the most appropriate pool based on its capacity. + exponentToPreviousLargestPoolMap []int + sizedPools []bufferPool + fallbackPool bufferPool + maxPoolCap int // Optimization: Cache max capacity +} + +// NewBinaryTieredBufferPool returns a BufferPool backed by multiple sub-pools. +// This structure enables O(1) lookup time for Get and Put operations. +// +// The arguments provided are the exponents for the buffer capacities (powers +// of 2), not the raw byte sizes. For example, to create a pool of 16KB buffers +// (2^14 bytes), pass 14 as the argument. +func NewBinaryTieredBufferPool(powerOfTwoExponents ...uint8) (*BinaryTieredBufferPool, error) { + return newBinaryTiered(func(size int) bufferPool { + return newSizedBufferPool(size, true) + }, &simpleBufferPool{shouldZero: true}, powerOfTwoExponents...) +} + +// NewDirtyBinaryTieredBufferPool returns a BufferPool backed by multiple +// sub-pools. It is similar to NewBinaryTieredBufferPool but it does not +// initialize the buffers before returning them. +func NewDirtyBinaryTieredBufferPool(powerOfTwoExponents ...uint8) (*BinaryTieredBufferPool, error) { + return newBinaryTiered(func(size int) bufferPool { + return newSizedBufferPool(size, false) + }, &simpleBufferPool{shouldZero: false}, powerOfTwoExponents...) +} + +func newBinaryTiered(sizedPoolFactory func(int) bufferPool, fallbackPool bufferPool, powerOfTwoExponents ...uint8) (*BinaryTieredBufferPool, error) { + slices.Sort(powerOfTwoExponents) + powerOfTwoExponents = slices.Compact(powerOfTwoExponents) + + // Determine the maximum exponent we need to support. This depends on the + // word size (32-bit vs 64-bit). + maxExponent := uintSize - 2 + indexOfNextLargestBit := slices.Repeat([]int{-1}, maxExponent+1) + indexOfPreviousLargestBit := slices.Repeat([]int{-1}, maxExponent+1) + + maxTier := 0 + pools := make([]bufferPool, 0, len(powerOfTwoExponents)) + + for i, exp := range powerOfTwoExponents { + // Allocating slices of size > 2^maxExponent isn't possible on + // maxExponent-bit machines. + if int(exp) > maxExponent { + return nil, fmt.Errorf("mem: allocating slice of size 2^%d is not possible", exp) + } + tierSize := 1 << exp + pools = append(pools, sizedPoolFactory(tierSize)) + maxTier = max(maxTier, tierSize) + + // Map the exact power of 2 to this pool index. + indexOfNextLargestBit[exp] = i + indexOfPreviousLargestBit[exp] = i + } + + // Fill gaps for Get() (Next Largest) + // We iterate backwards. If current is empty, take the value from the right (larger). + for i := maxExponent - 1; i >= 0; i-- { + if indexOfNextLargestBit[i] == -1 { + indexOfNextLargestBit[i] = indexOfNextLargestBit[i+1] + } + } + + // Fill gaps for Put() (Previous Largest) + // We iterate forwards. If current is empty, take the value from the left (smaller). + for i := 1; i <= maxExponent; i++ { + if indexOfPreviousLargestBit[i] == -1 { + indexOfPreviousLargestBit[i] = indexOfPreviousLargestBit[i-1] + } + } + + return &BinaryTieredBufferPool{ + exponentToNextLargestPoolMap: indexOfNextLargestBit, + exponentToPreviousLargestPoolMap: indexOfPreviousLargestBit, + sizedPools: pools, + maxPoolCap: maxTier, + fallbackPool: fallbackPool, + }, nil +} + +// Get returns a buffer with specified length from the pool. +func (b *BinaryTieredBufferPool) Get(size int) *[]byte { + return b.poolForGet(size).Get(size) +} + +func (b *BinaryTieredBufferPool) poolForGet(size int) bufferPool { + if size == 0 || size > b.maxPoolCap { + return b.fallbackPool + } + + // Calculate the exponent of the smallest power of 2 >= size. + // We subtract 1 from size to handle exact powers of 2 correctly. + // + // Examples: + // size=16 (0b10000) -> size-1=15 (0b01111) -> bits.Len=4 -> Pool for 2^4 + // size=17 (0b10001) -> size-1=16 (0b10000) -> bits.Len=5 -> Pool for 2^5 + querySize := uint(size - 1) + poolIdx := b.exponentToNextLargestPoolMap[bits.Len(querySize)] + + return b.sizedPools[poolIdx] +} + +// Put returns a buffer to the pool. +func (b *BinaryTieredBufferPool) Put(buf *[]byte) { + // We pass the capacity of the buffer, and not the size of the buffer here. + // If we did the latter, all buffers would eventually move to the smallest + // pool. + b.poolForPut(cap(*buf)).Put(buf) +} + +func (b *BinaryTieredBufferPool) poolForPut(bCap int) bufferPool { + if bCap == 0 { + return NopBufferPool{} + } + if bCap > b.maxPoolCap { + return b.fallbackPool + } + // Find the pool with the largest capacity <= bCap. + // + // We calculate the exponent of the largest power of 2 <= bCap. + // bits.Len(x) returns the minimum number of bits required to represent x; + // i.e. the number of bits up to and including the most significant bit. + // Subtracting 1 gives the 0-based index of the most significant bit, + // which is the exponent of the largest power of 2 <= bCap. + // + // Examples: + // cap=16 (0b10000) -> Len=5 -> 5-1=4 -> 2^4 + // cap=15 (0b01111) -> Len=4 -> 4-1=3 -> 2^3 + largestPowerOfTwo := bits.Len(uint(bCap)) - 1 + poolIdx := b.exponentToPreviousLargestPoolMap[largestPowerOfTwo] + // The buffer is smaller than the smallest power of 2, discard it. + if poolIdx == -1 { + // Buffer is smaller than our smallest pool bucket. + return NopBufferPool{} + } + return b.sizedPools[poolIdx] +} + +// NopBufferPool is a buffer pool that returns new buffers without pooling. +type NopBufferPool struct{} + +// Get returns a buffer with specified length from the pool. +func (NopBufferPool) Get(length int) *[]byte { + b := make([]byte, length) + return &b +} + +// Put returns a buffer to the pool. +func (NopBufferPool) Put(*[]byte) { +} + +// sizedBufferPool is a BufferPool implementation that is optimized for specific +// buffer sizes. For example, HTTP/2 frames within gRPC have a default max size +// of 16kb and a sizedBufferPool can be configured to only return buffers with a +// capacity of 16kb. Note that however it does not support returning larger +// buffers and in fact panics if such a buffer is requested. Because of this, +// this BufferPool implementation is not meant to be used on its own and rather +// is intended to be embedded in a TieredBufferPool such that Get is only +// invoked when the required size is smaller than or equal to defaultSize. +type sizedBufferPool struct { + pool sync.Pool + defaultSize int + shouldZero bool +} + +func (p *sizedBufferPool) Get(size int) *[]byte { + buf, ok := p.pool.Get().(*[]byte) + if !ok { + buf := make([]byte, size, p.defaultSize) + return &buf + } + b := *buf + if p.shouldZero { + clear(b[:cap(b)]) + } + *buf = b[:size] + return buf +} + +func (p *sizedBufferPool) Put(buf *[]byte) { + if cap(*buf) < p.defaultSize { + // Ignore buffers that are too small to fit in the pool. Otherwise, when + // Get is called it will panic as it tries to index outside the bounds + // of the buffer. + return + } + p.pool.Put(buf) +} + +func newSizedBufferPool(size int, zero bool) *sizedBufferPool { + return &sizedBufferPool{ + defaultSize: size, + shouldZero: zero, + } +} + +// TieredBufferPool implements the BufferPool interface with multiple tiers of +// buffer pools for different sizes of buffers. +type TieredBufferPool struct { + sizedPools []*sizedBufferPool + fallbackPool simpleBufferPool +} + +// NewTieredBufferPool returns a BufferPool implementation that uses multiple +// underlying pools of the given pool sizes. +func NewTieredBufferPool(poolSizes ...int) *TieredBufferPool { + sort.Ints(poolSizes) + pools := make([]*sizedBufferPool, len(poolSizes)) + for i, s := range poolSizes { + pools[i] = newSizedBufferPool(s, true) + } + return &TieredBufferPool{ + sizedPools: pools, + fallbackPool: simpleBufferPool{shouldZero: true}, + } +} + +// Get returns a buffer with specified length from the pool. +func (p *TieredBufferPool) Get(size int) *[]byte { + return p.getPool(size).Get(size) +} + +// Put returns a buffer to the pool. +func (p *TieredBufferPool) Put(buf *[]byte) { + p.getPool(cap(*buf)).Put(buf) +} + +func (p *TieredBufferPool) getPool(size int) bufferPool { + poolIdx := sort.Search(len(p.sizedPools), func(i int) bool { + return p.sizedPools[i].defaultSize >= size + }) + + if poolIdx == len(p.sizedPools) { + return &p.fallbackPool + } + + return p.sizedPools[poolIdx] +} + +// simpleBufferPool is an implementation of the BufferPool interface that +// attempts to pool buffers with a sync.Pool. When Get is invoked, it tries to +// acquire a buffer from the pool but if that buffer is too small, it returns it +// to the pool and creates a new one. +type simpleBufferPool struct { + pool sync.Pool + shouldZero bool +} + +func (p *simpleBufferPool) Get(size int) *[]byte { + bs, ok := p.pool.Get().(*[]byte) + if ok && cap(*bs) >= size { + if p.shouldZero { + clear((*bs)[:cap(*bs)]) + } + *bs = (*bs)[:size] + return bs + } + + // A buffer was pulled from the pool, but it is too small. Put it back in + // the pool and create one large enough. + if ok { + p.pool.Put(bs) + } + + // If we're going to allocate, round up to the nearest page. This way if + // requests frequently arrive with small variation we don't allocate + // repeatedly if we get unlucky and they increase over time. By default we + // only allocate here if size > 1MiB. Because goPageSize is a power of 2, we + // can round up efficiently. + allocSize := (size + goPageSize - 1) & ^(goPageSize - 1) + + b := make([]byte, size, allocSize) + return &b +} + +func (p *simpleBufferPool) Put(buf *[]byte) { + p.pool.Put(buf) +} diff --git a/vendor/google.golang.org/grpc/internal/transport/defaults.go b/vendor/google.golang.org/grpc/internal/transport/defaults.go index bc8ee074..0b2269a5 100644 --- a/vendor/google.golang.org/grpc/internal/transport/defaults.go +++ b/vendor/google.golang.org/grpc/internal/transport/defaults.go @@ -46,6 +46,7 @@ const ( defaultWriteQuota = 64 * 1024 defaultClientMaxHeaderListSize = uint32(16 << 20) defaultServerMaxHeaderListSize = uint32(16 << 20) + upcomingDefaultHeaderListSize = uint32(8 << 10) ) // MaxStreamID is the upper bound for the stream ID before the current diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go index 37b1acc3..c943503f 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_client.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go @@ -871,11 +871,15 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr, handler s } var sz int64 for _, f := range hdr.hf { - if sz += int64(f.Size()); sz > int64(*t.maxSendHeaderListSize) { + sz += int64(f.Size()) + if sz > int64(*t.maxSendHeaderListSize) { hdrListSizeErr = status.Errorf(codes.Internal, "header list size to send violates the maximum size (%d bytes) set by server", *t.maxSendHeaderListSize) return false } } + if sz > int64(upcomingDefaultHeaderListSize) { + t.logger.Warningf("Header list size to send (%d bytes) is larger than the upcoming default limit (%d bytes). In a future release, this will be restricted to %d bytes.", sz, upcomingDefaultHeaderListSize, upcomingDefaultHeaderListSize) + } return true } for { diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go index a1a14e14..3a8c36e4 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go @@ -940,13 +940,17 @@ func (t *http2Server) checkForHeaderListSize(hf []hpack.HeaderField) bool { } var sz int64 for _, f := range hf { - if sz += int64(f.Size()); sz > int64(*t.maxSendHeaderListSize) { + sz += int64(f.Size()) + if sz > int64(*t.maxSendHeaderListSize) { if t.logger.V(logLevel) { t.logger.Infof("Header list size to send violates the maximum size (%d bytes) set by client", *t.maxSendHeaderListSize) } return false } } + if sz > int64(upcomingDefaultHeaderListSize) { + t.logger.Warningf("Header list size to send (%d bytes) is larger than the upcoming default limit (%d bytes). In a future release, this will be restricted to %d bytes.", sz, upcomingDefaultHeaderListSize, upcomingDefaultHeaderListSize) + } return true } diff --git a/vendor/google.golang.org/grpc/mem/buffer_pool.go b/vendor/google.golang.org/grpc/mem/buffer_pool.go index 2ea763a4..3b02b909 100644 --- a/vendor/google.golang.org/grpc/mem/buffer_pool.go +++ b/vendor/google.golang.org/grpc/mem/buffer_pool.go @@ -19,10 +19,10 @@ package mem import ( - "sort" - "sync" + "fmt" "google.golang.org/grpc/internal" + "google.golang.org/grpc/internal/mem" ) // BufferPool is a pool of buffers that can be shared and reused, resulting in @@ -38,20 +38,23 @@ type BufferPool interface { Put(*[]byte) } -const goPageSize = 4 << 10 // 4KiB. N.B. this must be a power of 2. - -var defaultBufferPoolSizes = []int{ - 256, - goPageSize, - 16 << 10, // 16KB (max HTTP/2 frame size used by gRPC) - 32 << 10, // 32KB (default buffer size for io.Copy) - 1 << 20, // 1MB -} - -var defaultBufferPool BufferPool +var ( + defaultBufferPoolSizeExponents = []uint8{ + 8, + 12, // Go page size, 4KB + 14, // 16KB (max HTTP/2 frame size used by gRPC) + 15, // 32KB (default buffer size for io.Copy) + 20, // 1MB + } + defaultBufferPool BufferPool +) func init() { - defaultBufferPool = NewTieredBufferPool(defaultBufferPoolSizes...) + var err error + defaultBufferPool, err = NewBinaryTieredBufferPool(defaultBufferPoolSizeExponents...) + if err != nil { + panic(fmt.Sprintf("Failed to create default buffer pool: %v", err)) + } internal.SetDefaultBufferPool = func(pool BufferPool) { defaultBufferPool = pool @@ -72,134 +75,22 @@ func DefaultBufferPool() BufferPool { // NewTieredBufferPool returns a BufferPool implementation that uses multiple // underlying pools of the given pool sizes. func NewTieredBufferPool(poolSizes ...int) BufferPool { - sort.Ints(poolSizes) - pools := make([]*sizedBufferPool, len(poolSizes)) - for i, s := range poolSizes { - pools[i] = newSizedBufferPool(s) - } - return &tieredBufferPool{ - sizedPools: pools, - } -} - -// tieredBufferPool implements the BufferPool interface with multiple tiers of -// buffer pools for different sizes of buffers. -type tieredBufferPool struct { - sizedPools []*sizedBufferPool - fallbackPool simpleBufferPool -} - -func (p *tieredBufferPool) Get(size int) *[]byte { - return p.getPool(size).Get(size) + return mem.NewTieredBufferPool(poolSizes...) } -func (p *tieredBufferPool) Put(buf *[]byte) { - p.getPool(cap(*buf)).Put(buf) +// NewBinaryTieredBufferPool returns a BufferPool backed by multiple sub-pools. +// This structure enables O(1) lookup time for Get and Put operations. +// +// The arguments provided are the exponents for the buffer capacities (powers +// of 2), not the raw byte sizes. For example, to create a pool of 16KB buffers +// (2^14 bytes), pass 14 as the argument. +func NewBinaryTieredBufferPool(powerOfTwoExponents ...uint8) (BufferPool, error) { + return mem.NewBinaryTieredBufferPool(powerOfTwoExponents...) } -func (p *tieredBufferPool) getPool(size int) BufferPool { - poolIdx := sort.Search(len(p.sizedPools), func(i int) bool { - return p.sizedPools[i].defaultSize >= size - }) - - if poolIdx == len(p.sizedPools) { - return &p.fallbackPool - } - - return p.sizedPools[poolIdx] -} - -// sizedBufferPool is a BufferPool implementation that is optimized for specific -// buffer sizes. For example, HTTP/2 frames within gRPC have a default max size -// of 16kb and a sizedBufferPool can be configured to only return buffers with a -// capacity of 16kb. Note that however it does not support returning larger -// buffers and in fact panics if such a buffer is requested. Because of this, -// this BufferPool implementation is not meant to be used on its own and rather -// is intended to be embedded in a tieredBufferPool such that Get is only -// invoked when the required size is smaller than or equal to defaultSize. -type sizedBufferPool struct { - pool sync.Pool - defaultSize int -} - -func (p *sizedBufferPool) Get(size int) *[]byte { - buf, ok := p.pool.Get().(*[]byte) - if !ok { - buf := make([]byte, size, p.defaultSize) - return &buf - } - b := *buf - clear(b[:cap(b)]) - *buf = b[:size] - return buf -} - -func (p *sizedBufferPool) Put(buf *[]byte) { - if cap(*buf) < p.defaultSize { - // Ignore buffers that are too small to fit in the pool. Otherwise, when - // Get is called it will panic as it tries to index outside the bounds - // of the buffer. - return - } - p.pool.Put(buf) -} - -func newSizedBufferPool(size int) *sizedBufferPool { - return &sizedBufferPool{ - defaultSize: size, - } -} - -var _ BufferPool = (*simpleBufferPool)(nil) - -// simpleBufferPool is an implementation of the BufferPool interface that -// attempts to pool buffers with a sync.Pool. When Get is invoked, it tries to -// acquire a buffer from the pool but if that buffer is too small, it returns it -// to the pool and creates a new one. -type simpleBufferPool struct { - pool sync.Pool -} - -func (p *simpleBufferPool) Get(size int) *[]byte { - bs, ok := p.pool.Get().(*[]byte) - if ok && cap(*bs) >= size { - clear((*bs)[:cap(*bs)]) - *bs = (*bs)[:size] - return bs - } - - // A buffer was pulled from the pool, but it is too small. Put it back in - // the pool and create one large enough. - if ok { - p.pool.Put(bs) - } - - // If we're going to allocate, round up to the nearest page. This way if - // requests frequently arrive with small variation we don't allocate - // repeatedly if we get unlucky and they increase over time. By default we - // only allocate here if size > 1MiB. Because goPageSize is a power of 2, we - // can round up efficiently. - allocSize := (size + goPageSize - 1) & ^(goPageSize - 1) - - b := make([]byte, size, allocSize) - return &b -} - -func (p *simpleBufferPool) Put(buf *[]byte) { - p.pool.Put(buf) -} - -var _ BufferPool = NopBufferPool{} - // NopBufferPool is a buffer pool that returns new buffers without pooling. -type NopBufferPool struct{} - -// Get returns a buffer with specified length from the pool. -func (NopBufferPool) Get(length int) *[]byte { - b := make([]byte, length) - return &b +type NopBufferPool struct { + mem.NopBufferPool } -// Put returns a buffer to the pool. -func (NopBufferPool) Put(*[]byte) { -} +var _ BufferPool = NopBufferPool{} diff --git a/vendor/google.golang.org/grpc/picker_wrapper.go b/vendor/google.golang.org/grpc/picker_wrapper.go index aa52bfe9..0183ab22 100644 --- a/vendor/google.golang.org/grpc/picker_wrapper.go +++ b/vendor/google.golang.org/grpc/picker_wrapper.go @@ -192,7 +192,9 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer. // DoneInfo with default value works. pickResult.Done(balancer.DoneInfo{}) } - logger.Infof("blockingPicker: the picked transport is not ready, loop back to repick") + if logger.V(2) { + logger.Infof("blockingPicker: the picked transport is not ready, loop back to repick") + } // If ok == false, ac.state is not READY. // A valid picker always returns READY subConn. This means the state of ac // just changed, and picker will be updated shortly. diff --git a/vendor/google.golang.org/grpc/resolver/map.go b/vendor/google.golang.org/grpc/resolver/map.go index c3c15ac9..789a5aba 100644 --- a/vendor/google.golang.org/grpc/resolver/map.go +++ b/vendor/google.golang.org/grpc/resolver/map.go @@ -20,6 +20,7 @@ package resolver import ( "encoding/base64" + "iter" "sort" "strings" ) @@ -135,6 +136,7 @@ func (a *AddressMapV2[T]) Len() int { } // Keys returns a slice of all current map keys. +// Deprecated: Use AddressMapV2.All() instead. func (a *AddressMapV2[T]) Keys() []Address { ret := make([]Address, 0, a.Len()) for _, entryList := range a.m { @@ -146,6 +148,7 @@ func (a *AddressMapV2[T]) Keys() []Address { } // Values returns a slice of all current map values. +// Deprecated: Use AddressMapV2.All() instead. func (a *AddressMapV2[T]) Values() []T { ret := make([]T, 0, a.Len()) for _, entryList := range a.m { @@ -156,6 +159,19 @@ func (a *AddressMapV2[T]) Values() []T { return ret } +// All returns an iterator over all elements. +func (a *AddressMapV2[T]) All() iter.Seq2[Address, T] { + return func(yield func(Address, T) bool) { + for _, entryList := range a.m { + for _, entry := range entryList { + if !yield(entry.addr, entry.value) { + return + } + } + } + } +} + type endpointMapKey string // EndpointMap is a map of endpoints to arbitrary values keyed on only the @@ -223,6 +239,7 @@ func (em *EndpointMap[T]) Len() int { // the unordered set of addresses. Thus, endpoint information returned is not // the full endpoint data (drops duplicated addresses and attributes) but can be // used for EndpointMap accesses. +// Deprecated: Use EndpointMap.All() instead. func (em *EndpointMap[T]) Keys() []Endpoint { ret := make([]Endpoint, 0, len(em.endpoints)) for _, en := range em.endpoints { @@ -232,6 +249,7 @@ func (em *EndpointMap[T]) Keys() []Endpoint { } // Values returns a slice of all current map values. +// Deprecated: Use EndpointMap.All() instead. func (em *EndpointMap[T]) Values() []T { ret := make([]T, 0, len(em.endpoints)) for _, val := range em.endpoints { @@ -240,6 +258,22 @@ func (em *EndpointMap[T]) Values() []T { return ret } +// All returns an iterator over all elements. +// The map keys are endpoints specifying the addresses present in the endpoint +// map, in which uniqueness is determined by the unordered set of addresses. +// Thus, endpoint information returned is not the full endpoint data (drops +// duplicated addresses and attributes) but can be used for EndpointMap +// accesses. +func (em *EndpointMap[T]) All() iter.Seq2[Endpoint, T] { + return func(yield func(Endpoint, T) bool) { + for _, en := range em.endpoints { + if !yield(en.decodedKey, en.value) { + return + } + } + } +} + // Delete removes the specified endpoint from the map. func (em *EndpointMap[T]) Delete(e Endpoint) { en := encodeEndpoint(e) diff --git a/vendor/google.golang.org/grpc/rpc_util.go b/vendor/google.golang.org/grpc/rpc_util.go index 8160f943..ee7f7dea 100644 --- a/vendor/google.golang.org/grpc/rpc_util.go +++ b/vendor/google.golang.org/grpc/rpc_util.go @@ -961,24 +961,32 @@ func recvAndDecompress(p *parser, s recvCompressor, dc Decompressor, maxReceiveM return out, nil } -// decompress processes the given data by decompressing it using either a custom decompressor or a standard compressor. -// If a custom decompressor is provided, it takes precedence. The function validates that the decompressed data -// does not exceed the specified maximum size and returns an error if this limit is exceeded. -// On success, it returns the decompressed data. Otherwise, it returns an error if decompression fails or the data exceeds the size limit. +// decompress processes the given data by decompressing it using either +// a custom decompressor or a standard compressor. If a custom decompressor +// is provided, it takes precedence. The function validates that +// the decompressed data does not exceed the specified maximum size and returns +// an error if this limit is exceeded. On success, it returns the decompressed +// data. Otherwise, it returns an error if decompression fails or the data +// exceeds the size limit. func decompress(compressor encoding.Compressor, d mem.BufferSlice, dc Decompressor, maxReceiveMessageSize int, pool mem.BufferPool) (mem.BufferSlice, error) { if dc != nil { - uncompressed, err := dc.Do(d.Reader()) + r := d.Reader() + uncompressed, err := dc.Do(r) if err != nil { + r.Close() // ensure buffers are reused return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message: %v", err) } if len(uncompressed) > maxReceiveMessageSize { + r.Close() // ensure buffers are reused return nil, status.Errorf(codes.ResourceExhausted, "grpc: message after decompression larger than max (%d vs. %d)", len(uncompressed), maxReceiveMessageSize) } return mem.BufferSlice{mem.SliceBuffer(uncompressed)}, nil } if compressor != nil { - dcReader, err := compressor.Decompress(d.Reader()) + r := d.Reader() + dcReader, err := compressor.Decompress(r) if err != nil { + r.Close() // ensure buffers are reused return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the message: %v", err) } @@ -990,11 +998,13 @@ func decompress(compressor encoding.Compressor, d mem.BufferSlice, dc Decompress } out, err := mem.ReadAll(dcReader, pool) if err != nil { + r.Close() // ensure buffers are reused out.Free() return nil, status.Errorf(codes.Internal, "grpc: failed to read decompressed data: %v", err) } if out.Len() > maxReceiveMessageSize { + r.Close() // ensure buffers are reused out.Free() return nil, status.Errorf(codes.ResourceExhausted, "grpc: received message after decompression larger than max %d", maxReceiveMessageSize) } diff --git a/vendor/google.golang.org/grpc/server.go b/vendor/google.golang.org/grpc/server.go index 8efb29a7..5229adf7 100644 --- a/vendor/google.golang.org/grpc/server.go +++ b/vendor/google.golang.org/grpc/server.go @@ -192,6 +192,7 @@ var defaultServerOptions = serverOptions{ maxSendMessageSize: defaultServerMaxSendMessageSize, connectionTimeout: 120 * time.Second, writeBufferSize: defaultWriteBufSize, + sharedWriteBuffer: true, readBufferSize: defaultReadBufSize, bufferPool: mem.DefaultBufferPool(), } diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go index 76c2eed7..12f649dc 100644 --- a/vendor/google.golang.org/grpc/version.go +++ b/vendor/google.golang.org/grpc/version.go @@ -19,4 +19,4 @@ package grpc // Version is the current grpc version. -const Version = "1.79.3" +const Version = "1.80.0" diff --git a/vendor/modules.txt b/vendor/modules.txt index 7789003f..c94b21fa 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,8 +1,8 @@ # github.com/Scalingo/errgo-rollbar v0.2.1 ## explicit; go 1.17 github.com/Scalingo/errgo-rollbar -# github.com/Scalingo/go-handlers v1.11.0 -## explicit; go 1.24.0 +# github.com/Scalingo/go-handlers v1.11.1 +## explicit; go 1.25.0 github.com/Scalingo/go-handlers # github.com/Scalingo/go-philae/v4 v4.4.7 ## explicit; go 1.17 @@ -18,18 +18,18 @@ github.com/Scalingo/go-utils/errors # github.com/Scalingo/go-utils/errors/v2 v2.5.1 ## explicit; go 1.24 github.com/Scalingo/go-utils/errors/v2 -# github.com/Scalingo/go-utils/errors/v3 v3.2.0 +# github.com/Scalingo/go-utils/errors/v3 v3.2.1 ## explicit; go 1.24 github.com/Scalingo/go-utils/errors/v3 -# github.com/Scalingo/go-utils/etcd v1.2.1 -## explicit; go 1.24 +# github.com/Scalingo/go-utils/etcd v1.2.2 +## explicit; go 1.25.0 github.com/Scalingo/go-utils/etcd -# github.com/Scalingo/go-utils/logger v1.12.1 -## explicit; go 1.25 +# github.com/Scalingo/go-utils/logger v1.12.2 +## explicit; go 1.25.0 github.com/Scalingo/go-utils/logger github.com/Scalingo/go-utils/logger/plugins/rollbarplugin -# github.com/Scalingo/go-utils/retry v1.4.0 -## explicit; go 1.25 +# github.com/Scalingo/go-utils/retry v1.4.1 +## explicit; go 1.25.0 github.com/Scalingo/go-utils/retry # github.com/Scalingo/go-utils/security v1.2.2 ## explicit; go 1.24 @@ -123,8 +123,8 @@ github.com/golang/protobuf/proto # github.com/gorilla/mux v1.8.1 ## explicit; go 1.20 github.com/gorilla/mux -# github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 -## explicit; go 1.24.0 +# github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 +## explicit; go 1.25.0 github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options # github.com/j-keck/arping v1.0.3 ## explicit; go 1.12 @@ -144,16 +144,16 @@ github.com/looplab/fsm # github.com/mattn/go-colorable v0.1.14 ## explicit; go 1.18 github.com/mattn/go-colorable -# github.com/mattn/go-isatty v0.0.20 -## explicit; go 1.15 +# github.com/mattn/go-isatty v0.0.22 +## explicit; go 1.21 github.com/mattn/go-isatty -# github.com/mattn/go-runewidth v0.0.21 +# github.com/mattn/go-runewidth v0.0.23 ## explicit; go 1.20 github.com/mattn/go-runewidth # github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 ## explicit; go 1.21 github.com/olekukonko/cat -# github.com/olekukonko/errors v1.2.0 +# github.com/olekukonko/errors v1.3.0 ## explicit; go 1.21 github.com/olekukonko/errors # github.com/olekukonko/ll v0.1.8 @@ -202,7 +202,7 @@ github.com/vishvananda/netlink/nl # github.com/vishvananda/netns v0.0.5 ## explicit; go 1.17 github.com/vishvananda/netns -# go.etcd.io/etcd/api/v3 v3.6.9 +# go.etcd.io/etcd/api/v3 v3.6.10 ## explicit; go 1.25.0 go.etcd.io/etcd/api/v3/authpb go.etcd.io/etcd/api/v3/etcdserverpb @@ -211,7 +211,7 @@ go.etcd.io/etcd/api/v3/mvccpb go.etcd.io/etcd/api/v3/v3rpc/rpctypes go.etcd.io/etcd/api/v3/version go.etcd.io/etcd/api/v3/versionpb -# go.etcd.io/etcd/client/pkg/v3 v3.6.9 +# go.etcd.io/etcd/client/pkg/v3 v3.6.10 ## explicit; go 1.25.0 go.etcd.io/etcd/client/pkg/v3/fileutil go.etcd.io/etcd/client/pkg/v3/logutil @@ -220,7 +220,7 @@ go.etcd.io/etcd/client/pkg/v3/tlsutil go.etcd.io/etcd/client/pkg/v3/transport go.etcd.io/etcd/client/pkg/v3/types go.etcd.io/etcd/client/pkg/v3/verify -# go.etcd.io/etcd/client/v3 v3.6.9 +# go.etcd.io/etcd/client/v3 v3.6.10 ## explicit; go 1.25.0 go.etcd.io/etcd/client/v3 go.etcd.io/etcd/client/v3/credentials @@ -230,12 +230,12 @@ go.etcd.io/etcd/client/v3/internal/resolver ## explicit; go 1.24.0 go.opentelemetry.io/auto/sdk go.opentelemetry.io/auto/sdk/internal/telemetry -# go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.67.0 +# go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.68.0 ## explicit; go 1.25.0 go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/internal/request go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv -# go.opentelemetry.io/otel v1.42.0 +# go.opentelemetry.io/otel v1.43.0 ## explicit; go 1.25.0 go.opentelemetry.io/otel go.opentelemetry.io/otel/attribute @@ -250,12 +250,12 @@ go.opentelemetry.io/otel/propagation go.opentelemetry.io/otel/semconv/v1.37.0 go.opentelemetry.io/otel/semconv/v1.40.0 go.opentelemetry.io/otel/semconv/v1.40.0/httpconv -# go.opentelemetry.io/otel/metric v1.42.0 +# go.opentelemetry.io/otel/metric v1.43.0 ## explicit; go 1.25.0 go.opentelemetry.io/otel/metric go.opentelemetry.io/otel/metric/embedded go.opentelemetry.io/otel/metric/noop -# go.opentelemetry.io/otel/trace v1.42.0 +# go.opentelemetry.io/otel/trace v1.43.0 ## explicit; go 1.25.0 go.opentelemetry.io/otel/trace go.opentelemetry.io/otel/trace/embedded @@ -264,7 +264,7 @@ go.opentelemetry.io/otel/trace/noop # go.uber.org/multierr v1.11.0 ## explicit; go 1.19 go.uber.org/multierr -# go.uber.org/zap v1.27.1 +# go.uber.org/zap v1.28.0 ## explicit; go 1.19 go.uber.org/zap go.uber.org/zap/buffer @@ -276,7 +276,7 @@ go.uber.org/zap/internal/pool go.uber.org/zap/internal/stacktrace go.uber.org/zap/zapcore go.uber.org/zap/zapgrpc -# golang.org/x/net v0.52.0 +# golang.org/x/net v0.53.0 ## explicit; go 1.25.0 golang.org/x/net/http/httpguts golang.org/x/net/http2 @@ -290,24 +290,24 @@ golang.org/x/net/trace ## explicit; go 1.25.0 golang.org/x/oauth2 golang.org/x/oauth2/internal -# golang.org/x/sys v0.42.0 +# golang.org/x/sys v0.43.0 ## explicit; go 1.25.0 golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/text v0.35.0 +# golang.org/x/text v0.36.0 ## explicit; go 1.25.0 golang.org/x/text/secure/bidirule golang.org/x/text/transform golang.org/x/text/unicode/bidi golang.org/x/text/unicode/norm -# google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 -## explicit; go 1.24.0 +# google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 +## explicit; go 1.25.0 google.golang.org/genproto/googleapis/api google.golang.org/genproto/googleapis/api/annotations -# google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 -## explicit; go 1.24.0 +# google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 +## explicit; go 1.25.0 google.golang.org/genproto/googleapis/rpc/status -# google.golang.org/grpc v1.79.3 +# google.golang.org/grpc v1.80.0 ## explicit; go 1.24.0 google.golang.org/grpc google.golang.org/grpc/attributes @@ -345,6 +345,7 @@ google.golang.org/grpc/internal/grpclog google.golang.org/grpc/internal/grpcsync google.golang.org/grpc/internal/grpcutil google.golang.org/grpc/internal/idle +google.golang.org/grpc/internal/mem google.golang.org/grpc/internal/metadata google.golang.org/grpc/internal/pretty google.golang.org/grpc/internal/proxyattributes