From 6af0d02d44db1791f9c796aa8eb5164ebab056ee Mon Sep 17 00:00:00 2001 From: wtifs Date: Wed, 30 Aug 2023 19:07:40 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20BBR=E9=99=90=E6=B5=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.go | 6 + api/config_file.go | 6 + api/config_file_impl.go | 15 + api_config.go | 15 + examples/configuration/crud/go.mod | 38 + examples/configuration/crud/go.sum | 962 +++++++++++++++++ examples/configuration/crud/main.go | 70 ++ examples/configuration/crud/polaris.yaml | 8 + examples/configuration/encrypt/go.mod | 2 +- examples/configuration/encrypt/go.sum | 4 +- examples/configuration/encrypt/polaris.yaml | 2 +- examples/configuration/fallback/go.mod | 38 + examples/configuration/fallback/go.sum | 967 ++++++++++++++++++ examples/configuration/fallback/main.go | 66 ++ examples/configuration/fallback/polaris.yaml | 30 + examples/quickstart/consumer/polaris.yaml | 2 +- examples/quickstart/provider/go.mod | 2 +- examples/quickstart/provider/go.sum | 4 +- examples/quickstart/provider/main.go | 2 +- examples/quickstart/provider/polaris.yaml | 2 +- examples/ratelimit/consumer/go.mod | 12 +- examples/ratelimit/consumer/go.sum | 33 +- examples/ratelimit/consumer/main.go | 2 +- examples/ratelimit/provider/go.mod | 12 +- examples/ratelimit/provider/go.sum | 33 +- examples/ratelimit/provider/main.go | 27 +- examples/route/nearby/consumer/polaris.yaml | 22 +- examples/route/nearby/provider/go.mod | 2 +- examples/route/nearby/provider/go.sum | 4 +- examples/route/nearby/provider/main.go | 28 + examples/route/nearby/provider/polaris.yaml | 16 +- go.mod | 8 +- go.sum | 42 +- pkg/config/api.go | 35 + pkg/config/config_file.go | 136 ++- pkg/config/default.go | 4 +- pkg/config/location_provider.go | 11 +- pkg/flow/configuration/config_flow.go | 140 ++- pkg/flow/configuration/file_repo.go | 171 +++- pkg/flow/configuration/local_cache.go | 195 ++++ pkg/flow/impl.go | 6 +- pkg/flow/quota/assist.go | 20 +- pkg/flow/quota/window.go | 9 + pkg/flow/sync_flow.go | 15 + pkg/model/engine.go | 6 + pkg/model/quota.go | 18 +- pkg/model/util.go | 26 + .../configconnector/config_connector.go | 6 + pkg/plugin/configconnector/config_file.go | 53 +- pkg/plugin/configconnector/proxy.go | 18 + pkg/plugin/configfilter/configfilter.go | 1 + pkg/plugin/ratelimiter/ratelimiter.go | 2 + pkg/plugin/register/plugins.go | 1 + .../polaris/config_connector.go | 129 ++- plugin/configfilter/crypto/crypto.go | 113 +- plugin/ratelimiter/bbr/README.md | 59 ++ plugin/ratelimiter/bbr/bucket.go | 106 ++ plugin/ratelimiter/bbr/core/bbr.go | 313 ++++++ plugin/ratelimiter/bbr/core/bbr_test.go | 285 ++++++ plugin/ratelimiter/bbr/cpu/cgroup.go | 126 +++ plugin/ratelimiter/bbr/cpu/cgroup_cpu.go | 242 +++++ plugin/ratelimiter/bbr/cpu/psutil_cpu.go | 47 + plugin/ratelimiter/bbr/cpu/stat.go | 68 ++ plugin/ratelimiter/bbr/cpu/stat_test.go | 21 + plugin/ratelimiter/bbr/cpu/utils.go | 121 +++ plugin/ratelimiter/bbr/img.jpg | Bin 0 -> 89650 bytes .../{cpubbr/cpubbr.go => bbr/plugin.go} | 24 +- plugin/ratelimiter/bbr/window/counter.go | 98 ++ plugin/ratelimiter/bbr/window/counter_test.go | 156 +++ plugin/ratelimiter/bbr/window/iterator.go | 26 + plugin/ratelimiter/bbr/window/policy.go | 97 ++ plugin/ratelimiter/bbr/window/policy_test.go | 106 ++ plugin/ratelimiter/bbr/window/reduce.go | 77 ++ plugin/ratelimiter/bbr/window/window.go | 108 ++ plugin/ratelimiter/bbr/window/window_test.go | 68 ++ plugin/ratelimiter/cpubbr/bucket.go | 76 -- plugin/ratelimiter/reject/bucket.go | 5 + plugin/ratelimiter/unirate/bucket_leaky.go | 5 + plugin/serverconnector/common/util.go | 21 + polaris.yaml | 14 + 80 files changed, 5534 insertions(+), 332 deletions(-) create mode 100644 examples/configuration/crud/go.mod create mode 100644 examples/configuration/crud/go.sum create mode 100644 examples/configuration/crud/main.go create mode 100644 examples/configuration/crud/polaris.yaml create mode 100644 examples/configuration/fallback/go.mod create mode 100644 examples/configuration/fallback/go.sum create mode 100644 examples/configuration/fallback/main.go create mode 100644 examples/configuration/fallback/polaris.yaml create mode 100644 pkg/flow/configuration/local_cache.go create mode 100644 plugin/ratelimiter/bbr/README.md create mode 100644 plugin/ratelimiter/bbr/bucket.go create mode 100644 plugin/ratelimiter/bbr/core/bbr.go create mode 100644 plugin/ratelimiter/bbr/core/bbr_test.go create mode 100644 plugin/ratelimiter/bbr/cpu/cgroup.go create mode 100644 plugin/ratelimiter/bbr/cpu/cgroup_cpu.go create mode 100644 plugin/ratelimiter/bbr/cpu/psutil_cpu.go create mode 100644 plugin/ratelimiter/bbr/cpu/stat.go create mode 100644 plugin/ratelimiter/bbr/cpu/stat_test.go create mode 100644 plugin/ratelimiter/bbr/cpu/utils.go create mode 100644 plugin/ratelimiter/bbr/img.jpg rename plugin/ratelimiter/{cpubbr/cpubbr.go => bbr/plugin.go} (57%) create mode 100644 plugin/ratelimiter/bbr/window/counter.go create mode 100644 plugin/ratelimiter/bbr/window/counter_test.go create mode 100644 plugin/ratelimiter/bbr/window/iterator.go create mode 100644 plugin/ratelimiter/bbr/window/policy.go create mode 100644 plugin/ratelimiter/bbr/window/policy_test.go create mode 100644 plugin/ratelimiter/bbr/window/reduce.go create mode 100644 plugin/ratelimiter/bbr/window/window.go create mode 100644 plugin/ratelimiter/bbr/window/window_test.go delete mode 100644 plugin/ratelimiter/cpubbr/bucket.go diff --git a/api.go b/api.go index b5346405..9cbbee5b 100644 --- a/api.go +++ b/api.go @@ -139,6 +139,12 @@ type ConfigAPI interface { api.SDKOwner // GetConfigFile obtaining the configuration file GetConfigFile(namespace, fileGroup, fileName string) (ConfigFile, error) + // CreateConfigFile create configuration file + CreateConfigFile(namespace, fileGroup, fileName, content string) error + // UpdateConfigFile update configuration file + UpdateConfigFile(namespace, fileGroup, fileName, content string) error + // PublishConfigFile publish configuration file + PublishConfigFile(namespace, fileGroup, fileName string) error } // RouterAPI routing api methods diff --git a/api/config_file.go b/api/config_file.go index b68e7dbf..b7c9d109 100644 --- a/api/config_file.go +++ b/api/config_file.go @@ -24,6 +24,12 @@ type ConfigFileAPI interface { SDKOwner // GetConfigFile 获取配置文件 GetConfigFile(namespace, fileGroup, fileName string) (model.ConfigFile, error) + // CreateConfigFile 创建配置文件 + CreateConfigFile(namespace, fileGroup, fileName, content string) error + // UpdateConfigFile 更新配置文件 + UpdateConfigFile(namespace, fileGroup, fileName, content string) error + // PublishConfigFile 发布配置文件 + PublishConfigFile(namespace, fileGroup, fileName string) error } var ( diff --git a/api/config_file_impl.go b/api/config_file_impl.go index 42574eec..ae45190a 100644 --- a/api/config_file_impl.go +++ b/api/config_file_impl.go @@ -57,6 +57,21 @@ func (c *configFileAPI) GetConfigFile(namespace, fileGroup, fileName string) (mo return c.context.GetEngine().SyncGetConfigFile(namespace, fileGroup, fileName) } +// CreateConfigFile 创建配置文件 +func (c *configFileAPI) CreateConfigFile(namespace, fileGroup, fileName, content string) error { + return c.context.GetEngine().SyncCreateConfigFile(namespace, fileGroup, fileName, content) +} + +// UpdateConfigFile 更新配置文件 +func (c *configFileAPI) UpdateConfigFile(namespace, fileGroup, fileName, content string) error { + return c.context.GetEngine().SyncUpdateConfigFile(namespace, fileGroup, fileName, content) +} + +// PublishConfigFile 发布配置文件 +func (c *configFileAPI) PublishConfigFile(namespace, fileGroup, fileName string) error { + return c.context.GetEngine().SyncPublishConfigFile(namespace, fileGroup, fileName) +} + // SDKContext 获取SDK上下文 func (c *configFileAPI) SDKContext() SDKContext { return c.context diff --git a/api_config.go b/api_config.go index ee675f05..cd1a26b2 100644 --- a/api_config.go +++ b/api_config.go @@ -72,6 +72,21 @@ func (c *configAPI) GetConfigFile(namespace, fileGroup, fileName string) (Config return c.rawAPI.GetConfigFile(namespace, fileGroup, fileName) } +// CreateConfigFile 创建配置文件 +func (c *configAPI) CreateConfigFile(namespace, fileGroup, fileName, content string) error { + return c.rawAPI.CreateConfigFile(namespace, fileGroup, fileName, content) +} + +// UpdateConfigFile 更新配置文件 +func (c *configAPI) UpdateConfigFile(namespace, fileGroup, fileName, content string) error { + return c.rawAPI.UpdateConfigFile(namespace, fileGroup, fileName, content) +} + +// PublishConfigFile 发布配置文件 +func (c *configAPI) PublishConfigFile(namespace, fileGroup, fileName string) error { + return c.rawAPI.PublishConfigFile(namespace, fileGroup, fileName) +} + // SDKContext 获取SDK上下文 func (c *configAPI) SDKContext() api.SDKContext { return c.rawAPI.SDKContext() diff --git a/examples/configuration/crud/go.mod b/examples/configuration/crud/go.mod new file mode 100644 index 00000000..9ab251fd --- /dev/null +++ b/examples/configuration/crud/go.mod @@ -0,0 +1,38 @@ +module github.com/polarismesh/polaris-go-configuration + +go 1.20 + +require github.com/polarismesh/polaris-go v1.5.4-incompatible + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/dlclark/regexp2 v1.7.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/natefinch/lumberjack v2.0.0+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/polarismesh/specification v1.4.0 // indirect + github.com/prometheus/client_golang v1.12.2 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.21.0 // indirect + golang.org/x/net v0.2.0 // indirect + golang.org/x/sys v0.2.0 // indirect + golang.org/x/text v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a // indirect + google.golang.org/grpc v1.51.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) + +replace github.com/polarismesh/polaris-go => ../../../ diff --git a/examples/configuration/crud/go.sum b/examples/configuration/crud/go.sum new file mode 100644 index 00000000..f3ab45ec --- /dev/null +++ b/examples/configuration/crud/go.sum @@ -0,0 +1,962 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw= +github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= +github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc= +github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+aosOB5+iEPoV3picfs8tUpkVd0pDo+Kg= +github.com/gonum/integrate v0.0.0-20181209220457-a422b5c0fdf2/go.mod h1:pDgmNM6seYpwvPos3q+zxlXMsbve6mOIPucUnUOrI7Y= +github.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhSyOzRwuXkOgAvijx4o+4YMUJJo9OvPYMkks= +github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2EAE789SSiSJNqxPaC0aE9J8NTOI0Jo/A= +github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw= +github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b/go.mod h1:Z4GIJBJO3Wa4gD4vbwQxXXZ+WHmW6E9ixmNrwvs0iZs= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM= +github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polarismesh/specification v1.4.0 h1:fm7sUtFZC2g9+lLmRCtjGrUow47CY5JDFoZXwwCQGGY= +github.com/polarismesh/specification v1.4.0/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/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= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +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= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a h1:GH6UPn3ixhWcKDhpnEC55S75cerLPdpp3hrhfKYjZgw= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/examples/configuration/crud/main.go b/examples/configuration/crud/main.go new file mode 100644 index 00000000..2cbcdb52 --- /dev/null +++ b/examples/configuration/crud/main.go @@ -0,0 +1,70 @@ +/** + * Tencent is pleased to support the open source community by making polaris-go available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 main + +import ( + "fmt" + + "github.com/polarismesh/polaris-go" +) + +func main() { + configAPI, err := polaris.NewConfigAPI() + + if err != nil { + fmt.Println("failed to start example.", err) + return + } + + // 获取远程的配置文件 + namespace := "default" + fileGroup := "polaris-config-example" + fileName := "example.yaml" + content := "hello world" + newContent := "bye~" + + err = configAPI.CreateConfigFile(namespace, fileGroup, fileName, content) + if err != nil { + fmt.Println("failed to create config file.", err) + return + } + + fmt.Println("[Create] Success") + + err = configAPI.UpdateConfigFile(namespace, fileGroup, fileName, newContent) + if err != nil { + fmt.Println("failed to update config file.", err) + return + } + + fmt.Println("[Update] Success") + + err = configAPI.PublishConfigFile(namespace, fileGroup, fileName) + if err != nil { + fmt.Println("failed to publish config file.", err) + return + } + + configFile, err := configAPI.GetConfigFile(namespace, fileGroup, fileName) + if err != nil { + fmt.Println("failed to get config file.", err) + return + } + + fmt.Printf("config file is %#v\n", configFile) +} diff --git a/examples/configuration/crud/polaris.yaml b/examples/configuration/crud/polaris.yaml new file mode 100644 index 00000000..fdee6156 --- /dev/null +++ b/examples/configuration/crud/polaris.yaml @@ -0,0 +1,8 @@ +global: + serverConnector: + addresses: + - 127.0.0.1:8091 +config: + configConnector: + addresses: + - 127.0.0.1:8093 diff --git a/examples/configuration/encrypt/go.mod b/examples/configuration/encrypt/go.mod index dfc41598..a5879e8e 100644 --- a/examples/configuration/encrypt/go.mod +++ b/examples/configuration/encrypt/go.mod @@ -17,7 +17,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/natefinch/lumberjack v2.0.0+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/polarismesh/specification v1.3.2-alpha.2 // indirect + github.com/polarismesh/specification v1.4.0 // indirect github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect diff --git a/examples/configuration/encrypt/go.sum b/examples/configuration/encrypt/go.sum index 093a5191..41c830a6 100644 --- a/examples/configuration/encrypt/go.sum +++ b/examples/configuration/encrypt/go.sum @@ -375,8 +375,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polarismesh/specification v1.3.2-alpha.2 h1:cMghyvCnRVM5ca2kYCGHOgIIxVnokiMvw0720q8a8RA= -github.com/polarismesh/specification v1.3.2-alpha.2/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= +github.com/polarismesh/specification v1.4.0 h1:fm7sUtFZC2g9+lLmRCtjGrUow47CY5JDFoZXwwCQGGY= +github.com/polarismesh/specification v1.4.0/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= diff --git a/examples/configuration/encrypt/polaris.yaml b/examples/configuration/encrypt/polaris.yaml index 6eba4c40..017558e8 100644 --- a/examples/configuration/encrypt/polaris.yaml +++ b/examples/configuration/encrypt/polaris.yaml @@ -1,7 +1,7 @@ global: serverConnector: addresses: - - 119.91.66.223:8091 + - 127.0.0.1:8091 config: configConnector: addresses: diff --git a/examples/configuration/fallback/go.mod b/examples/configuration/fallback/go.mod new file mode 100644 index 00000000..1e44571c --- /dev/null +++ b/examples/configuration/fallback/go.mod @@ -0,0 +1,38 @@ +module github.com/polarismesh/polaris-go-configuration + +go 1.17 + +require github.com/polarismesh/polaris-go v1.4.3 + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/dlclark/regexp2 v1.7.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/natefinch/lumberjack v2.0.0+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/polarismesh/specification v1.4.1 // indirect + github.com/prometheus/client_golang v1.12.2 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.21.0 // indirect + golang.org/x/net v0.2.0 // indirect + golang.org/x/sys v0.2.0 // indirect + golang.org/x/text v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a // indirect + google.golang.org/grpc v1.51.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) + +replace github.com/polarismesh/polaris-go => ../../../ diff --git a/examples/configuration/fallback/go.sum b/examples/configuration/fallback/go.sum new file mode 100644 index 00000000..0a144418 --- /dev/null +++ b/examples/configuration/fallback/go.sum @@ -0,0 +1,967 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw= +github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= +github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc= +github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+aosOB5+iEPoV3picfs8tUpkVd0pDo+Kg= +github.com/gonum/integrate v0.0.0-20181209220457-a422b5c0fdf2/go.mod h1:pDgmNM6seYpwvPos3q+zxlXMsbve6mOIPucUnUOrI7Y= +github.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhSyOzRwuXkOgAvijx4o+4YMUJJo9OvPYMkks= +github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2EAE789SSiSJNqxPaC0aE9J8NTOI0Jo/A= +github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw= +github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b/go.mod h1:Z4GIJBJO3Wa4gD4vbwQxXXZ+WHmW6E9ixmNrwvs0iZs= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM= +github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polarismesh/specification v1.4.1 h1:lTZqeyUhhWuKyr6NDKBwmUrNfcUDvKLxWT/uOq71T5A= +github.com/polarismesh/specification v1.4.1/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/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= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +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= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a h1:GH6UPn3ixhWcKDhpnEC55S75cerLPdpp3hrhfKYjZgw= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/examples/configuration/fallback/main.go b/examples/configuration/fallback/main.go new file mode 100644 index 00000000..0e1b5684 --- /dev/null +++ b/examples/configuration/fallback/main.go @@ -0,0 +1,66 @@ +/** + * Tencent is pleased to support the open source community by making polaris-go available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 main + +import ( + "fmt" + "log" + + "github.com/polarismesh/polaris-go" + "github.com/polarismesh/polaris-go/pkg/model" +) + +func main() { + configAPI, err := polaris.NewConfigAPI() + + if err != nil { + fmt.Println("fail to start example.", err) + return + } + + // 获取远程的配置文件 + namespace := "default" + fileGroup := "polaris-config-example" + fileName := "example.yaml" + + configFile, err := configAPI.GetConfigFile(namespace, fileGroup, fileName) + if err != nil { + log.Println("fail to get config.", err) + return + } + + // 打印配置文件内容 + log.Println(configFile.GetContent()) + + // 方式一:添加监听器 + configFile.AddChangeListener(changeListener) + + // 方式二:添加监听器 + changeChan := configFile.AddChangeListenerWithChannel() + + for { + select { + case event := <-changeChan: + log.Printf("received change event by channel. %+v", event) + } + } +} + +func changeListener(event model.ConfigFileChangeEvent) { + log.Printf("received change event. %+v", event) +} diff --git a/examples/configuration/fallback/polaris.yaml b/examples/configuration/fallback/polaris.yaml new file mode 100644 index 00000000..71ef36c2 --- /dev/null +++ b/examples/configuration/fallback/polaris.yaml @@ -0,0 +1,30 @@ +global: + serverConnector: + addresses: + - 127.0.0.1:8091 +config: + # 本地缓存配置 + localCache: + #描述: 配置文件持久化到本地开关 + persistEnable: true + #描述: 配置文件持久化目录,SDK在配置文件变更后,把相关的配置持久化到本地磁盘 + persistDir: ./polaris/backup/config + #描述: 配置文件写盘失败的最大重试次数 + persistMaxWriteRetry: 1 + #描述: 配置文件从磁盘读取失败的最大重试次数 + persistMaxReadRetry: 0 + #描述: 缓存读写磁盘的重试间隔 + persistRetryInterval: 500ms + #描述: 远端获取配置文件失败,兜底降级到本地文件缓存 + fallbackToLocalCache: true + configConnector: + addresses: + - 127.0.0.1:18093 + configFilter: + enable: true + chain: + - crypto + plugin: + crypto: + entries: + - name: AES diff --git a/examples/quickstart/consumer/polaris.yaml b/examples/quickstart/consumer/polaris.yaml index c6ac55cf..07e08516 100644 --- a/examples/quickstart/consumer/polaris.yaml +++ b/examples/quickstart/consumer/polaris.yaml @@ -1,7 +1,7 @@ global: serverConnector: addresses: - - 119.91.66.223:8091 + - 127.0.0.1:8091 statReporter: enable: true chain: diff --git a/examples/quickstart/provider/go.mod b/examples/quickstart/provider/go.mod index 6d4d9274..dc988a11 100644 --- a/examples/quickstart/provider/go.mod +++ b/examples/quickstart/provider/go.mod @@ -17,7 +17,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/natefinch/lumberjack v2.0.0+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/polarismesh/specification v1.3.2-alpha.2 // indirect + github.com/polarismesh/specification v1.4.0 // indirect github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect diff --git a/examples/quickstart/provider/go.sum b/examples/quickstart/provider/go.sum index 093a5191..41c830a6 100644 --- a/examples/quickstart/provider/go.sum +++ b/examples/quickstart/provider/go.sum @@ -375,8 +375,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polarismesh/specification v1.3.2-alpha.2 h1:cMghyvCnRVM5ca2kYCGHOgIIxVnokiMvw0720q8a8RA= -github.com/polarismesh/specification v1.3.2-alpha.2/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= +github.com/polarismesh/specification v1.4.0 h1:fm7sUtFZC2g9+lLmRCtjGrUow47CY5JDFoZXwwCQGGY= +github.com/polarismesh/specification v1.4.0/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= diff --git a/examples/quickstart/provider/main.go b/examples/quickstart/provider/main.go index aaee4349..b611f08a 100644 --- a/examples/quickstart/provider/main.go +++ b/examples/quickstart/provider/main.go @@ -98,7 +98,7 @@ func (svr *PolarisProvider) registerService() { registerRequest.Host = svr.host registerRequest.Port = svr.port registerRequest.ServiceToken = token - registerRequest.SetTTL(10) + registerRequest.SetTTL(1) // 实例id不是必填,如果不填,服务端会默认生成一个唯一Id,否则当提供实例id时,需要保证实例id是唯一的 registerRequest.InstanceId = providedInstanceId(namespace, service, svr.host, svr.port) resp, err := svr.provider.RegisterInstance(registerRequest) diff --git a/examples/quickstart/provider/polaris.yaml b/examples/quickstart/provider/polaris.yaml index c6ac55cf..07e08516 100644 --- a/examples/quickstart/provider/polaris.yaml +++ b/examples/quickstart/provider/polaris.yaml @@ -1,7 +1,7 @@ global: serverConnector: addresses: - - 119.91.66.223:8091 + - 127.0.0.1:8091 statReporter: enable: true chain: diff --git a/examples/ratelimit/consumer/go.mod b/examples/ratelimit/consumer/go.mod index 433cb94b..b424a974 100644 --- a/examples/ratelimit/consumer/go.mod +++ b/examples/ratelimit/consumer/go.mod @@ -8,26 +8,34 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect + github.com/go-kratos/aegis v0.2.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/natefinch/lumberjack v2.0.0+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/polarismesh/specification v1.3.2-alpha.2 // indirect + github.com/polarismesh/specification v1.4.0 // indirect + github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect + github.com/shirou/gopsutil/v3 v3.23.2 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/tklauser/go-sysconf v0.3.11 // indirect + github.com/tklauser/numcpus v0.6.0 // indirect + github.com/yusufpapurcu/wmi v1.2.2 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.21.0 // indirect golang.org/x/net v0.2.0 // indirect - golang.org/x/sys v0.2.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/text v0.4.0 // indirect google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a // indirect google.golang.org/grpc v1.51.0 // indirect diff --git a/examples/ratelimit/consumer/go.sum b/examples/ratelimit/consumer/go.sum index 093a5191..496fcd53 100644 --- a/examples/ratelimit/consumer/go.sum +++ b/examples/ratelimit/consumer/go.sum @@ -226,15 +226,20 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kratos/aegis v0.2.0 h1:dObzCDWn3XVjUkgxyBp6ZeWtx/do0DPZ7LY3yNSJLUQ= +github.com/go-kratos/aegis v0.2.0/go.mod h1:v0R2m73WgEEYB3XYu6aE2WcMwsZkJ/Rzuf5eVccm7bI= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -285,8 +290,9 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -354,6 +360,9 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de h1:V53FWzU6KAZVi1tPp5UIsMoUWJ2/PNwYIDXnu7QuBCE= +github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -375,8 +384,11 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polarismesh/specification v1.3.2-alpha.2 h1:cMghyvCnRVM5ca2kYCGHOgIIxVnokiMvw0720q8a8RA= -github.com/polarismesh/specification v1.3.2-alpha.2/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= +github.com/polarismesh/specification v1.4.0 h1:fm7sUtFZC2g9+lLmRCtjGrUow47CY5JDFoZXwwCQGGY= +github.com/polarismesh/specification v1.4.0/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig= +github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -401,6 +413,8 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/shirou/gopsutil/v3 v3.23.2 h1:PAWSuiAszn7IhPMBtXsbSCafej7PqUOvY6YywlQUExU= +github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -425,12 +439,19 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= +github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= +github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= +github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= +github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/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= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -590,6 +611,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -613,6 +635,7 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -649,8 +672,10 @@ golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= diff --git a/examples/ratelimit/consumer/main.go b/examples/ratelimit/consumer/main.go index 107fc93a..ed424591 100644 --- a/examples/ratelimit/consumer/main.go +++ b/examples/ratelimit/consumer/main.go @@ -78,7 +78,7 @@ func (svr *PolarisConsumer) runWebServer() { if err != nil { log.Printf("[errot] send request to %s:%d fail : %s", instance.GetHost(), instance.GetPort(), err) rw.WriteHeader(http.StatusInternalServerError) - _, _ = rw.Write([]byte(fmt.Sprintf("[errot] send request to %s:%d fail : %s", instance.GetHost(), instance.GetPort(), err))) + _, _ = rw.Write([]byte(fmt.Sprintf("[error] send request to %s:%d fail : %s", instance.GetHost(), instance.GetPort(), err))) time.Sleep(time.Millisecond * time.Duration(rand.Intn(10))) delay := time.Since(start) diff --git a/examples/ratelimit/provider/go.mod b/examples/ratelimit/provider/go.mod index fc3a5827..7db41060 100644 --- a/examples/ratelimit/provider/go.mod +++ b/examples/ratelimit/provider/go.mod @@ -8,26 +8,34 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect + github.com/go-kratos/aegis v0.2.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/natefinch/lumberjack v2.0.0+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/polarismesh/specification v1.3.2-alpha.2 // indirect + github.com/polarismesh/specification v1.4.0 // indirect + github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect + github.com/shirou/gopsutil/v3 v3.23.2 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/tklauser/go-sysconf v0.3.11 // indirect + github.com/tklauser/numcpus v0.6.0 // indirect + github.com/yusufpapurcu/wmi v1.2.2 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.21.0 // indirect golang.org/x/net v0.2.0 // indirect - golang.org/x/sys v0.2.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/text v0.4.0 // indirect google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a // indirect google.golang.org/grpc v1.51.0 // indirect diff --git a/examples/ratelimit/provider/go.sum b/examples/ratelimit/provider/go.sum index 093a5191..496fcd53 100644 --- a/examples/ratelimit/provider/go.sum +++ b/examples/ratelimit/provider/go.sum @@ -226,15 +226,20 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kratos/aegis v0.2.0 h1:dObzCDWn3XVjUkgxyBp6ZeWtx/do0DPZ7LY3yNSJLUQ= +github.com/go-kratos/aegis v0.2.0/go.mod h1:v0R2m73WgEEYB3XYu6aE2WcMwsZkJ/Rzuf5eVccm7bI= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -285,8 +290,9 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -354,6 +360,9 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de h1:V53FWzU6KAZVi1tPp5UIsMoUWJ2/PNwYIDXnu7QuBCE= +github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -375,8 +384,11 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polarismesh/specification v1.3.2-alpha.2 h1:cMghyvCnRVM5ca2kYCGHOgIIxVnokiMvw0720q8a8RA= -github.com/polarismesh/specification v1.3.2-alpha.2/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= +github.com/polarismesh/specification v1.4.0 h1:fm7sUtFZC2g9+lLmRCtjGrUow47CY5JDFoZXwwCQGGY= +github.com/polarismesh/specification v1.4.0/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig= +github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -401,6 +413,8 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/shirou/gopsutil/v3 v3.23.2 h1:PAWSuiAszn7IhPMBtXsbSCafej7PqUOvY6YywlQUExU= +github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -425,12 +439,19 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= +github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= +github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= +github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= +github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/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= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -590,6 +611,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -613,6 +635,7 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -649,8 +672,10 @@ golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= diff --git a/examples/ratelimit/provider/main.go b/examples/ratelimit/provider/main.go index 72ab62c7..b1247e8f 100644 --- a/examples/ratelimit/provider/main.go +++ b/examples/ratelimit/provider/main.go @@ -20,6 +20,8 @@ package main import ( "flag" "fmt" + "github.com/polarismesh/polaris-go" + "github.com/polarismesh/polaris-go/pkg/model" "log" "net" "net/http" @@ -28,9 +30,6 @@ import ( "strings" "syscall" "time" - - "github.com/polarismesh/polaris-go" - "github.com/polarismesh/polaris-go/pkg/model" ) var ( @@ -81,22 +80,16 @@ func (svr *PolarisProvider) runWebServer() { quotaReq.SetNamespace(namespace) quotaReq.SetService(service) - log.Printf("[info] get quota req : ns=%s, svc=%s, method=%v, labels=%v", - quotaReq.GetNamespace(), quotaReq.GetService(), quotaReq.GetMethod(), quotaReq.GetLabels()) - start := time.Now() + //log.Printf("[info] get quota req : ns=%s, svc=%s, method=%v, labels=%v", + // quotaReq.GetNamespace(), quotaReq.GetService(), quotaReq.GetMethod(), quotaReq.GetLabels()) + //start := time.Now() resp, err := svr.limiter.GetQuota(quotaReq) if err != nil { rw.WriteHeader(http.StatusInternalServerError) _, _ = rw.Write([]byte(fmt.Sprintf("[error] fail to GetQuota, err is %v", err))) return } - log.Printf("[info] %s get quota resp : code=%d, info=%s", time.Since(start).String(), resp.Get().Code, resp.Get().Info) - - if err != nil { - rw.WriteHeader(http.StatusInternalServerError) - _, _ = rw.Write([]byte(fmt.Sprintf("[error] fail to GetQuota, err is %v", err))) - return - } + //log.Printf("[info] %s get quota resp : code=%d, info=%s", time.Since(start).String(), resp.Get().Code, resp.Get().Info) if resp.Get().Code != model.QuotaResultOk { rw.WriteHeader(http.StatusTooManyRequests) @@ -106,6 +99,10 @@ func (svr *PolarisProvider) runWebServer() { rw.WriteHeader(http.StatusOK) _, _ = rw.Write([]byte(fmt.Sprintf("Hello, I'm RateLimitEchoServer Provider, My host : %s:%d", svr.host, svr.port))) + + // 模拟远端处理耗时 + time.Sleep(time.Millisecond * 500) + resp.Release() }) ln, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port)) @@ -117,7 +114,9 @@ func (svr *PolarisProvider) runWebServer() { go func() { log.Printf("[INFO] start http server, listen port is %v", svr.port) - if err := http.Serve(ln, nil); err != nil { + s := &http.Server{} + s.SetKeepAlivesEnabled(false) + if err := s.Serve(ln); err != nil { log.Fatalf("[ERROR]fail to run webServer, err is %v", err) } }() diff --git a/examples/route/nearby/consumer/polaris.yaml b/examples/route/nearby/consumer/polaris.yaml index 7e3b7c02..5ee581ef 100644 --- a/examples/route/nearby/consumer/polaris.yaml +++ b/examples/route/nearby/consumer/polaris.yaml @@ -1,22 +1,14 @@ global: serverConnector: addresses: - - 183.47.111.80:8091 + - 127.0.0.1:8091 + # 地址提供插件,用于获取当前SDK所在的地域信息 location: - # 设置 polaris-go 进程地理信息的提供插件 - # 设置为 env 时,可以在 linux 中注入以下环境变量 - # POLARIS_INSTANCE_REGION: 设置 region 信息, 例如 china - # POLARIS_INSTANCE_ZONE: 设置 zone 信息, 例如 ap-guangzhou - # POLARIS_INSTANCE_CAMPUS: 设置 IDC 信息, 例如 ap-guangzhou-3 - provider: env - statReporter: - enable: true - chain: - - prometheus - plugin: - prometheus: - type: pull - metricPort: 0 + providers: + - type: local + region: ${REGION} + zone: ${ZONE} + campus: ${CAMPUS} consumer: serviceRouter: # 服务路由链 diff --git a/examples/route/nearby/provider/go.mod b/examples/route/nearby/provider/go.mod index 1fff7a25..0b82dabb 100644 --- a/examples/route/nearby/provider/go.mod +++ b/examples/route/nearby/provider/go.mod @@ -17,7 +17,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/natefinch/lumberjack v2.0.0+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/polarismesh/specification v1.3.2-alpha.2 // indirect + github.com/polarismesh/specification v1.4.0 // indirect github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect diff --git a/examples/route/nearby/provider/go.sum b/examples/route/nearby/provider/go.sum index 093a5191..41c830a6 100644 --- a/examples/route/nearby/provider/go.sum +++ b/examples/route/nearby/provider/go.sum @@ -375,8 +375,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polarismesh/specification v1.3.2-alpha.2 h1:cMghyvCnRVM5ca2kYCGHOgIIxVnokiMvw0720q8a8RA= -github.com/polarismesh/specification v1.3.2-alpha.2/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= +github.com/polarismesh/specification v1.4.0 h1:fm7sUtFZC2g9+lLmRCtjGrUow47CY5JDFoZXwwCQGGY= +github.com/polarismesh/specification v1.4.0/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= diff --git a/examples/route/nearby/provider/main.go b/examples/route/nearby/provider/main.go index 7b307084..8d469520 100644 --- a/examples/route/nearby/provider/main.go +++ b/examples/route/nearby/provider/main.go @@ -19,10 +19,12 @@ package main import ( "context" + "encoding/json" "flag" "fmt" "log" "net" + "net/http" "os" "os/signal" "strings" @@ -90,6 +92,7 @@ func (svr *PolarisProvider) Run() { host = tmpHost svr.host = tmpHost } + svr.runWebServer() svr.registerService() svr.runMainLoop() } @@ -125,6 +128,31 @@ func (svr *PolarisProvider) deregisterService() { log.Printf("deregister successfully.") } +func (svr *PolarisProvider) runWebServer() { + http.HandleFunc("/echo", func(rw http.ResponseWriter, r *http.Request) { + rw.WriteHeader(http.StatusOK) + loc := svr.provider.SDKContext().GetValueContext().GetCurrentLocation().GetLocation() + locStr, _ := json.Marshal(loc) + msg := fmt.Sprintf("Hello, I'm RouteNearbyEchoServer Provider, MyLocInfo's : %s, host : %s:%d", string(locStr), svr.host, svr.port) + _, _ = rw.Write([]byte(msg)) + }) + + ln, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", svr.port)) + if err != nil { + log.Fatalf("[ERROR]fail to listen tcp, err is %v", err) + } + + svr.port = ln.Addr().(*net.TCPAddr).Port + + go func() { + log.Printf("[INFO] start http server, listen port is %v", svr.port) + if err := http.Serve(ln, nil); err != nil { + log.Fatalf("[ERROR]fail to run webServer, err is %v", err) + } + }() + +} + func (svr *PolarisProvider) runMainLoop() { ch := make(chan os.Signal, 1) signal.Notify(ch, []os.Signal{ diff --git a/examples/route/nearby/provider/polaris.yaml b/examples/route/nearby/provider/polaris.yaml index ebdfbbd1..614bd51b 100644 --- a/examples/route/nearby/provider/polaris.yaml +++ b/examples/route/nearby/provider/polaris.yaml @@ -1,14 +1,16 @@ global: serverConnector: addresses: - - 183.47.111.80:8091 + - 119.91.66.223:8091 + # 地址提供插件,用于获取当前SDK所在的地域信息 location: - # 设置 polaris-go 进程地理信息的提供插件 - # 设置为 env 时,可以在 linux 中注入以下环境变量 - # POLARIS_INSTANCE_REGION: 设置 region 信息, 例如 china - # POLARIS_INSTANCE_ZONE: 设置 zone 信息, 例如 ap-guangzhou - # POLARIS_INSTANCE_CAMPUS: 设置 IDC 信息, 例如 ap-guangzhou-3 - provider: env + providers: + - type: local + options: + region: ${REGION} + zone: ${ZONE} + campus: ${CAMPUS} +#描述:主调端配置 statReporter: enable: true chain: diff --git a/go.mod b/go.mod index 7f2879bd..01acd169 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,10 @@ module github.com/polarismesh/polaris-go -replace github.com/polarismesh/specification => ../../wtifs/specification - go 1.15 require ( github.com/agiledragon/gomonkey v2.0.2+incompatible github.com/dlclark/regexp2 v1.7.0 - github.com/go-kratos/aegis v0.2.0 github.com/golang/protobuf v1.5.2 github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac // indirect github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82 // indirect @@ -22,11 +19,12 @@ require ( github.com/modern-go/reflect2 v1.0.2 github.com/natefinch/lumberjack v2.0.0+incompatible github.com/pkg/errors v0.9.1 - github.com/polarismesh/specification v1.4.0 + github.com/polarismesh/specification v1.4.1 github.com/prometheus/client_golang v1.12.2 + github.com/shirou/gopsutil/v3 v3.23.8 github.com/smartystreets/goconvey v1.7.2 github.com/spaolacci/murmur3 v1.1.0 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.21.0 google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a // indirect google.golang.org/grpc v1.51.0 diff --git a/go.sum b/go.sum index b3185b73..e103ecfe 100644 --- a/go.sum +++ b/go.sum @@ -226,8 +226,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kratos/aegis v0.2.0 h1:dObzCDWn3XVjUkgxyBp6ZeWtx/do0DPZ7LY3yNSJLUQ= -github.com/go-kratos/aegis v0.2.0/go.mod h1:v0R2m73WgEEYB3XYu6aE2WcMwsZkJ/Rzuf5eVccm7bI= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -239,7 +237,6 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -366,9 +363,8 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de h1:V53FWzU6KAZVi1tPp5UIsMoUWJ2/PNwYIDXnu7QuBCE= -github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -389,9 +385,10 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polarismesh/specification v1.4.1 h1:lTZqeyUhhWuKyr6NDKBwmUrNfcUDvKLxWT/uOq71T5A= +github.com/polarismesh/specification v1.4.1/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig= -github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -416,8 +413,12 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/shirou/gopsutil/v3 v3.23.2 h1:PAWSuiAszn7IhPMBtXsbSCafej7PqUOvY6YywlQUExU= -github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M= +github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= +github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -440,21 +441,20 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= -github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= -github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= -github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= -github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/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= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= -github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -677,9 +677,9 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/config/api.go b/pkg/config/api.go index dce8cf62..983a48c9 100644 --- a/pkg/config/api.go +++ b/pkg/config/api.go @@ -85,6 +85,8 @@ type ConfigFileConfig interface { GetPropertiesValueCacheSize() int32 // GetPropertiesValueExpireTime 缓存的过期时间,默认为 60s GetPropertiesValueExpireTime() int64 + // GetLocalCache . + GetLocalCache() ConfigLocalCacheConfig } // RateLimitConfig 限流相关配置. @@ -488,6 +490,39 @@ type ServiceSpecificConfig interface { GetServiceRouter() ServiceRouterConfig } +type ConfigLocalCacheConfig interface { + BaseConfig + // IsPersistEnable consumer.localCache.persistEnable + // 是否启用本地缓存 + IsPersistEnable() bool + // SetPersistEnable 设置是否启用本地缓存 + SetPersistEnable(enable bool) + // GetPersistDir consumer.localCache.persistDir + // 本地缓存持久化路径 + GetPersistDir() string + // SetPersistDir 设置本地缓存持久化路径 + SetPersistDir(string) + // GetPersistMaxWriteRetry consumer.localCache.persistMaxWriteRetry + // 缓存最大写重试次数 + GetPersistMaxWriteRetry() int + // SetPersistMaxWriteRetry 设置缓存最大写重试次数 + SetPersistMaxWriteRetry(int) + // GetPersistMaxReadRetry consumer.localCache.persistMaxReadRetry + // 缓存最大读重试次数 + GetPersistMaxReadRetry() int + // SetPersistMaxReadRetry 设置缓存最大读重试次数 + SetPersistMaxReadRetry(int) + // GetPersistRetryInterval consumer.localCache.persistRetryInterval + // 缓存持久化重试间隔 + GetPersistRetryInterval() time.Duration + // SetPersistRetryInterval 设置缓存持久化重试间隔 + SetPersistRetryInterval(time.Duration) + // SetFallbackToLocalCache . + SetFallbackToLocalCache(enable bool) + // IsFallbackToLocalCache . + IsFallbackToLocalCache() bool +} + // ConfigConnectorConfig 配置中心连接相关的配置. type ConfigConnectorConfig interface { ServerConnectorConfig diff --git a/pkg/config/config_file.go b/pkg/config/config_file.go index e10ca7b1..13617600 100644 --- a/pkg/config/config_file.go +++ b/pkg/config/config_file.go @@ -21,9 +21,13 @@ package config import ( "errors" "fmt" + "path/filepath" + "time" "github.com/golang/protobuf/proto" "github.com/hashicorp/go-multierror" + + "github.com/polarismesh/polaris-go/pkg/model" ) // DefaultConfigFileEnable 默认打开配置中心能力 @@ -31,8 +35,9 @@ var DefaultConfigFileEnable = true // ConfigFileConfigImpl 对接配置中心相关配置. type ConfigFileConfigImpl struct { - ConfigConnectorConfig *ConfigConnectorConfigImpl `yaml:"configConnector" json:"configConnector"` - ConfigFilterConfig *ConfigFilterConfigImpl `yaml:"configFilter" json:"configFilter"` + LocalCache *ConfigLocalCacheConfigImpl `yaml:"localCache" json:"localCache"` + ConfigConnectorConfig *ConfigConnectorConfigImpl `yaml:"configConnector" json:"configConnector"` + ConfigFilterConfig *ConfigFilterConfigImpl `yaml:"configFilter" json:"configFilter"` // 是否启动配置中心 Enable *bool `yaml:"enable" json:"enable"` PropertiesValueCacheSize *int32 `yaml:"propertiesValueCacheSize" json:"propertiesValueCacheSize"` @@ -79,6 +84,11 @@ func (c *ConfigFileConfigImpl) SetPropertiesValueExpireTime(propertiesValueExpir c.PropertiesValueExpireTime = &propertiesValueExpireTime } +// GetLocalCache . +func (c *ConfigFileConfigImpl) GetLocalCache() ConfigLocalCacheConfig { + return c.LocalCache +} + // Verify 检验ConfigConnector配置. func (c *ConfigFileConfigImpl) Verify() error { if c == nil { @@ -107,6 +117,7 @@ func (c *ConfigFileConfigImpl) Verify() error { func (c *ConfigFileConfigImpl) SetDefault() { c.ConfigConnectorConfig.SetDefault() c.ConfigFilterConfig.SetDefault() + c.LocalCache.SetDefault() if c.Enable == nil { c.Enable = &DefaultConfigFileEnable } @@ -124,4 +135,125 @@ func (c *ConfigFileConfigImpl) Init() { c.ConfigConnectorConfig.Init() c.ConfigFilterConfig = &ConfigFilterConfigImpl{} c.ConfigFilterConfig.Init() + c.LocalCache = &ConfigLocalCacheConfigImpl{} + c.LocalCache.Init() +} + +// ConfigLocalCacheConfigImpl 本地缓存配置. +type ConfigLocalCacheConfigImpl struct { + // config.localCache.persistDir + // 本地缓存持久化路径 + PersistDir string `yaml:"persistDir" json:"persistDir"` + // 是否启用本地缓存 + PersistEnable *bool `yaml:"persistEnable" json:"persistEnable"` + // config.localCache.persistMaxWriteRetry + PersistMaxWriteRetry int `yaml:"persistMaxWriteRetry" json:"persistMaxWriteRetry"` + // config.localCache.persistReadRetry + PersistMaxReadRetry int `yaml:"persistMaxReadRetry" json:"persistMaxReadRetry"` + // config.localCache.persistRetryInterval + PersistRetryInterval *time.Duration `yaml:"persistRetryInterval" json:"persistRetryInterval"` + // config.localCache.fallbackToLocalCache + FallbackToLocalCache *bool `yaml:"fallbackToLocalCache" json:"fallbackToLocalCache"` +} + +// IsPersistEnable consumer.localCache.persistEnable +// 是否启用本地缓存 +func (l *ConfigLocalCacheConfigImpl) IsPersistEnable() bool { + if l.PersistEnable == nil { + return true + } + return *l.PersistEnable +} + +// SetPersistEnable 设置是否启用本地缓存 +func (l *ConfigLocalCacheConfigImpl) SetPersistEnable(enable bool) { + l.PersistEnable = &enable +} + +// GetPersistDir consumer.localCache.persist.path +// 本地缓存持久化路径. +func (l *ConfigLocalCacheConfigImpl) GetPersistDir() string { + return l.PersistDir +} + +// SetPersistDir 设置本地缓存持久化路径. +func (l *ConfigLocalCacheConfigImpl) SetPersistDir(dir string) { + l.PersistDir = dir +} + +// GetPersistMaxWriteRetry consumer.localCache.persist.maxWriteRetry. +func (l *ConfigLocalCacheConfigImpl) GetPersistMaxWriteRetry() int { + return l.PersistMaxWriteRetry +} + +// SetPersistMaxWriteRetry 设置本地缓存持久化写入失败重试次数. +func (l *ConfigLocalCacheConfigImpl) SetPersistMaxWriteRetry(maxWriteRetry int) { + l.PersistMaxWriteRetry = maxWriteRetry +} + +// GetPersistMaxReadRetry consumer.localCache.persist.maxReadRetry. +func (l *ConfigLocalCacheConfigImpl) GetPersistMaxReadRetry() int { + return l.PersistMaxReadRetry +} + +// SetPersistMaxReadRetry 设置本地缓存持久化读取失败重试次数. +func (l *ConfigLocalCacheConfigImpl) SetPersistMaxReadRetry(maxReadRetry int) { + l.PersistMaxReadRetry = maxReadRetry +} + +// GetPersistRetryInterval consumer.localCache.persist.retryInterval. +func (l *ConfigLocalCacheConfigImpl) GetPersistRetryInterval() time.Duration { + return *l.PersistRetryInterval +} + +// SetPersistRetryInterval 设置本地缓存持久化重试间隔. +func (l *ConfigLocalCacheConfigImpl) SetPersistRetryInterval(interval time.Duration) { + l.PersistRetryInterval = &interval +} + +// SetFallbackToLocalCache . +func (l *ConfigLocalCacheConfigImpl) SetFallbackToLocalCache(enable bool) { + l.FallbackToLocalCache = &enable +} + +// IsFallbackToLocalCache . +func (l *ConfigLocalCacheConfigImpl) IsFallbackToLocalCache() bool { + if l.FallbackToLocalCache == nil { + return true + } + return *l.FallbackToLocalCache +} + +// Verify 检验LocalCacheConfig配置. +func (l *ConfigLocalCacheConfigImpl) Verify() error { + if nil == l { + return errors.New("LocalCacheConfig is nil") + } + return nil +} + +// SetDefault 设置LocalCacheConfig配置的默认值. +func (l *ConfigLocalCacheConfigImpl) SetDefault() { + if l.PersistEnable == nil { + l.PersistEnable = model.ToBoolPtr(true) + } + if l.FallbackToLocalCache == nil { + l.FallbackToLocalCache = model.ToBoolPtr(true) + } + if len(l.PersistDir) == 0 { + l.PersistDir = filepath.Join(DefaultCachePersistDir, "config") + } + if nil == l.PersistRetryInterval { + l.PersistRetryInterval = model.ToDurationPtr(DefaultPersistRetryInterval) + } + if l.PersistMaxReadRetry == 0 { + l.PersistMaxReadRetry = DefaultPersistMaxReadRetry + } + if l.PersistMaxWriteRetry == 0 { + l.PersistMaxWriteRetry = DefaultPersistMaxWriteRetry + } +} + +// Init localche配置初始化. +func (l *ConfigLocalCacheConfigImpl) Init() { } diff --git a/pkg/config/default.go b/pkg/config/default.go index 3691a10d..81a4e727 100644 --- a/pkg/config/default.go +++ b/pkg/config/default.go @@ -207,8 +207,8 @@ const ( DefaultUniformRateLimiter = "unirate" // DefaultWarmUpWaitLimiter 默认限流插件,预热匀速. DefaultWarmUpWaitLimiter = "warmup-wait" - // DefaultCpuBbrRateLimiter 默认的CPU自适应限流器. - DefaultCpuBbrRateLimiter = "cpuBbr" + // DefaultBBRRateLimiter 默认的 CPU 自适应限流器. 使用 BBR 算法 + DefaultBBRRateLimiter = "bbr" // SubscribeLocalChannel 默认订阅事件处理插件. SubscribeLocalChannel = "subscribeLocalChannel" diff --git a/pkg/config/location_provider.go b/pkg/config/location_provider.go index 66750fdb..725ad73f 100644 --- a/pkg/config/location_provider.go +++ b/pkg/config/location_provider.go @@ -26,20 +26,23 @@ type LocationProviderConfigImpl struct { Options map[string]interface{} `yaml:"options" json:"options"` } -func (l LocationProviderConfigImpl) GetType() string { +func (l *LocationProviderConfigImpl) GetType() string { return l.Type } -func (l LocationProviderConfigImpl) GetOptions() map[string]interface{} { +func (l *LocationProviderConfigImpl) GetOptions() map[string]interface{} { return l.Options } -func (l LocationProviderConfigImpl) Verify() error { +func (l *LocationProviderConfigImpl) Verify() error { if l.Type == "" { return errors.New("type is empty") } return nil } -func (l LocationProviderConfigImpl) SetDefault() { +func (l *LocationProviderConfigImpl) SetDefault() { + if len(l.Options) == 0 { + l.Options = map[string]interface{}{} + } } diff --git a/pkg/flow/configuration/config_flow.go b/pkg/flow/configuration/config_flow.go index 2fe83367..b1f92af8 100644 --- a/pkg/flow/configuration/config_flow.go +++ b/pkg/flow/configuration/config_flow.go @@ -19,12 +19,12 @@ package configuration import ( "context" + "fmt" "strings" "sync" "time" apimodel "github.com/polarismesh/specification/source/go/api/v1/model" - "go.uber.org/zap" "github.com/polarismesh/polaris-go/pkg/config" "github.com/polarismesh/polaris-go/pkg/log" @@ -47,13 +47,24 @@ type ConfigFileFlow struct { chain configfilter.Chain configuration config.Configuration + persistHandler *CachePersistHandler + startLongPollingTaskOnce sync.Once } // NewConfigFileFlow 创建配置中心服务 -func NewConfigFileFlow(connector configconnector.ConfigConnector, - chain configfilter.Chain, - configuration config.Configuration) *ConfigFileFlow { +func NewConfigFileFlow(connector configconnector.ConfigConnector, chain configfilter.Chain, + configuration config.Configuration) (*ConfigFileFlow, error) { + persistHandler, err := NewCachePersistHandler( + configuration.GetConfigFile().GetLocalCache().GetPersistDir(), + configuration.GetConfigFile().GetLocalCache().GetPersistMaxWriteRetry(), + configuration.GetConfigFile().GetLocalCache().GetPersistMaxReadRetry(), + configuration.GetConfigFile().GetLocalCache().GetPersistRetryInterval(), + ) + if err != nil { + return nil, err + } + configFileService := &ConfigFileFlow{ connector: connector, chain: chain, @@ -62,9 +73,10 @@ func NewConfigFileFlow(connector configconnector.ConfigConnector, configFileCache: map[string]model.ConfigFile{}, configFilePool: map[string]*ConfigFileRepo{}, notifiedVersion: map[string]uint64{}, + persistHandler: persistHandler, } - return configFileService + return configFileService, nil } // Destroy 销毁服务 @@ -100,7 +112,7 @@ func (c *ConfigFileFlow) GetConfigFile(namespace, fileGroup, fileName string) (m return configFile, nil } - fileRepo, err := newConfigFileRepo(configFileMetadata, c.connector, c.chain, c.configuration) + fileRepo, err := newConfigFileRepo(configFileMetadata, c.connector, c.chain, c.configuration, c.persistHandler) if err != nil { return nil, err } @@ -112,12 +124,116 @@ func (c *ConfigFileFlow) GetConfigFile(namespace, fileGroup, fileName string) (m return configFile, nil } +// CreateConfigFile 创建配置文件 +func (c *ConfigFileFlow) CreateConfigFile(namespace, fileGroup, fileName, content string) error { + // 校验参数 + configFile := &configconnector.ConfigFile{ + Namespace: namespace, + FileGroup: fileGroup, + FileName: fileName, + } + configFile.SetContent(content) + + if err := model.CheckConfigFileMetadata(configFile); err != nil { + return model.NewSDKError(model.ErrCodeAPIInvalidArgument, err, "") + } + + c.fclock.Lock() + defer c.fclock.Unlock() + + resp, err := c.connector.CreateConfigFile(configFile) + if err != nil { + return err + } + + responseCode := resp.GetCode() + + if responseCode != uint32(apimodel.Code_ExecuteSuccess) { + log.GetBaseLogger().Infof("[Config] failed to create config file. namespace = %s, fileGroup = %s, fileName = %s, response code = %d", + namespace, fileGroup, fileName, responseCode) + errMsg := fmt.Sprintf("failed to create config file. namespace = %s, fileGroup = %s, fileName = %s, response code = %d", + namespace, fileGroup, fileName, responseCode) + return model.NewSDKError(model.ErrCodeInternalError, nil, errMsg) + } + + return nil +} + +// UpdateConfigFile 更新配置文件 +func (c *ConfigFileFlow) UpdateConfigFile(namespace, fileGroup, fileName, content string) error { + // 校验参数 + configFile := &configconnector.ConfigFile{ + Namespace: namespace, + FileGroup: fileGroup, + FileName: fileName, + } + configFile.SetContent(content) + + if err := model.CheckConfigFileMetadata(configFile); err != nil { + return model.NewSDKError(model.ErrCodeAPIInvalidArgument, err, "") + } + + c.fclock.Lock() + defer c.fclock.Unlock() + + resp, err := c.connector.UpdateConfigFile(configFile) + if err != nil { + return err + } + + responseCode := resp.GetCode() + + if responseCode != uint32(apimodel.Code_ExecuteSuccess) { + log.GetBaseLogger().Infof("[Config] failed to update config file. namespace = %s, fileGroup = %s, fileName = %s, response code = %d", + namespace, fileGroup, fileName, responseCode) + errMsg := fmt.Sprintf("failed to update config file. namespace = %s, fileGroup = %s, fileName = %s, response code = %d", + namespace, fileGroup, fileName, responseCode) + return model.NewSDKError(model.ErrCodeInternalError, nil, errMsg) + } + + return nil +} + +// PublishConfigFile 发布配置文件 +func (c *ConfigFileFlow) PublishConfigFile(namespace, fileGroup, fileName string) error { + // 检验参数 + configFile := &configconnector.ConfigFile{ + Namespace: namespace, + FileGroup: fileGroup, + FileName: fileName, + } + + if err := model.CheckConfigFileMetadata(configFile); err != nil { + return model.NewSDKError(model.ErrCodeAPIInvalidArgument, err, "") + } + + c.fclock.Lock() + defer c.fclock.Unlock() + + resp, err := c.connector.PublishConfigFile(configFile) + if err != nil { + return err + } + + responseCode := resp.GetCode() + + if responseCode != uint32(apimodel.Code_ExecuteSuccess) { + log.GetBaseLogger().Infof("[Config] failed to publish config file. namespace = %s, fileGroup = %s, fileName = %s, response code = %d", + namespace, fileGroup, fileName, responseCode) + errMsg := fmt.Sprintf("failed to publish config file. namespace = %s, fileGroup = %s, fileName = %s, response code = %d", + namespace, fileGroup, fileName, responseCode) + return model.NewSDKError(model.ErrCodeInternalError, nil, errMsg) + } + + return nil +} + func (c *ConfigFileFlow) addConfigFileToLongPollingPool(fileRepo *ConfigFileRepo) { configFileMetadata := fileRepo.configFileMetadata version := fileRepo.getVersion() - log.GetBaseLogger().Infof("[Config] add long polling config file.", - zap.Any("file", configFileMetadata), zap.Uint64("version", version)) + log.GetBaseLogger().Infof("[Config] add long polling config file. metadata %#v, version: %+v", + configFileMetadata, version) cacheKey := genCacheKeyByMetadata(configFileMetadata) c.configFilePool[cacheKey] = fileRepo @@ -147,19 +263,21 @@ func (c *ConfigFileFlow) startCheckVersionTask(ctx context.Context) { continue } + remoteConfigFile := repo.loadRemoteFile() + // 从服务端获取的配置文件版本号落后于通知的版本号,重新拉取配置 - if !(repo.remoteConfigFile == nil || repo.GetNotifiedVersion() > repo.remoteConfigFile.GetVersion()) { + if !(remoteConfigFile == nil || repo.GetNotifiedVersion() > remoteConfigFile.GetVersion()) { continue } - if repo.remoteConfigFile == nil { + if remoteConfigFile == nil { log.GetBaseLogger().Warnf("[Config] client does not pull the configuration, it will be pulled again."+ "file = %+v, notified version = %d", repo.configFileMetadata, repo.notifiedVersion) } else { log.GetBaseLogger().Warnf("[Config] notified version greater than pulled version, will pull config file again. "+ "file = %+v, notified version = %d, pulled version = %d", - repo.configFileMetadata, repo.notifiedVersion, repo.remoteConfigFile.GetVersion()) + repo.configFileMetadata, repo.notifiedVersion, remoteConfigFile.GetVersion()) } if err := repo.pull(); err != nil { diff --git a/pkg/flow/configuration/file_repo.go b/pkg/flow/configuration/file_repo.go index d9bef45a..402f03b5 100644 --- a/pkg/flow/configuration/file_repo.go +++ b/pkg/flow/configuration/file_repo.go @@ -19,6 +19,8 @@ package configuration import ( "fmt" + "net/url" + "sync/atomic" "time" apimodel "github.com/polarismesh/specification/source/go/api/v1/model" @@ -36,6 +38,13 @@ const ( delayMaxTime = 120 // 120s ) +var ( + _notExistFile = &configconnector.ConfigFile{ + SourceContent: NotExistedFileContent, + NotExist: true, + } +) + // ConfigFileRepo 服务端配置文件代理类,从服务端拉取配置并同步数据 type ConfigFileRepo struct { connector configconnector.ConfigConnector @@ -43,10 +52,16 @@ type ConfigFileRepo struct { configuration config.Configuration configFileMetadata model.ConfigFileMetadata - notifiedVersion uint64 // 长轮询通知的版本号 - remoteConfigFile *configconnector.ConfigFile // 从服务端获取的原始配置对象 - retryPolicy retryPolicy - listeners []ConfigFileRepoChangeListener + // 长轮询通知的版本号 + notifiedVersion uint64 + // 从服务端获取的原始配置对象 *configconnector.ConfigFile + remoteConfigFileRef *atomic.Value + retryPolicy retryPolicy + listeners []ConfigFileRepoChangeListener + + persistHandler *CachePersistHandler + + fallbackToLocalCache bool } // ConfigFileRepoChangeListener 远程配置文件发布监听器 @@ -56,7 +71,8 @@ type ConfigFileRepoChangeListener func(configFileMetadata model.ConfigFileMetada func newConfigFileRepo(metadata model.ConfigFileMetadata, connector configconnector.ConfigConnector, chain configfilter.Chain, - configuration config.Configuration) (*ConfigFileRepo, error) { + configuration config.Configuration, + persistHandler *CachePersistHandler) (*ConfigFileRepo, error) { repo := &ConfigFileRepo{ connector: connector, chain: chain, @@ -67,13 +83,16 @@ func newConfigFileRepo(metadata model.ConfigFileMetadata, delayMinTime: delayMinTime, delayMaxTime: delayMaxTime, }, - remoteConfigFile: &configconnector.ConfigFile{ - Namespace: metadata.GetNamespace(), - FileGroup: metadata.GetFileGroup(), - FileName: metadata.GetFileName(), - Version: initVersion, - }, + remoteConfigFileRef: &atomic.Value{}, + persistHandler: persistHandler, + fallbackToLocalCache: configuration.GetConfigFile().GetLocalCache().IsFallbackToLocalCache(), } + repo.remoteConfigFileRef.Store(&configconnector.ConfigFile{ + Namespace: metadata.GetNamespace(), + FileGroup: metadata.GetFileGroup(), + FileName: metadata.GetFileName(), + Version: initVersion, + }) // 1. 同步从服务端拉取配置 if err := repo.pull(); err != nil { return nil, err @@ -85,26 +104,37 @@ func (r *ConfigFileRepo) GetNotifiedVersion() uint64 { return r.notifiedVersion } +func (r *ConfigFileRepo) loadRemoteFile() *configconnector.ConfigFile { + val := r.remoteConfigFileRef.Load() + if val == nil { + return nil + } + return val.(*configconnector.ConfigFile) +} + // GetContent 获取配置文件内容 func (r *ConfigFileRepo) GetContent() string { - if r.remoteConfigFile == nil { + remoteFile := r.loadRemoteFile() + if remoteFile == nil { return NotExistedFileContent } - return r.remoteConfigFile.GetContent() + return remoteFile.GetContent() } func (r *ConfigFileRepo) getVersion() uint64 { - if r.remoteConfigFile == nil { + remoteConfigFile := r.loadRemoteFile() + if remoteConfigFile == nil { return initVersion } - return r.remoteConfigFile.GetVersion() + return remoteConfigFile.GetVersion() } func (r *ConfigFileRepo) getDataKey() string { - if r.remoteConfigFile == nil { + remoteConfigFile := r.loadRemoteFile() + if remoteConfigFile == nil { return "" } - return r.remoteConfigFile.GetDataKey() + return remoteConfigFile.GetDataKey() } func (r *ConfigFileRepo) pull() error { @@ -145,14 +175,16 @@ func (r *ConfigFileRepo) pull() error { pulledConfigFileVersion = int64(pulledConfigFile.GetVersion()) } log.GetBaseLogger().Infof("[Config] pull config file finished. config file = %+v, code = %d, version = %d, duration = %d ms", - pulledConfigFile, responseCode, pulledConfigFileVersion, time.Since(startTime).Milliseconds()) + pulledConfigFile.String(), responseCode, pulledConfigFileVersion, time.Since(startTime).Milliseconds()) // 拉取成功 if responseCode == uint32(apimodel.Code_ExecuteSuccess) { + remoteConfigFile := r.loadRemoteFile() // 本地配置文件落后,更新内存缓存 - if r.remoteConfigFile == nil || pulledConfigFile.Version >= r.remoteConfigFile.Version { - r.remoteConfigFile = deepCloneConfigFile(pulledConfigFile) - r.fireChangeEvent(pulledConfigFile.GetContent()) + if remoteConfigFile == nil || pulledConfigFile.Version >= remoteConfigFile.Version { + // save into local_cache + r.saveCacheConfigFile(pulledConfigFile) + r.fireChangeEvent(pulledConfigFile) } return nil } @@ -161,9 +193,13 @@ func (r *ConfigFileRepo) pull() error { if responseCode == uint32(apimodel.Code_NotFoundResource) { log.GetBaseLogger().Warnf("[Config] config file not found, please check whether config file released. %+v", r.configFileMetadata) // 删除配置文件 - if r.remoteConfigFile != nil { - r.remoteConfigFile = nil - r.fireChangeEvent(NotExistedFileContent) + r.removeCacheConfigFile(&configconnector.ConfigFile{ + Namespace: pullConfigFileReq.Namespace, + FileGroup: pullConfigFileReq.FileGroup, + FileName: pullConfigFileReq.FileName, + }) + if remoteConfigFile := r.loadRemoteFile(); remoteConfigFile != nil { + r.fireChangeEvent(_notExistFile) } return nil } @@ -176,9 +212,61 @@ func (r *ConfigFileRepo) pull() error { retryTimes++ r.retryPolicy.delay() } + r.fallbackIfNecessary(retryTimes, pullConfigFileReq) return err } +const ( + PullConfigMaxRetryTimes = 3 +) + +func (r *ConfigFileRepo) fallbackIfNecessary(retryTimes int, req *configconnector.ConfigFile) { + if !(retryTimes >= PullConfigMaxRetryTimes && r.fallbackToLocalCache) { + return + } + cacheVal := &configconnector.ConfigFile{} + fileName := fmt.Sprintf(PatternService, url.QueryEscape(req.Namespace), url.QueryEscape(req.FileGroup), + url.QueryEscape(req.FileName)) + CacheSuffix + if err := r.persistHandler.LoadMessageFromFile(fileName, cacheVal); err != nil { + return + } + + response, err := r.chain.Execute(req, func(configFile *configconnector.ConfigFile) (*configconnector.ConfigFileResponse, error) { + return &configconnector.ConfigFileResponse{ + Code: uint32(apimodel.Code_ExecuteSuccess), + ConfigFile: &configconnector.ConfigFile{ + Namespace: cacheVal.Namespace, + FileGroup: cacheVal.FileGroup, + FileName: cacheVal.FileName, + SourceContent: cacheVal.SourceContent, + Version: cacheVal.Version, + Md5: cacheVal.Md5, + Encrypted: cacheVal.Encrypted, + Tags: cacheVal.Tags, + }, + }, nil + }) + if err != nil { + log.GetBaseLogger().Errorf("[Config] fallback to local cache fail. %+v", err) + return + } + log.GetBaseLogger().Errorf("[Config] fallback to local cache success.") + localFile := response.ConfigFile + r.fireChangeEvent(localFile) +} + +func (r *ConfigFileRepo) saveCacheConfigFile(file *configconnector.ConfigFile) { + fileName := fmt.Sprintf(PatternService, url.QueryEscape(file.Namespace), url.QueryEscape(file.FileGroup), + url.QueryEscape(file.FileName)) + CacheSuffix + r.persistHandler.SaveMessageToFile(fileName, file) +} + +func (r *ConfigFileRepo) removeCacheConfigFile(file *configconnector.ConfigFile) { + fileName := fmt.Sprintf(PatternService, url.QueryEscape(file.Namespace), url.QueryEscape(file.FileGroup), + url.QueryEscape(file.FileName)) + CacheSuffix + r.persistHandler.DeleteCacheFromFile(fileName) +} + func deepCloneConfigFile(sourceConfigFile *configconnector.ConfigFile) *configconnector.ConfigFile { tags := make([]*configconnector.ConfigFileTag, 0, len(sourceConfigFile.Tags)) for _, tag := range sourceConfigFile.Tags { @@ -187,20 +275,22 @@ func deepCloneConfigFile(sourceConfigFile *configconnector.ConfigFile) *configco Value: tag.Value, }) } - return &configconnector.ConfigFile{ - Namespace: sourceConfigFile.GetNamespace(), - FileGroup: sourceConfigFile.GetFileGroup(), - FileName: sourceConfigFile.GetFileName(), - Content: sourceConfigFile.GetContent(), - Version: sourceConfigFile.GetVersion(), - Md5: sourceConfigFile.GetMd5(), - Encrypted: sourceConfigFile.GetEncrypted(), - Tags: tags, + ret := &configconnector.ConfigFile{ + Namespace: sourceConfigFile.GetNamespace(), + FileGroup: sourceConfigFile.GetFileGroup(), + FileName: sourceConfigFile.GetFileName(), + SourceContent: sourceConfigFile.GetSourceContent(), + Version: sourceConfigFile.GetVersion(), + Md5: sourceConfigFile.GetMd5(), + Encrypted: sourceConfigFile.GetEncrypted(), + Tags: tags, } + return ret } func (r *ConfigFileRepo) onLongPollingNotified(newVersion uint64) { - if r.remoteConfigFile != nil && r.remoteConfigFile.GetVersion() >= newVersion { + remoteConfigFile := r.loadRemoteFile() + if remoteConfigFile != nil && remoteConfigFile.GetVersion() >= newVersion { return } r.notifiedVersion = newVersion @@ -214,9 +304,18 @@ func (r *ConfigFileRepo) AddChangeListener(listener ConfigFileRepoChangeListener r.listeners = append(r.listeners, listener) } -func (r *ConfigFileRepo) fireChangeEvent(newContent string) { +func (r *ConfigFileRepo) fireChangeEvent(f *configconnector.ConfigFile) { + if f.GetContent() == "" { + f.SetContent(f.GetSourceContent()) + } + if f.NotExist { + r.remoteConfigFileRef = &atomic.Value{} + } else { + r.remoteConfigFileRef.Store(f) + } + for _, listener := range r.listeners { - if err := listener(r.configFileMetadata, newContent); err != nil { + if err := listener(r.configFileMetadata, f.GetContent()); err != nil { log.GetBaseLogger().Errorf("[Config] invoke config file repo change listener failed.", zap.Any("file", r.configFileMetadata), zap.Error(err)) } diff --git a/pkg/flow/configuration/local_cache.go b/pkg/flow/configuration/local_cache.go new file mode 100644 index 00000000..d187bfe4 --- /dev/null +++ b/pkg/flow/configuration/local_cache.go @@ -0,0 +1,195 @@ +/** + * Tencent is pleased to support the open source community by making polaris-go available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 configuration + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "time" + + "github.com/golang/protobuf/proto" + "github.com/hashicorp/go-multierror" + + "github.com/polarismesh/polaris-go/pkg/log" + "github.com/polarismesh/polaris-go/pkg/model" +) + +const ( + // PatternService is the pattern of service name + PatternService = "config#%s#%s#%s" + // CacheSuffix filesystem suffix + CacheSuffix = ".json" + // PatternGlob is the pattern of glob + PatternGlob = "#?*#?*#?*" +) + +// CachePersistHandler 持久化工具类 +type CachePersistHandler struct { + persistDir string + maxWriteRetry int + maxReadRetry int + retryInterval time.Duration +} + +// CacheFileInfo 文件信息 +type CacheFileInfo struct { + Msg proto.Message + FileInfo os.FileInfo +} + +// NewCachePersistHandler create persistence handler +func NewCachePersistHandler(persistDir string, maxWriteRetry int, + maxReadRetry int, retryInterval time.Duration) (*CachePersistHandler, error) { + handler := &CachePersistHandler{} + handler.persistDir = persistDir + handler.maxReadRetry = maxReadRetry + handler.maxWriteRetry = maxWriteRetry + handler.retryInterval = retryInterval + if err := handler.init(); err != nil { + return nil, model.NewSDKError(model.ErrCodeAPIInvalidConfig, err, "fail to init cachePersistHandler") + } + return handler, nil +} + +// 持久化配置初始化 +func (cph *CachePersistHandler) init() error { + if err := model.EnsureAndVerifyDir(cph.persistDir); err != nil { + return err + } + return nil +} + +// LoadMessageFromFile 从相对文件中加载缓存 +func (cph *CachePersistHandler) LoadMessageFromFile(relativeFile string, message interface{}) error { + absFile := filepath.Join(cph.persistDir, relativeFile) + return cph.loadMessageFromAbsoluteFile(absFile, message, cph.maxReadRetry) +} + +// 从绝对文件中加载缓存 +func (cph *CachePersistHandler) loadMessageFromAbsoluteFile(cacheFile string, message interface{}, + maxRetry int) error { + log.GetBaseLogger().Infof("Start to load cache from %s", cacheFile) + var lastErr error + var retryTimes int + for retryTimes = 0; retryTimes <= maxRetry; retryTimes++ { + cacheJson, err := ioutil.ReadFile(cacheFile) + if err != nil { + lastErr = model.NewSDKError(model.ErrCodeDiskError, err, "fail to read file cache") + // 文件打开失败的话,重试没有意义,直接失败 + break + } + if err := json.Unmarshal(cacheJson, message); err != nil { + lastErr = multierror.Prefix(err, "Fail to unmarshal file cache: ") + time.Sleep(cph.retryInterval) + // 解码失败可能是读到了部分数据,所以这里可以重试 + continue + } + return nil + } + return multierror.Prefix(lastErr, + fmt.Sprintf("load message from %s failed after retry %d times", cacheFile, retryTimes)) +} + +// DeleteCacheFromFile 删除缓存文件 +func (cph *CachePersistHandler) DeleteCacheFromFile(fileName string) { + fileToDelete := filepath.Join(cph.persistDir, fileName) + log.GetBaseLogger().Infof("Start to delete cache for %s", fileToDelete) + for retryTimes := 0; retryTimes <= cph.maxWriteRetry; retryTimes++ { + err := os.Remove(fileToDelete) + if err != nil { + if !os.IsNotExist(err) { + log.GetBaseLogger().Warnf("Fail to delete cache file %s,"+ + " because %s, next retrytimes %d", fileToDelete, err.Error(), retryTimes) + } else { + log.GetBaseLogger().Warnf("Fail to delete cache file %s,"+ + " error %s is not retryable, stop retrying", fileToDelete, err.Error()) + return + } + } else { + log.GetBaseLogger().Infof("Success to delete cache file %s", fileToDelete) + return + } + time.Sleep(cph.retryInterval) + } +} + +// SaveMessageToFile 按服务来进行缓存存储 +func (cph *CachePersistHandler) SaveMessageToFile(fileName string, svcResp interface{}) { + fileToAdd := filepath.Join(cph.persistDir, fileName) + log.GetBaseLogger().Infof("Start to save cache to file %s", fileToAdd) + msg, err := json.Marshal(svcResp) + if err != nil { + log.GetBaseLogger().Warnf("Fail to marshal the service response for %s", fileToAdd) + return + } + for retryTimes := 0; retryTimes <= cph.maxWriteRetry; retryTimes++ { + err = cph.doWriteFile(fileToAdd, []byte(msg)) + if err != nil { + if retryTimes > 0 { + log.GetBaseLogger().Warnf("Fail to write cache file %s, error: %s,"+ + " retry times: %v", fileToAdd, err.Error(), retryTimes) + } + } else { + log.GetBaseLogger().Infof("Success to write cache file %s", fileToAdd) + return + } + time.Sleep(cph.retryInterval) + } +} + +// 实际写文件 +func (cph *CachePersistHandler) doWriteFile(cacheFile string, msg []byte) error { + tempFileName := cacheFile + ".tmp" + tmpFile, err := os.OpenFile(tempFileName, os.O_WRONLY|os.O_CREATE, 0600) + if err != nil { + return model.NewSDKError(model.ErrCodeDiskError, err, "fail to open file %s to write", tempFileName) + } + n, err := tmpFile.Write(msg) + if err == nil && n < len(msg) { + return model.NewSDKError(model.ErrCodeDiskError, nil, "unable to write all bytes to file %s", tempFileName) + } + if err = cph.closeTmpFile(tmpFile, cacheFile); err != nil { + _ = os.Remove(tempFileName) + return err + } + return nil +} + +// 关闭文件 +func (cph *CachePersistHandler) closeTmpFile(tmpFile *os.File, cacheFile string) error { + if err := tmpFile.Sync(); err != nil { + _ = tmpFile.Close() + return model.NewSDKError(model.ErrCodeDiskError, err, "fail to sync file %s", tmpFile.Name()) + } + if err := tmpFile.Close(); err != nil { + return model.NewSDKError(model.ErrCodeDiskError, err, "fail to close file %s", tmpFile.Name()) + } + if model.PathExist(cacheFile) { + if err := os.Chmod(cacheFile, 0600); err != nil { + return model.NewSDKError(model.ErrCodeDiskError, err, "fail to chmod file %s", cacheFile) + } + } + err := os.Rename(tmpFile.Name(), cacheFile) + if err != nil { + return model.NewSDKError(model.ErrCodeDiskError, err, "fail to rename file %s to %s", tmpFile.Name(), cacheFile) + } + return nil +} diff --git a/pkg/flow/impl.go b/pkg/flow/impl.go index f83fa753..0bf2e6f4 100644 --- a/pkg/flow/impl.go +++ b/pkg/flow/impl.go @@ -180,7 +180,11 @@ func InitFlowEngine(flowEngine *Engine, initContext plugin.InitContext) error { // 初始化配置中心服务 if cfg.GetConfigFile().IsEnable() { - flowEngine.configFileFlow = configuration.NewConfigFileFlow(flowEngine.configConnector, flowEngine.configFilterChain, flowEngine.configuration) + configFileFlow, err := configuration.NewConfigFileFlow(flowEngine.configConnector, flowEngine.configFilterChain, flowEngine.configuration) + if err != nil { + return err + } + flowEngine.configFileFlow = configFileFlow } // 初始注册状态管理器 diff --git a/pkg/flow/quota/assist.go b/pkg/flow/quota/assist.go index 7c4be4d7..b14c7950 100644 --- a/pkg/flow/quota/assist.go +++ b/pkg/flow/quota/assist.go @@ -241,7 +241,7 @@ func (f *FlowQuotaAssistant) GetQuota(commonRequest *data.CommonRateLimitRequest Code: model.QuotaResultOk, Info: Disabled, } - return model.QuotaFutureWithResponse(resp), nil + return model.QuotaFutureWithResponse(resp, nil), nil } windows, err := f.lookupRateLimitWindow(commonRequest) if err != nil { @@ -253,15 +253,25 @@ func (f *FlowQuotaAssistant) GetQuota(commonRequest *data.CommonRateLimitRequest Code: model.QuotaResultOk, Info: RuleNotExists, } - return model.QuotaFutureWithResponse(resp), nil + return model.QuotaFutureWithResponse(resp, nil), nil } var maxWaitMs int64 = 0 + var releaseFuncs = make([]func(), 0, len(windows)) for _, window := range windows { window.Init() - quotaResult := window.AllocateQuota(commonRequest) + quotaResult, releaseFunc := window.AllocateQuotaWithRelease(commonRequest) + if releaseFunc != nil { + releaseFuncs = append(releaseFuncs, releaseFunc) + } + // 触发限流,提前返回 if quotaResult.Code == model.QuotaResultLimited { - return model.QuotaFutureWithResponse(quotaResult), nil + // 先释放资源 + for i := range releaseFuncs { + releaseFuncs[i]() + } + return model.QuotaFutureWithResponse(quotaResult, nil), nil } + // 未触发限流,记录令牌桶的最大排队时间 if quotaResult.WaitMs > maxWaitMs { maxWaitMs = quotaResult.WaitMs } @@ -269,7 +279,7 @@ func (f *FlowQuotaAssistant) GetQuota(commonRequest *data.CommonRateLimitRequest return model.QuotaFutureWithResponse(&model.QuotaResponse{ Code: model.QuotaResultOk, WaitMs: maxWaitMs, - }), nil + }, releaseFuncs), nil } // lookupRateLimitWindow 计算限流窗口 diff --git a/pkg/flow/quota/window.go b/pkg/flow/quota/window.go index 3a63c26d..bfcca2d3 100644 --- a/pkg/flow/quota/window.go +++ b/pkg/flow/quota/window.go @@ -608,6 +608,15 @@ func (r *RateLimitWindow) AllocateQuota(commonRequest *data.CommonRateLimitReque return r.trafficShapingBucket.GetQuota(curTimeMs, commonRequest.Token) } +// AllocateQuotaWithRelease 分配配额,并返回释放资源函数 +func (r *RateLimitWindow) AllocateQuotaWithRelease(commonRequest *data.CommonRateLimitRequest) (*model.QuotaResponse, func()) { + nowMilli := model.CurrentMillisecond() + atomic.StoreInt64(&r.lastAccessTimeMilli, nowMilli) + // 获取服务端时间 + curTimeMs := r.toServerTimeMilli(nowMilli) + return r.trafficShapingBucket.GetQuotaWithRelease(curTimeMs, commonRequest.Token) +} + // GetLastAccessTimeMilli 获取最近访问时间 func (r *RateLimitWindow) GetLastAccessTimeMilli() int64 { return atomic.LoadInt64(&r.lastAccessTimeMilli) diff --git a/pkg/flow/sync_flow.go b/pkg/flow/sync_flow.go index 9b7a798f..a04360c8 100644 --- a/pkg/flow/sync_flow.go +++ b/pkg/flow/sync_flow.go @@ -632,6 +632,21 @@ func (e *Engine) SyncGetConfigFile(namespace, fileGroup, fileName string) (model return e.configFileFlow.GetConfigFile(namespace, fileGroup, fileName) } +// SyncCreateConfigFile 同步创建配置文件 +func (e *Engine) SyncCreateConfigFile(namespace, fileGroup, fileName, content string) error { + return e.configFileFlow.CreateConfigFile(namespace, fileGroup, fileName, content) +} + +// SyncUpdateConfigFile 同步更新配置文件 +func (e *Engine) SyncUpdateConfigFile(namespace, fileGroup, fileName, content string) error { + return e.configFileFlow.UpdateConfigFile(namespace, fileGroup, fileName, content) +} + +// SyncPublishConfigFile 同步发布配置文件 +func (e *Engine) SyncPublishConfigFile(namespace, fileGroup, fileName string) error { + return e.configFileFlow.PublishConfigFile(namespace, fileGroup, fileName) +} + // WatchAllInstances 监听所有的实例 func (e *Engine) WatchAllInstances(request *model.WatchAllInstancesRequest) (*model.WatchAllInstancesResponse, error) { return e.watchEngine.WatchAllInstances(request) diff --git a/pkg/model/engine.go b/pkg/model/engine.go index a38d82b9..e2c77727 100644 --- a/pkg/model/engine.go +++ b/pkg/model/engine.go @@ -112,6 +112,12 @@ type Engine interface { InitCalleeService(req *InitCalleeServiceRequest) error // SyncGetConfigFile 同步获取配置文件 SyncGetConfigFile(namespace, fileGroup, fileName string) (ConfigFile, error) + // SyncCreateConfigFile 同步创建配置文件 + SyncCreateConfigFile(namespace, fileGroup, fileName, content string) error + // SyncUpdateConfigFile 同步更新配置文件 + SyncUpdateConfigFile(namespace, fileGroup, fileName, content string) error + // SyncPublishConfigFile 同步发布配置文件 + SyncPublishConfigFile(namespace, fileGroup, fileName string) error // ProcessRouters 执行路由链过滤,返回经过路由后的实例列表 ProcessRouters(req *ProcessRoutersRequest) (*InstancesResponse, error) // ProcessLoadBalance 执行负载均衡策略,返回负载均衡后的实例 diff --git a/pkg/model/quota.go b/pkg/model/quota.go index 2901f000..7a210557 100644 --- a/pkg/model/quota.go +++ b/pkg/model/quota.go @@ -168,19 +168,24 @@ type QuotaResponse struct { // QuotaFutureImpl 异步获取配额的future. type QuotaFutureImpl struct { - resp *QuotaResponse - deadlineCtx context.Context - cancel context.CancelFunc + resp *QuotaResponse + deadlineCtx context.Context + cancel context.CancelFunc + releaseFuncs []func() } -func QuotaFutureWithResponse(resp *QuotaResponse) *QuotaFutureImpl { +func QuotaFutureWithResponse(resp *QuotaResponse, releaseFuncs []func()) *QuotaFutureImpl { var deadlineCtx context.Context var cancel context.CancelFunc if resp.WaitMs > 0 { deadlineCtx, cancel = context.WithTimeout(context.Background(), time.Duration(resp.WaitMs)*time.Millisecond) } return &QuotaFutureImpl{ - resp: resp, deadlineCtx: deadlineCtx, cancel: cancel} + resp: resp, + deadlineCtx: deadlineCtx, + cancel: cancel, + releaseFuncs: releaseFuncs, + } } // Done 分配是否结束. @@ -206,6 +211,9 @@ func (q *QuotaFutureImpl) Get() *QuotaResponse { // Release 释放资源,仅用于并发数限流的场景. func (q *QuotaFutureImpl) Release() { + for i := range q.releaseFuncs { + q.releaseFuncs[i]() + } } const ( diff --git a/pkg/model/util.go b/pkg/model/util.go index ef04afb3..a297f3e9 100644 --- a/pkg/model/util.go +++ b/pkg/model/util.go @@ -18,6 +18,7 @@ package model import ( + "errors" "fmt" "hash/crc64" "hash/fnv" @@ -151,6 +152,11 @@ func ToDurationPtr(v time.Duration) *time.Duration { return &v } +// ToBoolPtr . +func ToBoolPtr(v bool) *bool { + return &v +} + // ToMilliSeconds 时间转换成毫秒 func ToMilliSeconds(v time.Duration) int64 { return ParseMilliSeconds(v.Nanoseconds()) @@ -315,3 +321,23 @@ func GetCrc64Hash(value string) (uint64, error) { } return h.Sum64(), nil } + +func CheckConfigFileMetadata(configFileMetadata ConfigFileMetadata) error { + if configFileMetadata == nil { + return errors.New("configFileMetadata is nil") + } + + if configFileMetadata.GetNamespace() == "" { + return errors.New("namespace connot be empty") + } + + if configFileMetadata.GetFileGroup() == "" { + return errors.New("fileGroup cannot be empty") + } + + if configFileMetadata.GetFileName() == "" { + return errors.New("fileName cannot be empty") + } + + return nil +} diff --git a/pkg/plugin/configconnector/config_connector.go b/pkg/plugin/configconnector/config_connector.go index bad91cd9..02038dc9 100644 --- a/pkg/plugin/configconnector/config_connector.go +++ b/pkg/plugin/configconnector/config_connector.go @@ -30,6 +30,12 @@ type ConfigConnector interface { GetConfigFile(configFile *ConfigFile) (*ConfigFileResponse, error) // WatchConfigFiles Watch config files WatchConfigFiles(configFileList []*ConfigFile) (*ConfigFileResponse, error) + // CreateConfigFile Create config file + CreateConfigFile(configFile *ConfigFile) (*ConfigFileResponse, error) + // UpdateConfigFile Update config file + UpdateConfigFile(configFile *ConfigFile) (*ConfigFileResponse, error) + // PublishConfigFile Publish config file + PublishConfigFile(configFile *ConfigFile) (*ConfigFileResponse, error) } // init diff --git a/pkg/plugin/configconnector/config_file.go b/pkg/plugin/configconnector/config_file.go index 3993ef17..7fc55bd1 100644 --- a/pkg/plugin/configconnector/config_file.go +++ b/pkg/plugin/configconnector/config_file.go @@ -18,6 +18,12 @@ package configconnector +import ( + "bytes" + "encoding/json" + "strconv" +) + const ( // ConfigFileTagKeyUseEncrypted 配置加密开关标识,value 为 boolean ConfigFileTagKeyUseEncrypted = "internal-encrypted" @@ -29,15 +35,33 @@ const ( // ConfigFile 配置文件 type ConfigFile struct { - Namespace string - FileGroup string - FileName string - Content string - Version uint64 - Md5 string - Encrypted bool - PublicKey string - Tags []*ConfigFileTag + Namespace string + FileGroup string + FileName string + SourceContent string + Version uint64 + Md5 string + Encrypted bool + PublicKey string + Tags []*ConfigFileTag + + // 实际暴露给应用的配置内容数据 + content string + // 该配置文件是否为不存在的场景下的占位信息 + NotExist bool +} + +func (c *ConfigFile) String() string { + var bf bytes.Buffer + _, _ = bf.WriteString("namespace=" + c.Namespace) + _, _ = bf.WriteString("group=" + c.FileGroup) + _, _ = bf.WriteString("file_name=" + c.FileName) + _, _ = bf.WriteString("version=" + strconv.FormatUint(c.Version, 10)) + _, _ = bf.WriteString("encrypt=" + strconv.FormatBool(c.Encrypted)) + //nolint: errchkjson + data, _ := json.Marshal(c.Tags) + _, _ = bf.WriteString("tags=" + string(data)) + return bf.String() } type ConfigFileTag struct { @@ -60,9 +84,18 @@ func (c *ConfigFile) GetFileName() string { return c.FileName } +// GetSourceContent 获取配置文件内容 +func (c *ConfigFile) GetSourceContent() string { + return c.SourceContent +} + +func (c *ConfigFile) SetContent(v string) { + c.content = v +} + // GetContent 获取配置文件内容 func (c *ConfigFile) GetContent() string { - return c.Content + return c.content } // GetVersion 获取配置文件版本号 diff --git a/pkg/plugin/configconnector/proxy.go b/pkg/plugin/configconnector/proxy.go index 09fc39d8..59647d8a 100644 --- a/pkg/plugin/configconnector/proxy.go +++ b/pkg/plugin/configconnector/proxy.go @@ -48,6 +48,24 @@ func (p *Proxy) WatchConfigFiles(configFileList []*ConfigFile) (*ConfigFileRespo return response, err } +// CreateConfigFile Create config file +func (p *Proxy) CreateConfigFile(configFile *ConfigFile) (*ConfigFileResponse, error) { + response, err := p.ConfigConnector.CreateConfigFile(configFile) + return response, err +} + +// UpdateConfigFile Update config file +func (p *Proxy) UpdateConfigFile(configFile *ConfigFile) (*ConfigFileResponse, error) { + response, err := p.ConfigConnector.UpdateConfigFile(configFile) + return response, err +} + +// PublishConfigFile Publish config file +func (p *Proxy) PublishConfigFile(configFile *ConfigFile) (*ConfigFileResponse, error) { + response, err := p.ConfigConnector.PublishConfigFile(configFile) + return response, err +} + // init 注册proxy func init() { plugin.RegisterPluginProxy(common.TypeConfigConnector, &Proxy{}) diff --git a/pkg/plugin/configfilter/configfilter.go b/pkg/plugin/configfilter/configfilter.go index 4e9133e1..715eab95 100644 --- a/pkg/plugin/configfilter/configfilter.go +++ b/pkg/plugin/configfilter/configfilter.go @@ -45,6 +45,7 @@ func (c Chain) Execute(configFile *configconnector.ConfigFile, next ConfigFileHa // ConfigFilter 配置过滤器接口 type ConfigFilter interface { plugin.Plugin + // DoFilter DoFilter(configFile *configconnector.ConfigFile, next ConfigFileHandleFunc) ConfigFileHandleFunc } diff --git a/pkg/plugin/ratelimiter/ratelimiter.go b/pkg/plugin/ratelimiter/ratelimiter.go index be8e2f8b..f2cdf5c6 100644 --- a/pkg/plugin/ratelimiter/ratelimiter.go +++ b/pkg/plugin/ratelimiter/ratelimiter.go @@ -35,6 +35,8 @@ type ServiceRateLimiter interface { type QuotaBucket interface { // GetQuota 在令牌桶/漏桶中进行单个配额的划扣,并返回本次分配的结果 GetQuota(curTimeMs int64, token uint32) *model.QuotaResponse + // GetQuotaWithRelease 判断限流结果,并返回配额释放函数(对并发数限流、CPU自适应限流有用) + GetQuotaWithRelease(curTimeMs int64, token uint32) (*model.QuotaResponse, func()) // Release 释放配额(仅对于并发数限流有用) Release() // OnRemoteUpdate 远程配额更新 diff --git a/pkg/plugin/register/plugins.go b/pkg/plugin/register/plugins.go index 071c6bbc..fa7b26e3 100644 --- a/pkg/plugin/register/plugins.go +++ b/pkg/plugin/register/plugins.go @@ -46,6 +46,7 @@ import ( _ "github.com/polarismesh/polaris-go/plugin/location" _ "github.com/polarismesh/polaris-go/plugin/logger/zaplog" _ "github.com/polarismesh/polaris-go/plugin/metrics/prometheus" + _ "github.com/polarismesh/polaris-go/plugin/ratelimiter/bbr" _ "github.com/polarismesh/polaris-go/plugin/ratelimiter/reject" _ "github.com/polarismesh/polaris-go/plugin/ratelimiter/unirate" _ "github.com/polarismesh/polaris-go/plugin/serverconnector/grpc" diff --git a/plugin/configconnector/polaris/config_connector.go b/plugin/configconnector/polaris/config_connector.go index 389733e3..efdd4e45 100644 --- a/plugin/configconnector/polaris/config_connector.go +++ b/plugin/configconnector/polaris/config_connector.go @@ -172,6 +172,102 @@ func (c *Connector) WatchConfigFiles(configFileList []*configconnector.ConfigFil return c.handleResponse(request.String(), reqID, opKey, pbResp, err, conn, startTime) } +// CreateConfigFile Create config file. +func (c *Connector) CreateConfigFile(configFile *configconnector.ConfigFile) (*configconnector.ConfigFileResponse, error) { + var err error + if err = c.waitDiscoverReady(); err != nil { + return nil, err + } + opKey := connector.OpKeyCreateConfigFile + startTime := clock.GetClock().Now() + // 获取server连接 + conn, err := c.connManager.GetConnection(opKey, config.ConfigCluster) + if err != nil { + return nil, connector.NetworkError(c.connManager, conn, int32(model.ErrCodeConnectError), err, startTime, + fmt.Sprintf("failed to get connection, opKey: %s", opKey)) + } + // 释放server连接 + defer conn.Release(opKey) + configClient := config_manage.NewPolarisConfigGRPCClient(network.ToGRPCConn(conn.Conn)) + reqID := connector.NextCreateConfigFileReqID() + ctx, cancel := connector.CreateHeaderContextWithReqId(0, reqID) + if cancel != nil { + defer cancel() + } + // 打印请求报文 + pbConfigFile := transferToConfigFile(configFile) + if log.GetBaseLogger().IsLevelEnabled(log.DebugLog) { + reqJson, _ := (&jsonpb.Marshaler{}).MarshalToString(pbConfigFile) + log.GetBaseLogger().Debugf("request to send is %s, opKey %s, connID %s", reqJson, opKey, conn.ConnID) + } + pbResp, err := configClient.CreateConfigFile(ctx, pbConfigFile) + return c.handleResponse(pbResp.String(), reqID, opKey, pbResp, err, conn, startTime) +} + +// UpdateConfigFile Update Config file. +func (c *Connector) UpdateConfigFile(configFile *configconnector.ConfigFile) (*configconnector.ConfigFileResponse, error) { + var err error + if err = c.waitDiscoverReady(); err != nil { + return nil, err + } + opKey := connector.OpKeyUpdateConfigFile + startTime := clock.GetClock().Now() + // 获取server连接 + conn, err := c.connManager.GetConnection(opKey, config.ConfigCluster) + if err != nil { + return nil, connector.NetworkError(c.connManager, conn, int32(model.ErrCodeConnectError), err, startTime, + fmt.Sprintf("failed to get connection, opKey: %s", opKey)) + } + // 释放server连接 + defer conn.Release(opKey) + configClient := config_manage.NewPolarisConfigGRPCClient(network.ToGRPCConn(conn.Conn)) + reqID := connector.NextUpdateConfigFileReqID() + ctx, cancel := connector.CreateHeaderContextWithReqId(0, reqID) + if cancel != nil { + defer cancel() + } + // 打印请求报文 + pbConfigFile := transferToConfigFile(configFile) + if log.GetBaseLogger().IsLevelEnabled(log.DebugLog) { + reqJson, _ := (&jsonpb.Marshaler{}).MarshalToString(pbConfigFile) + log.GetBaseLogger().Debugf("request to send is %s, opKey %s, connID %s", reqJson, opKey, conn.ConnID) + } + pbResp, err := configClient.UpdateConfigFile(ctx, pbConfigFile) + return c.handleResponse(pbResp.String(), reqID, opKey, pbResp, err, conn, startTime) +} + +// PublishConfigFile Publish Config file. +func (c *Connector) PublishConfigFile(configFile *configconnector.ConfigFile) (*configconnector.ConfigFileResponse, error) { + var err error + if err = c.waitDiscoverReady(); err != nil { + return nil, err + } + opKey := connector.OpKeyPublishConfigFile + startTime := clock.GetClock().Now() + // 获取server连接 + conn, err := c.connManager.GetConnection(opKey, config.ConfigCluster) + if err != nil { + return nil, connector.NetworkError(c.connManager, conn, int32(model.ErrCodeConnectError), err, startTime, + fmt.Sprintf("failed to get connection, opKey: %s", opKey)) + } + // 释放server连接 + defer conn.Release(opKey) + configClient := config_manage.NewPolarisConfigGRPCClient(network.ToGRPCConn(conn.Conn)) + reqID := connector.NextPublishConfigFileReqID() + ctx, cancel := connector.CreateHeaderContextWithReqId(0, reqID) + if cancel != nil { + defer cancel() + } + // 打印请求报文 + pbConfigFileRelease := transferToConfigFileRelease(configFile) + if log.GetBaseLogger().IsLevelEnabled(log.DebugLog) { + reqJson, _ := (&jsonpb.Marshaler{}).MarshalToString(pbConfigFileRelease) + log.GetBaseLogger().Debugf("request to send is %s, opKey %s, connID %s", reqJson, opKey, conn.ConnID) + } + pbResp, err := configClient.PublishConfigFile(ctx, pbConfigFileRelease) + return c.handleResponse(pbResp.String(), reqID, opKey, pbResp, err, conn, startTime) +} + // IsEnable .插件开关. func (c *Connector) IsEnable(cfg config.Configuration) bool { return cfg.GetGlobal().GetSystem().GetMode() != model.ModeWithAgent @@ -252,14 +348,31 @@ func transferFromClientConfigFileInfo(configFileInfo *config_manage.ClientConfig }) } return &configconnector.ConfigFile{ - Namespace: configFileInfo.GetNamespace().GetValue(), - FileGroup: configFileInfo.GetGroup().GetValue(), - FileName: configFileInfo.GetFileName().GetValue(), - Content: configFileInfo.GetContent().GetValue(), - Version: configFileInfo.GetVersion().GetValue(), - Md5: configFileInfo.GetMd5().GetValue(), - Encrypted: configFileInfo.GetEncrypted().GetValue(), - Tags: tags, + Namespace: configFileInfo.GetNamespace().GetValue(), + FileGroup: configFileInfo.GetGroup().GetValue(), + FileName: configFileInfo.GetFileName().GetValue(), + SourceContent: configFileInfo.GetContent().GetValue(), + Version: configFileInfo.GetVersion().GetValue(), + Md5: configFileInfo.GetMd5().GetValue(), + Encrypted: configFileInfo.GetEncrypted().GetValue(), + Tags: tags, + } +} + +func transferToConfigFile(configFile *configconnector.ConfigFile) *config_manage.ConfigFile { + return &config_manage.ConfigFile{ + Namespace: wrapperspb.String(configFile.GetNamespace()), + Group: wrapperspb.String(configFile.GetFileGroup()), + Name: wrapperspb.String(configFile.GetFileName()), + Content: wrapperspb.String(configFile.GetContent()), + } +} + +func transferToConfigFileRelease(configFile *configconnector.ConfigFile) *config_manage.ConfigFileRelease { + return &config_manage.ConfigFileRelease{ + Namespace: wrapperspb.String(configFile.GetNamespace()), + Group: wrapperspb.String(configFile.GetFileGroup()), + FileName: wrapperspb.String(configFile.GetFileName()), } } diff --git a/plugin/configfilter/crypto/crypto.go b/plugin/configfilter/crypto/crypto.go index 9e5467d0..fcf631f4 100644 --- a/plugin/configfilter/crypto/crypto.go +++ b/plugin/configfilter/crypto/crypto.go @@ -19,8 +19,8 @@ package crypto import ( + "encoding/base64" "fmt" - "sync" "github.com/polarismesh/polaris-go/pkg/config" "github.com/polarismesh/polaris-go/pkg/log" @@ -45,9 +45,8 @@ func init() { // CryptoFilter crypto filter plugin type CryptoFilter struct { *plugin.PluginBase - cfg *Config - cryptos map[string]Crypto - dataKeyCache *sync.Map + cfg *Config + cryptos map[string]Crypto } // Type plugin type @@ -64,7 +63,6 @@ func (c *CryptoFilter) Name() string { func (c *CryptoFilter) Init(ctx *plugin.InitContext) error { c.PluginBase = plugin.NewPluginBase(ctx) c.cryptos = make(map[string]Crypto) - c.dataKeyCache = new(sync.Map) cfgValue := ctx.Config.GetConfigFile().GetConfigFilterConfig().GetPluginConfig(c.Name()) if cfgValue != nil { @@ -100,14 +98,12 @@ func (c *CryptoFilter) IsEnable(cfg config.Configuration) bool { // DoFilter do crypto filter func (c *CryptoFilter) DoFilter(configFile *configconnector.ConfigFile, next configfilter.ConfigFileHandleFunc) configfilter.ConfigFileHandleFunc { return func(configFile *configconnector.ConfigFile) (*configconnector.ConfigFileResponse, error) { - // 查询缓存的数据密钥 - cacheKey := genCacheKey(configFile.Namespace, configFile.FileGroup, configFile.FileName) - cacheEncryptInfo := c.getEncryptInfo(cacheKey) - - var privateKey *rsa.RSAKey - var err error + var ( + privateKey *rsa.RSAKey + err error + ) // 如果是加密配置并且缓存密钥为空 - if configFile.GetEncrypted() && cacheEncryptInfo == nil { + if configFile.GetEncrypted() { // 生成公钥和私钥请求数据密钥 privateKey, err = rsa.GenerateRSAKey() if err != nil { @@ -121,47 +117,41 @@ func (c *CryptoFilter) DoFilter(configFile *configconnector.ConfigFile, next con return resp, err } // 如果是加密配置 - if resp.GetConfigFile().GetEncrypted() && resp.GetConfigFile().GetContent() != "" { - cipherContent := resp.GetConfigFile().GetContent() - cipherDataKey := resp.GetConfigFile().GetDataKey() - encryptAlgo := resp.GetConfigFile().GetEncryptAlgo() - - // 返回了数据密钥,解密配置 - if cipherDataKey != "" && privateKey != nil { - crypto, err := c.GetCrypto(encryptAlgo) - if err != nil { - return nil, err - } - dataKey, err := rsa.DecryptFromBase64(cipherDataKey, privateKey.PrivateKey) - if err != nil { - return nil, err - } - plainContent, err := crypto.Decrypt(cipherContent, dataKey) - if err != nil { - return nil, err - } - resp.ConfigFile.Content = string(plainContent) - // 缓存数据密钥 - c.setEncryptInfo(cacheKey, &encryptInfo{ - Key: dataKey, - Algo: encryptAlgo, - }) - } else if cacheEncryptInfo != nil { - // 有缓存的数据密钥和加密算法 - crypto, err := c.GetCrypto(cacheEncryptInfo.Algo) - if err != nil { - return nil, err - } - plainContent, err := crypto.Decrypt(cipherContent, cacheEncryptInfo.Key) - if err != nil { - return nil, err + if !resp.GetConfigFile().GetEncrypted() { + // 删除掉之前保存的 token cache + return resp, err + } + cipherContent := resp.GetConfigFile().GetSourceContent() + cipherDataKey := resp.GetConfigFile().GetDataKey() + encryptAlgo := resp.GetConfigFile().GetEncryptAlgo() + + // 返回了数据密钥,解密配置 + if cipherDataKey != "" && privateKey != nil { + crypto, err := c.GetCrypto(encryptAlgo) + if err != nil { + return nil, err + } + dataKey, err := rsa.DecryptFromBase64(cipherDataKey, privateKey.PrivateKey) + if err != nil { + log.GetBaseLogger().Errorf("cipher datakey use rsa decrypt fail: %s", err) + // 可能就没有走 RSA 加密, 直接用数据里面的 dataKey 进行获取 + dataKey, _ = base64.StdEncoding.DecodeString(cipherDataKey) + } + plainContent, err := crypto.Decrypt(cipherContent, dataKey) + if err != nil { + return nil, err + } + for i := range resp.ConfigFile.Tags { + if resp.ConfigFile.Tags[i].Key == "internal-datakey" { + resp.ConfigFile.Tags[i].Value = base64.StdEncoding.EncodeToString(dataKey) } - resp.ConfigFile.Content = string(plainContent) - } else { - // 没有返回数据密钥,设置为加密配置重新请求 - configFile.Encrypted = true - return c.DoFilter(configFile, next)(configFile) } + resp.ConfigFile.SetContent(string(plainContent)) + // 缓存数据密钥 + } else { + // 没有返回数据密钥,设置为加密配置重新请求 + configFile.Encrypted = true + return c.DoFilter(configFile, next)(configFile) } return resp, err } @@ -177,27 +167,6 @@ func (c *CryptoFilter) GetCrypto(algo string) (Crypto, error) { return crypto, nil } -type encryptInfo struct { - Key []byte - Algo string -} - -func (c *CryptoFilter) getEncryptInfo(key string) *encryptInfo { - obj, ok := c.dataKeyCache.Load(key) - if ok { - return obj.(*encryptInfo) - } - return nil -} - -func (c *CryptoFilter) setEncryptInfo(key string, value *encryptInfo) { - c.dataKeyCache.Store(key, value) -} - -func genCacheKey(namespace, fileGroup, fileName string) string { - return namespace + separator + fileGroup + separator + fileName -} - // Crypto Crypto interface type Crypto interface { GenerateKey() ([]byte, error) diff --git a/plugin/ratelimiter/bbr/README.md b/plugin/ratelimiter/bbr/README.md new file mode 100644 index 00000000..7b34f2c0 --- /dev/null +++ b/plugin/ratelimiter/bbr/README.md @@ -0,0 +1,59 @@ +# BBR +BBR CPU 自适应限流组件参考了 [TCP BBR](https://en.wikipedia.org/wiki/TCP_congestion_control#TCP_BBR) 的思想,以及 [阿里 Sentinel](https://github.com/alibaba/Sentinel/wiki/系统自适应限流) 的算法。 + +传统的限流思路为:超过一定负载就拦截流量进入,负载恢复就放开流量,这样做有延迟性,最终是按照果来调节因,无法取得良好效果。 + +BBR 的思路为:根据应用的请求处理时间、请求成功数、最大并发数这些指标,计算当前应用能承载的最大并发请求量,再对比当前系统并发量,判断是否应当拦截本次流量,即所谓"自适应"。 + +BBR 的源码实现可参考: +- [乔卓越 - 深入理解云原生下自适应限流技术原理与应用](https://mp.weixin.qq.com/s?__biz=MzA4ODg0NDkzOA==&mid=2247493581&idx=1&sn=62feb928915eaeb9082b58737829cf19&chksm=90215828a756d13e36cf77fe980f90810236296e5289259e085ccda7a539979c0716b5c8a601&scene=126&sessionid=1634901423&key=92c891f823e779d59fb069c1f73467971e77ea57597e6305cd46077c5115f63362682acb7d71e10dce269b227d3823d11ef9e5ce4116448fda19babccca00938bb97159b2d212d3a739c461a317a413867734e4ff39439da6d669943638ebb44fb5d44b939ae294b9b2eb42fa68fe939e1e4b21d8d806bf0299ecfea6bfa0c80&ascene=0&uin=MTg4NzU0NzUzNw%3D%3D&devicetype=Windows+10+x64&version=63040026&lang=zh_CN&exportkey=AyWZkGTg8xpxVEKYWHzdFvE%3D&pass_ticket=aPS1JJrPDslKIxzL8eyKwCG9loYdUIDyJU6iO22glE0yHlC3foSNMEFaklAFVWTj&wx_header=0&fontgear=2#) +- [yuemoxi - 从kratos分析BBR限流源码实现](https://juejin.cn/post/7004848252109455368) + + + +# 插件设计 +本插件将 BBR 限流器适配成 `QuotaBucket` 接口(主要实现 `GetQuotaWithRelease` 判断限流方法),以及 `ServiceRateLimiter` 接口(实现 `InitQuota` 初始化方法)。 + +由于 BBR 限流需要记录请求通过数、当前并发数、请求耗时,因此没有复用原来 `QuotaBucket` 接口中的 `GetQuota` 方法,而是新增了一个方法 `GetQuotaWithRelease`,该方法相比于 `GetQuota` 方法,返回参数中多了一个 `func()`,供业务方在业务逻辑处理完成后调用。 + +由于 CPU 使用率指标为实例单机指标,因此 CPU 限流只适用于单机限流,不适用于分布式限流,未实现分布式限流器需要实现的接口。 + + +## 初始化 InitQuota +kratos - BBR 初始化需要三个入参: +``` +CPUThreshold: CPU使用率阈值,超过该阈值时,根据应用过去能承受的负载判断是否拦截流量 +window: 窗口采样时长,控制采样多久的数据 +bucket: 桶数,BBR 会把 window 分成多个 bucket,沿时间轴向前滑动。如 window=1s, bucket=10 时,整个滑动窗口用来保存最近 1s 的采样数据,每个小的桶用来保存 100ms 的采样数据。当时间流动之后,过期的桶会自动被新桶的数据覆盖掉 +``` +这三个入参,从 `apitraffic.Rule` 结构体中解析,直接使用了结构体中的 `MaxAmount`、`ValidDuration`、`Precision` 字段 + + +## 判断限流 GetQuotaWithRelease +调用了 BBR 的 `Allow()` 方法 + +其内部执行 `shouldDrop()` 方法,其执行流程如下: + +![img.jpg](img.jpg) + +流程中比较关键的一步是计算应用可承受的最大请求量,由下列方法计算: +```go +func (l *BBR) maxInFlight() int64 { + return int64(math.Floor(float64(l.maxPASS()*l.minRT()*l.bucketPerSecond)/1000.0) + 0.5) +} +``` +- `maxPass * bucketPerSecond / 1000` 为每毫秒处理的请求数 +- `l.minRT()` 为 单个采样窗口中最小的响应时间 +- 0.5为向上取整 +- 当CPU利用率过载时,就需要通过上述预期公式进行干预。在服务运行期间持续统计当前服务的请求数,即 `inFlight`,通过在滑动窗口内的所有buckets中比较得出最多请求完成数 `maxPass`,以及最小的耗时 `minRT`,相乘就得出了预期的最佳请求数 `maxInFlight`。 +- `maxInFlight` 表示系统能同时处理的最多请求数,这个水位是一个平衡点,保持该水位可以最大化系统的处理能力,超过该水位则会导致请求堆积。 +- 通过 `inFlight` 与 `maxInFlight` 对比,如果前者大于后者那么就已经过载,进而拒绝后续到来的请求防止服务过载。 + +## 代码结构 +```go +├── core BBR核心算法实现 +├── cpu CPU使用率采集相关实现 +├── window 滑动窗口相关实现 +├── bucket.go 实现 `QuotaBucket` 接口 +├── plugin.go 实现 `Plugin` 接口 +``` diff --git a/plugin/ratelimiter/bbr/bucket.go b/plugin/ratelimiter/bbr/bucket.go new file mode 100644 index 00000000..03a6910a --- /dev/null +++ b/plugin/ratelimiter/bbr/bucket.go @@ -0,0 +1,106 @@ +package bbr + +import ( + "sort" + + "github.com/polarismesh/polaris-go/pkg/model" + "github.com/polarismesh/polaris-go/pkg/plugin/ratelimiter" + "github.com/polarismesh/polaris-go/plugin/ratelimiter/bbr/core" + + apitraffic "github.com/polarismesh/specification/source/go/api/v1/traffic_manage" +) + +var ( + allowResp = &model.QuotaResponse{ + Code: model.QuotaResultOk, + } + denyResp = &model.QuotaResponse{ + Code: model.QuotaResultLimited, + } +) + +// BBRQuotaBucket 实现 BBRQuotaBucket 接口的结构体 +type BBRQuotaBucket struct { + BBR *core.BBR +} + +// GetQuota 获取限额 +func (b *BBRQuotaBucket) GetQuota(_ int64, _ uint32) *model.QuotaResponse { + return nil +} + +// GetQuotaWithRelease 判断是否限流,并返回释放资源函数 +func (b *BBRQuotaBucket) GetQuotaWithRelease(_ int64, _ uint32) (*model.QuotaResponse, func()) { + release, allow := b.BBR.Allow() + if allow { + return allowResp, release + } + return denyResp, nil +} + +// Release 释放资源 +func (b *BBRQuotaBucket) Release() { + +} + +// OnRemoteUpdate 远端更新的时候通知。CPU限流为单机限流策略,不实现该函数 +func (b *BBRQuotaBucket) OnRemoteUpdate(_ ratelimiter.RemoteQuotaResult) { + +} + +// GetQuotaUsed 返回本地限流信息用于上报 +func (b *BBRQuotaBucket) GetQuotaUsed(_ int64) ratelimiter.UsageInfo { + return ratelimiter.UsageInfo{} +} + +// GetAmountInfos 获取规则的限流阈值信息,用于与服务端pb交互 +func (b *BBRQuotaBucket) GetAmountInfos() []ratelimiter.AmountInfo { + return nil +} + +// createBBRPlugin 初始化 +func createBBRPlugin(rule *apitraffic.Rule) *BBRQuotaBucket { + options := make([]core.Option, 0) + + if amounts := rule.GetAmounts(); len(amounts) > 0 { + // 如果有多条规则: + // 1. 先按CPU阈值比较,阈值小的生效 + // 2. 阈值相同时,按时间窗口比较,窗口小的生效 + // 3. 窗口也相同时,按精度比较,精度大的生效(polaris-server 做了校验,不会出现窗口相同的情况。这里也可以不用判断) + sort.Slice(amounts, func(i, j int) bool { + a, b := amounts[i], amounts[j] + threshold1, threshold2 := a.GetMaxAmount().GetValue(), b.GetMaxAmount().GetValue() + window1, window2 := a.GetValidDuration().AsDuration(), b.GetValidDuration().AsDuration() + precision1, precision2 := a.GetPrecision().GetValue(), b.GetPrecision().GetValue() + + if threshold1 == threshold2 { + if window1 == window2 { + return precision1 > precision2 + } + return window1 < window2 + } + return threshold1 < threshold2 + }) + + amount := amounts[0] + + // CPU使用率阈值,默认80% + if threshold := amount.GetMaxAmount().GetValue(); threshold > 0 { + // bbr 的参数为 800‰ 的形式,需要从 rule 中的百分号转到千分号,因此这里乘10 + options = append(options, core.WithCPUThreshold(int64(threshold*10))) + } + // 统计时间窗口,默认 10s + if window := amount.GetValidDuration().AsDuration(); window > 0 { + options = append(options, core.WithWindow(window)) + } + // 观测时间窗口内 计数桶 的个数(控制滑动窗口精度),默认100个 + // 如 window=1s, bucket=10 时,整个滑动窗口用来保存最近 1s 的采样数据,每个小的桶用来保存 100ms 的采样数据。当时间流动之后,过期的桶会自动被新桶的数据覆盖掉 + if precision := amount.GetPrecision().GetValue(); precision > 0 { + options = append(options, core.WithBucket(int(precision))) + } + } + + return &BBRQuotaBucket{ + BBR: core.NewLimiter(options...), + } +} diff --git a/plugin/ratelimiter/bbr/core/bbr.go b/plugin/ratelimiter/bbr/core/bbr.go new file mode 100644 index 00000000..861ac43b --- /dev/null +++ b/plugin/ratelimiter/bbr/core/bbr.go @@ -0,0 +1,313 @@ +package core + +import ( + "github.com/polarismesh/polaris-go/plugin/ratelimiter/bbr/cpu" + "github.com/polarismesh/polaris-go/plugin/ratelimiter/bbr/window" + "math" + "runtime" + "sync/atomic" + "time" +) + +var ( + gCPU int64 + decay = 0.95 +) + +type ( + cpuGetter func() int64 + + // Option function for bbr limiter + Option func(*options) +) + +func init() { + go collectCPUStat() +} + +// collectCPUStat 定期采集并更新 CPU 使用率等指标 +// cpu = cpuᵗ⁻¹ * decay + cpuᵗ * (1 - decay) +func collectCPUStat() { + ticker := time.NewTicker(time.Millisecond * 500) // same to cpu sample rate + defer func() { + ticker.Stop() + if err := recover(); err != nil { + go collectCPUStat() + } + }() + + // EMA algorithm: https://blog.csdn.net/m0_38106113/article/details/81542863 + for range ticker.C { + stat := &cpu.Stat{} + cpu.ReadStat(stat) + stat.Usage = min(stat.Usage, 1000) + prevCPU := atomic.LoadInt64(&gCPU) + curCPU := int64(float64(prevCPU)*decay + float64(stat.Usage)*(1.0-decay)) + atomic.StoreInt64(&gCPU, curCPU) + } +} + +func min(l, r uint64) uint64 { + if l < r { + return l + } + return r +} + +// Stat contains the metrics snapshot of bbr. +type Stat struct { + CPU int64 + InFlight int64 + MaxInFlight int64 + MinRt int64 + MaxPass int64 +} + +// counterCache is used to cache maxPASS and minRt result. +// Value of current bucket is not counted in real time. +// Cache time is equal to a bucket duration. +type counterCache struct { + val int64 + time time.Time +} + +// options of bbr limiter. +type options struct { + // WindowSize defines time duration per window + Window time.Duration + // BucketNum defines bucket number for each window + Bucket int + // CPUThreshold + CPUThreshold int64 + // CPUQuota + CPUQuota float64 +} + +// WithWindow with window size. +func WithWindow(d time.Duration) Option { + return func(o *options) { + o.Window = d + } +} + +// WithBucket with bucket ize. +func WithBucket(b int) Option { + return func(o *options) { + o.Bucket = b + } +} + +// WithCPUThreshold with cpu threshold; +func WithCPUThreshold(threshold int64) Option { + return func(o *options) { + o.CPUThreshold = threshold + } +} + +// WithCPUQuota with real cpu quota(if it can not collect from process correct); +func WithCPUQuota(quota float64) Option { + return func(o *options) { + o.CPUQuota = quota + } +} + +// BBR implements bbr-like limiter. +// It is inspired by sentinel. +// https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81 +type BBR struct { + cpu cpuGetter + passStat window.RollingCounter + rtStat window.RollingCounter + inFlight int64 + bucketPerSecond int64 + bucketDuration time.Duration + + // prevDropTime defines previous start drop since initTime + prevDropTime atomic.Value + maxPASSCache atomic.Value + minRtCache atomic.Value + + opts options +} + +// NewLimiter returns a bbr limiter +func NewLimiter(opts ...Option) *BBR { + opt := options{ + Window: time.Second * 10, + Bucket: 100, + CPUThreshold: 800, + } + for _, o := range opts { + o(&opt) + } + + bucketDuration := opt.Window / time.Duration(opt.Bucket) + passStat := window.NewRollingCounter(window.RollingCounterOpts{Size: opt.Bucket, BucketDuration: bucketDuration}) + rtStat := window.NewRollingCounter(window.RollingCounterOpts{Size: opt.Bucket, BucketDuration: bucketDuration}) + + limiter := &BBR{ + opts: opt, + passStat: passStat, + rtStat: rtStat, + bucketDuration: bucketDuration, + bucketPerSecond: int64(time.Second / bucketDuration), + cpu: func() int64 { return atomic.LoadInt64(&gCPU) }, + } + + if opt.CPUQuota != 0 { + // if cpuQuota is set, use new cpuGetter,Calculate the real CPU value based on the number of CPUs and Quota. + limiter.cpu = func() int64 { + return int64(float64(atomic.LoadInt64(&gCPU)) * float64(runtime.NumCPU()) / opt.CPUQuota) + } + } + + return limiter +} + +func (l *BBR) maxPASS() int64 { + passCache := l.maxPASSCache.Load() + if passCache != nil { + ps := passCache.(*counterCache) + if l.timespan(ps.time) < 1 { + return ps.val + } + } + rawMaxPass := int64(l.passStat.Reduce(func(iterator window.Iterator) float64 { + var result = 1.0 + for i := 1; iterator.Next() && i < l.opts.Bucket; i++ { + bucket := iterator.Bucket() + count := 0.0 + for _, p := range bucket.Points { + count += p + } + result = math.Max(result, count) + } + return result + })) + l.maxPASSCache.Store(&counterCache{ + val: rawMaxPass, + time: time.Now(), + }) + return rawMaxPass +} + +// timespan returns the passed bucket count +// since lastTime, if it is one bucket duration earlier than +// the last recorded time, it will return the BucketNum. +func (l *BBR) timespan(lastTime time.Time) int { + v := int(time.Since(lastTime) / l.bucketDuration) + if v > -1 { + return v + } + return l.opts.Bucket +} + +func (l *BBR) minRT() int64 { + rtCache := l.minRtCache.Load() + if rtCache != nil { + rc := rtCache.(*counterCache) + if l.timespan(rc.time) < 1 { + return rc.val + } + } + rawMinRT := int64(math.Ceil(l.rtStat.Reduce(func(iterator window.Iterator) float64 { + var result = math.MaxFloat64 + for i := 1; iterator.Next() && i < l.opts.Bucket; i++ { + bucket := iterator.Bucket() + if len(bucket.Points) == 0 { + continue + } + total := 0.0 + for _, p := range bucket.Points { + total += p + } + avg := total / float64(bucket.Count) + result = math.Min(result, avg) + } + return result + }))) + if rawMinRT <= 0 { + rawMinRT = 1 + } + l.minRtCache.Store(&counterCache{ + val: rawMinRT, + time: time.Now(), + }) + return rawMinRT +} + +// maxInFlight 每毫秒能同时处理的最多请求数 +// maxPass * bucketPerSecond / 1000 为每毫秒处理的请求数 +// l.minRT() 为 单个采样窗口中最小的响应时间 +// 0.5为向上取整 +func (l *BBR) maxInFlight() int64 { + return int64(math.Floor(float64(l.maxPASS()*l.minRT()*l.bucketPerSecond)/1000.0) + 0.5) +} + +// shouldDrop 是否应当抛弃本次请求 +// 在服务运行期间持续统计当前服务的并发处理请求数,即 inFlight,通过在滑动窗口内的所有buckets中比较得出最多请求完成数 maxPass,以及最小的耗时 minRT,相乘就得出了预期的最佳请求数 maxInFlight。 +// maxInFlight 表示系统能同时处理的最多请求数,这个水位是一个平衡点,保持该水位可以最大化系统的处理能力,超过该水位则会导致请求堆积。 +// 通过 inFlight 与 maxInFlight 对比,如果前者大于后者那么就已经过载,进而拒绝后续到来的请求防止服务过载。 +func (l *BBR) shouldDrop() bool { + now := time.Duration(time.Now().UnixNano()) + if l.cpu() < l.opts.CPUThreshold { + // current cpu payload below the threshold + prevDropTime, _ := l.prevDropTime.Load().(time.Duration) + if prevDropTime == 0 { + // haven't start drop, + // accept current request + return false + } + if now-prevDropTime <= time.Second { + // just start drop one second ago, + // check current inflight count + inFlight := atomic.LoadInt64(&l.inFlight) + return inFlight > 1 && inFlight > l.maxInFlight() + } + l.prevDropTime.Store(time.Duration(0)) + return false + } + // current cpu payload exceeds the threshold + inFlight := atomic.LoadInt64(&l.inFlight) + drop := inFlight > 1 && inFlight > l.maxInFlight() + if drop { + prevDrop, _ := l.prevDropTime.Load().(time.Duration) + if prevDrop != 0 { + // already started drop, return directly + return drop + } + // store start drop time + l.prevDropTime.Store(now) + } + return drop +} + +// Stat tasks a snapshot of the bbr limiter. +func (l *BBR) Stat() Stat { + return Stat{ + CPU: l.cpu(), + MinRt: l.minRT(), + MaxPass: l.maxPASS(), + MaxInFlight: l.maxInFlight(), + InFlight: atomic.LoadInt64(&l.inFlight), + } +} + +// Allow checks all inbound traffic. +// Once overload is detected, it raises limit.ErrLimitExceed error. +func (l *BBR) Allow() (func(), bool) { + if l.shouldDrop() { + return nil, false + } + atomic.AddInt64(&l.inFlight, 1) + start := time.Now().UnixNano() + ms := float64(time.Millisecond) + return func() { + //nolint + if rt := int64(math.Ceil(float64(time.Now().UnixNano()-start)) / ms); rt > 0 { + l.rtStat.Add(rt) + } + atomic.AddInt64(&l.inFlight, -1) + l.passStat.Add(1) + }, true +} diff --git a/plugin/ratelimiter/bbr/core/bbr_test.go b/plugin/ratelimiter/bbr/core/bbr_test.go new file mode 100644 index 00000000..8b522e2f --- /dev/null +++ b/plugin/ratelimiter/bbr/core/bbr_test.go @@ -0,0 +1,285 @@ +package core + +import ( + "github.com/polarismesh/polaris-go/plugin/ratelimiter/bbr/window" + "math" + "math/rand" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +var ( + windowSizeTest = time.Second + bucketNumTest = 10 + cpuThresholdTest = int64(800) + + optsForTest = []Option{ + WithWindow(windowSizeTest), + WithBucket(bucketNumTest), + WithCPUThreshold(cpuThresholdTest), + } +) + +func warmup(bbr *BBR, count int) { + for i := 0; i < count; i++ { + done, allow := bbr.Allow() + time.Sleep(time.Millisecond * 1) + if allow { + done() + } + } +} + +func forceAllow(bbr *BBR) { + inflight := bbr.inFlight + bbr.inFlight = bbr.maxPASS() - 1 + done, allow := bbr.Allow() + if allow { + done() + } + bbr.inFlight = inflight +} + +func TestBBR(t *testing.T) { + limiter := NewLimiter( + WithWindow(5*time.Second), + WithBucket(50), + WithCPUThreshold(100)) + var wg sync.WaitGroup + var drop int64 + for i := 0; i < 100; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for i := 0; i < 300; i++ { + done, allow := limiter.Allow() + if allow { + atomic.AddInt64(&drop, 1) + } else { + count := rand.Intn(100) + time.Sleep(time.Millisecond * time.Duration(count)) + done() + } + } + }() + } + wg.Wait() + t.Log("drop: ", drop) +} + +func TestBBRMaxPass(t *testing.T) { + bucketDuration := windowSizeTest / time.Duration(bucketNumTest) + bbr := NewLimiter(optsForTest...) + for i := 1; i <= 10; i++ { + bbr.passStat.Add(int64(i * 100)) + time.Sleep(bucketDuration) + } + assert.Equal(t, int64(1000), bbr.maxPASS()) + + // default max pass is equal to 1. + bbr = NewLimiter(optsForTest...) + assert.Equal(t, int64(1), bbr.maxPASS()) +} + +func TestBBRMaxPassWithCache(t *testing.T) { + bucketDuration := windowSizeTest / time.Duration(bucketNumTest) + bbr := NewLimiter(optsForTest...) + // witch cache, value of latest bucket is not counted instantly. + // after a bucket duration time, this bucket will be fully counted. + bbr.passStat.Add(int64(50)) + time.Sleep(bucketDuration / 2) + assert.Equal(t, int64(1), bbr.maxPASS()) + + bbr.passStat.Add(int64(50)) + time.Sleep(bucketDuration / 2) + assert.Equal(t, int64(1), bbr.maxPASS()) + + bbr.passStat.Add(int64(1)) + time.Sleep(bucketDuration) + assert.Equal(t, int64(100), bbr.maxPASS()) +} + +func TestBBRMinRt(t *testing.T) { + bucketDuration := windowSizeTest / time.Duration(bucketNumTest) + bbr := NewLimiter(optsForTest...) + for i := 0; i < 10; i++ { + for j := i*10 + 1; j <= i*10+10; j++ { + bbr.rtStat.Add(int64(j)) + } + if i != 9 { + time.Sleep(bucketDuration) + } + } + assert.Equal(t, int64(6), bbr.minRT()) + + // default max min rt is equal to maxFloat64. + bbr = NewLimiter(optsForTest...) + bbr.rtStat = window.NewRollingCounter(window.RollingCounterOpts{Size: 10, BucketDuration: bucketDuration}) + assert.Equal(t, int64(math.MaxInt64), bbr.minRT()) +} + +func TestBBRMinRtWithCache(t *testing.T) { + bucketDuration := windowSizeTest / time.Duration(bucketNumTest) + bbr := NewLimiter(optsForTest...) + for i := 0; i < 10; i++ { + for j := i*10 + 1; j <= i*10+5; j++ { + bbr.rtStat.Add(int64(j)) + } + if i != 9 { + time.Sleep(bucketDuration / 2) + } + _ = bbr.minRT() + for j := i*10 + 6; j <= i*10+10; j++ { + bbr.rtStat.Add(int64(j)) + } + if i != 9 { + time.Sleep(bucketDuration / 2) + } + } + assert.Equal(t, int64(6), bbr.minRT()) +} + +func TestBBRMaxQps(t *testing.T) { + bbr := NewLimiter(optsForTest...) + bucketDuration := windowSizeTest / time.Duration(bucketNumTest) + passStat := window.NewRollingCounter(window.RollingCounterOpts{Size: 10, BucketDuration: bucketDuration}) + rtStat := window.NewRollingCounter(window.RollingCounterOpts{Size: 10, BucketDuration: bucketDuration}) + for i := 0; i < 10; i++ { + passStat.Add(int64((i + 2) * 100)) + for j := i*10 + 1; j <= i*10+10; j++ { + rtStat.Add(int64(j)) + } + if i != 9 { + time.Sleep(bucketDuration) + } + } + bbr.passStat = passStat + bbr.rtStat = rtStat + assert.Equal(t, int64(60), bbr.maxInFlight()) +} + +func TestBBRShouldDrop(t *testing.T) { + var cpu int64 + bbr := NewLimiter(optsForTest...) + bbr.cpu = func() int64 { + return cpu + } + bucketDuration := windowSizeTest / time.Duration(bucketNumTest) + passStat := window.NewRollingCounter(window.RollingCounterOpts{Size: 10, BucketDuration: bucketDuration}) + rtStat := window.NewRollingCounter(window.RollingCounterOpts{Size: 10, BucketDuration: bucketDuration}) + for i := 0; i < 10; i++ { + passStat.Add(int64((i + 1) * 100)) + for j := i*10 + 1; j <= i*10+10; j++ { + rtStat.Add(int64(j)) + } + if i != 9 { + time.Sleep(bucketDuration) + } + } + bbr.passStat = passStat + bbr.rtStat = rtStat + // cpu >= 800, inflight < maxQps + cpu = 800 + bbr.inFlight = 50 + assert.Equal(t, false, bbr.shouldDrop()) + + // cpu >= 800, inflight > maxQps + cpu = 800 + bbr.inFlight = 80 + assert.Equal(t, true, bbr.shouldDrop()) + + // cpu < 800, inflight > maxQps, cold duration + cpu = 700 + bbr.inFlight = 80 + assert.Equal(t, true, bbr.shouldDrop()) + + // cpu < 800, inflight > maxQps + time.Sleep(2 * time.Second) + cpu = 700 + bbr.inFlight = 80 + assert.Equal(t, false, bbr.shouldDrop()) +} + +func BenchmarkBBRAllowUnderLowLoad(b *testing.B) { + bbr := NewLimiter(optsForTest...) + bbr.cpu = func() int64 { + return 500 + } + b.ResetTimer() + for i := 0; i <= b.N; i++ { + done, allow := bbr.Allow() + if allow { + done() + } + } +} + +func BenchmarkBBRAllowUnderHighLoad(b *testing.B) { + bbr := NewLimiter(optsForTest...) + bbr.cpu = func() int64 { + return 900 + } + bbr.inFlight = 1 + b.ResetTimer() + for i := 0; i <= b.N; i++ { + if i%10000 == 0 { + maxFlight := bbr.maxInFlight() + if maxFlight != 0 { + bbr.inFlight = rand.Int63n(bbr.maxInFlight() * 2) + } + } + done, allow := bbr.Allow() + if allow { + done() + } + } +} + +func BenchmarkBBRShouldDropUnderLowLoad(b *testing.B) { + bbr := NewLimiter(optsForTest...) + bbr.cpu = func() int64 { + return 500 + } + warmup(bbr, 10000) + b.ResetTimer() + for i := 0; i <= b.N; i++ { + bbr.shouldDrop() + } +} + +func BenchmarkBBRShouldDropUnderHighLoad(b *testing.B) { + bbr := NewLimiter(optsForTest...) + bbr.cpu = func() int64 { + return 900 + } + warmup(bbr, 10000) + bbr.inFlight = 1000 + b.ResetTimer() + for i := 0; i <= b.N; i++ { + bbr.shouldDrop() + if i%10000 == 0 { + forceAllow(bbr) + } + } +} + +func BenchmarkBBRShouldDropUnderUnstableLoad(b *testing.B) { + bbr := NewLimiter(optsForTest...) + bbr.cpu = func() int64 { + return 500 + } + warmup(bbr, 10000) + bbr.prevDropTime.Store(time.Now().UnixNano()) + bbr.inFlight = 1000 + b.ResetTimer() + for i := 0; i <= b.N; i++ { + bbr.shouldDrop() + if i%100000 == 0 { + forceAllow(bbr) + } + } +} diff --git a/plugin/ratelimiter/bbr/cpu/cgroup.go b/plugin/ratelimiter/bbr/cpu/cgroup.go new file mode 100644 index 00000000..a7d2c597 --- /dev/null +++ b/plugin/ratelimiter/bbr/cpu/cgroup.go @@ -0,0 +1,126 @@ +package cpu + +import ( + "bufio" + "fmt" + "io" + "os" + "path" + "strconv" + "strings" +) + +const cgroupRootDir = "/sys/fs/cgroup" + +// cgroup Linux cgroup +type cgroup struct { + cgroupSet map[string]string +} + +// CPUCFSQuotaUs cpu.cfs_quota_us +func (c *cgroup) CPUCFSQuotaUs() (int64, error) { + data, err := readFile(path.Join(c.cgroupSet["cpu"], "cpu.cfs_quota_us")) + if err != nil { + return 0, err + } + return strconv.ParseInt(data, 10, 64) +} + +// CPUCFSPeriodUs cpu.cfs_period_us +func (c *cgroup) CPUCFSPeriodUs() (uint64, error) { + data, err := readFile(path.Join(c.cgroupSet["cpu"], "cpu.cfs_period_us")) + if err != nil { + return 0, err + } + return parseUint(data) +} + +// CPUAcctUsage cpuacct.usage +func (c *cgroup) CPUAcctUsage() (uint64, error) { + data, err := readFile(path.Join(c.cgroupSet["cpuacct"], "cpuacct.usage")) + if err != nil { + return 0, err + } + return parseUint(data) +} + +// CPUAcctUsagePerCPU cpuacct.usage_percpu +func (c *cgroup) CPUAcctUsagePerCPU() ([]uint64, error) { + data, err := readFile(path.Join(c.cgroupSet["cpuacct"], "cpuacct.usage_percpu")) + if err != nil { + return nil, err + } + var usage []uint64 + for _, v := range strings.Fields(string(data)) { + var u uint64 + if u, err = parseUint(v); err != nil { + return nil, err + } + // fix possible_cpu:https://www.ibm.com/support/knowledgecenter/en/linuxonibm/com.ibm.linux.z.lgdd/lgdd_r_posscpusparm.html + if u != 0 { + usage = append(usage, u) + } + } + return usage, nil +} + +// CPUSetCPUs cpuset.cpus +func (c *cgroup) CPUSetCPUs() ([]uint64, error) { + data, err := readFile(path.Join(c.cgroupSet["cpuset"], "cpuset.cpus")) + if err != nil { + return nil, err + } + cpus, err := ParseUintList(data) + if err != nil { + return nil, err + } + sets := make([]uint64, 0) + for k := range cpus { + sets = append(sets, uint64(k)) + } + return sets, nil +} + +// currentcGroup get current process cgroup +func currentcGroup() (*cgroup, error) { + pid := os.Getpid() + cgroupFile := fmt.Sprintf("/proc/%d/cgroup", pid) + cgroupSet := make(map[string]string) + fp, err := os.Open(cgroupFile) + if err != nil { + return nil, err + } + defer fp.Close() + buf := bufio.NewReader(fp) + for { + line, err := buf.ReadString('\n') + if err != nil { + if err == io.EOF { + break + } + return nil, err + } + col := strings.Split(strings.TrimSpace(line), ":") + if len(col) != 3 { + return nil, fmt.Errorf("invalid cgroup format %s", line) + } + dir := col[2] + // When dir is not equal to /, it must be in docker + if dir != "/" { + cgroupSet[col[1]] = path.Join(cgroupRootDir, col[1]) + if strings.Contains(col[1], ",") { + for _, k := range strings.Split(col[1], ",") { + cgroupSet[k] = path.Join(cgroupRootDir, k) + } + } + } else { + cgroupSet[col[1]] = path.Join(cgroupRootDir, col[1], col[2]) + if strings.Contains(col[1], ",") { + for _, k := range strings.Split(col[1], ",") { + cgroupSet[k] = path.Join(cgroupRootDir, k, col[2]) + } + } + } + } + return &cgroup{cgroupSet: cgroupSet}, nil +} diff --git a/plugin/ratelimiter/bbr/cpu/cgroup_cpu.go b/plugin/ratelimiter/bbr/cpu/cgroup_cpu.go new file mode 100644 index 00000000..5d775cf3 --- /dev/null +++ b/plugin/ratelimiter/bbr/cpu/cgroup_cpu.go @@ -0,0 +1,242 @@ +package cpu + +import ( + "bufio" + "errors" + "os" + "strconv" + "strings" + + pscpu "github.com/shirou/gopsutil/v3/cpu" +) + +var _ CPU = (*cgroupCPU)(nil) + +type cgroupCPU struct { + frequency uint64 + quota float64 + cores uint64 + + preSystem uint64 + preTotal uint64 +} + +func newCgroupCPU() (cpu *cgroupCPU, err error) { + cores, err := pscpu.Counts(true) + if err != nil || cores == 0 { + var cpus []uint64 + cpus, err = perCPUUsage() + if err != nil { + return nil, err + } + cores = len(cpus) + } + + sets, err := cpuSets() + if err != nil { + return + } + quota := float64(len(sets)) + cq, err := cpuQuota() + if err == nil && cq != -1 { + var period uint64 + if period, err = cpuPeriod(); err != nil { + return + } + limit := float64(cq) / float64(period) + if limit < quota { + quota = limit + } + } + maxFreq := cpuMaxFreq() + + preSystem, err := systemCPUUsage() + if err != nil { + return + } + preTotal, err := totalCPUUsage() + if err != nil { + return + } + cpu = &cgroupCPU{ + frequency: maxFreq, + quota: quota, + cores: uint64(cores), + preSystem: preSystem, + preTotal: preTotal, + } + return +} + +func (cpu *cgroupCPU) Usage() (u uint64, err error) { + var ( + total uint64 + system uint64 + ) + total, err = totalCPUUsage() + if err != nil { + return + } + system, err = systemCPUUsage() + if err != nil { + return + } + if system != cpu.preSystem { + u = uint64(float64((total-cpu.preTotal)*cpu.cores*1e3) / (float64(system-cpu.preSystem) * cpu.quota)) + } + cpu.preSystem = system + cpu.preTotal = total + return +} + +func (cpu *cgroupCPU) Info() Info { + return Info{ + Frequency: cpu.frequency, + Quota: cpu.quota, + } +} + +const nanoSecondsPerSecond = 1e9 + +// ErrNoCFSLimit is no quota limit +var ErrNoCFSLimit = errors.New("no quota limit") + +var clockTicksPerSecond = uint64(getClockTicks()) + +// systemCPUUsage returns the host system's cpu usage in +// nanoseconds. An error is returned if the format of the underlying +// file does not match. +// +// Uses /proc/stat defined by POSIX. Looks for the cpu +// statistics line and then sums up the first seven fields +// provided. See man 5 proc for details on specific field +// information. +func systemCPUUsage() (usage uint64, err error) { + var ( + line string + f *os.File + ) + if f, err = os.Open("/proc/stat"); err != nil { + return + } + bufReader := bufio.NewReaderSize(nil, 128) + defer func() { + bufReader.Reset(nil) + f.Close() + }() + bufReader.Reset(f) + for err == nil { + if line, err = bufReader.ReadString('\n'); err != nil { + return + } + parts := strings.Fields(line) + switch parts[0] { + case "cpu": + if len(parts) < 8 { + err = errors.New("bad format of cpu stats") + return + } + var totalClockTicks uint64 + for _, i := range parts[1:8] { + var v uint64 + if v, err = strconv.ParseUint(i, 10, 64); err != nil { + return + } + totalClockTicks += v + } + usage = (totalClockTicks * nanoSecondsPerSecond) / clockTicksPerSecond + return + } + } + err = errors.New("bad stats format") + return +} + +func totalCPUUsage() (usage uint64, err error) { + var cg *cgroup + if cg, err = currentcGroup(); err != nil { + return + } + return cg.CPUAcctUsage() +} + +func perCPUUsage() (usage []uint64, err error) { + var cg *cgroup + if cg, err = currentcGroup(); err != nil { + return + } + return cg.CPUAcctUsagePerCPU() +} + +func cpuSets() (sets []uint64, err error) { + var cg *cgroup + if cg, err = currentcGroup(); err != nil { + return + } + return cg.CPUSetCPUs() +} + +func cpuQuota() (quota int64, err error) { + var cg *cgroup + if cg, err = currentcGroup(); err != nil { + return + } + return cg.CPUCFSQuotaUs() +} + +func cpuPeriod() (peroid uint64, err error) { + var cg *cgroup + if cg, err = currentcGroup(); err != nil { + return + } + return cg.CPUCFSPeriodUs() +} + +func cpuFreq() uint64 { + lines, err := readLines("/proc/cpuinfo") + if err != nil { + return 0 + } + for _, line := range lines { + fields := strings.Split(line, ":") + if len(fields) < 2 { + continue + } + key := strings.TrimSpace(fields[0]) + value := strings.TrimSpace(fields[1]) + if key == "cpu MHz" || key == "clock" { + // treat this as the fallback value, thus we ignore error + if t, err := strconv.ParseFloat(strings.Replace(value, "MHz", "", 1), 64); err == nil { + return uint64(t * 1000.0 * 1000.0) + } + } + } + return 0 +} + +func cpuMaxFreq() uint64 { + feq := cpuFreq() + data, err := readFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq") + if err != nil { + return feq + } + // override the max freq from /proc/cpuinfo + cfeq, err := parseUint(data) + if err == nil { + feq = cfeq + } + return feq +} + +// getClockTicks get the OS's ticks per second +func getClockTicks() int { + // TODO figure out a better alternative for platforms where we're missing cgo + // + // TODO Windows. This could be implemented using Win32 QueryPerformanceFrequency(). + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx + // + // An example of its usage can be found here. + // https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx + + return 100 +} diff --git a/plugin/ratelimiter/bbr/cpu/psutil_cpu.go b/plugin/ratelimiter/bbr/cpu/psutil_cpu.go new file mode 100644 index 00000000..66cbddae --- /dev/null +++ b/plugin/ratelimiter/bbr/cpu/psutil_cpu.go @@ -0,0 +1,47 @@ +package cpu + +import ( + "time" + + "github.com/shirou/gopsutil/v3/cpu" +) + +var _ CPU = (*psutilCPU)(nil) + +type psutilCPU struct { + interval time.Duration +} + +func newPsutilCPU(interval time.Duration) (cpu *psutilCPU, err error) { + cpu = &psutilCPU{interval: interval} + _, err = cpu.Usage() + if err != nil { + return + } + return +} + +func (ps *psutilCPU) Usage() (u uint64, err error) { + var percents []float64 + percents, err = cpu.Percent(ps.interval, false) + if err == nil { + u = uint64(percents[0] * 10) + } + return +} + +func (ps *psutilCPU) Info() (info Info) { + stats, err := cpu.Info() + if err != nil { + return + } + cores, err := cpu.Counts(true) + if err != nil { + return + } + info = Info{ + Frequency: uint64(stats[0].Mhz), + Quota: float64(cores), + } + return +} diff --git a/plugin/ratelimiter/bbr/cpu/stat.go b/plugin/ratelimiter/bbr/cpu/stat.go new file mode 100644 index 00000000..92d8a5c7 --- /dev/null +++ b/plugin/ratelimiter/bbr/cpu/stat.go @@ -0,0 +1,68 @@ +package cpu + +import ( + "fmt" + "sync/atomic" + "time" +) + +const ( + interval time.Duration = time.Millisecond * 500 +) + +var ( + stats CPU + usage uint64 +) + +// CPU is cpu stat usage. +type CPU interface { + Usage() (u uint64, e error) + Info() Info +} + +func init() { + var ( + err error + ) + stats, err = newCgroupCPU() + if err != nil { + // fmt.Printf("cgroup cpu init failed(%v),switch to psutil cpu\n", err) + stats, err = newPsutilCPU(interval) + if err != nil { + panic(fmt.Sprintf("cgroup cpu init failed!err:=%v", err)) + } + } + go func() { + ticker := time.NewTicker(interval) + defer ticker.Stop() + for { + <-ticker.C + u, err := stats.Usage() + if err == nil && u != 0 { + atomic.StoreUint64(&usage, u) + } + } + }() +} + +// Stat cpu stat. +type Stat struct { + Usage uint64 // cpu use ratio. +} + +// Info cpu info. +type Info struct { + Frequency uint64 + Quota float64 +} + +// ReadStat read cpu stat. +func ReadStat(stat *Stat) { + stat.Usage = atomic.LoadUint64(&usage) +} + +// GetInfo get cpu info. +func GetInfo() Info { + return stats.Info() +} diff --git a/plugin/ratelimiter/bbr/cpu/stat_test.go b/plugin/ratelimiter/bbr/cpu/stat_test.go new file mode 100644 index 00000000..9069c38a --- /dev/null +++ b/plugin/ratelimiter/bbr/cpu/stat_test.go @@ -0,0 +1,21 @@ +package cpu + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestStat(t *testing.T) { + time.Sleep(time.Second * 3) + + var s Stat + var i Info + ReadStat(&s) + i = GetInfo() + + assert.NotZero(t, s.Usage) + assert.NotZero(t, i.Frequency) + assert.NotZero(t, i.Quota) +} diff --git a/plugin/ratelimiter/bbr/cpu/utils.go b/plugin/ratelimiter/bbr/cpu/utils.go new file mode 100644 index 00000000..7f074eb6 --- /dev/null +++ b/plugin/ratelimiter/bbr/cpu/utils.go @@ -0,0 +1,121 @@ +package cpu + +import ( + "bufio" + "fmt" + "io/ioutil" + "os" + "strconv" + "strings" +) + +func readFile(path string) (string, error) { + contents, err := ioutil.ReadFile(path) + if err != nil { + return "", err + } + return strings.TrimSpace(string(contents)), nil +} + +func parseUint(s string) (uint64, error) { + v, err := strconv.ParseUint(s, 10, 64) + if err != nil { + intValue, intErr := strconv.ParseInt(s, 10, 64) + // 1. Handle negative values greater than MinInt64 (and) + // 2. Handle negative values lesser than MinInt64 + if intErr == nil && intValue < 0 { + return 0, nil + } else if intErr != nil && + intErr.(*strconv.NumError).Err == strconv.ErrRange && + intValue < 0 { + return 0, nil + } + return 0, err + } + return v, nil +} + +// ParseUintList parses and validates the specified string as the value +// found in some cgroup file (e.g. cpuset.cpus, cpuset.mems), which could be +// one of the formats below. Note that duplicates are actually allowed in the +// input string. It returns a map[int]bool with available elements from val +// set to true. +// Supported formats: +// 7 +// 1-6 +// 0,3-4,7,8-10 +// 0-0,0,1-7 +// 03,1-3 <- this is gonna get parsed as [1,2,3] +// 3,2,1 +// 0-2,3,1 +func ParseUintList(val string) (map[int]bool, error) { + if val == "" { + return map[int]bool{}, nil + } + + availableInts := make(map[int]bool) + split := strings.Split(val, ",") + errInvalidFormat := fmt.Errorf("os/stat: invalid format: %s", val) + for _, r := range split { + if !strings.Contains(r, "-") { + v, err := strconv.Atoi(r) + if err != nil { + return nil, errInvalidFormat + } + availableInts[v] = true + } else { + split := strings.SplitN(r, "-", 2) + min, err := strconv.Atoi(split[0]) + if err != nil { + return nil, errInvalidFormat + } + max, err := strconv.Atoi(split[1]) + if err != nil { + return nil, errInvalidFormat + } + if max < min { + return nil, errInvalidFormat + } + for i := min; i <= max; i++ { + availableInts[i] = true + } + } + } + return availableInts, nil +} + +// readLines reads contents from a file and splits them by new lines. +// A convenience wrapper to ReadLinesOffsetN(filename, 0, -1). +func readLines(filename string) ([]string, error) { + return readLinesOffsetN(filename, 0, -1) +} + +// readLinesOffsetN reads contents from file and splits them by new line. +// The offset tells at which line number to start. +// The count determines the number of lines to read (starting from offset): +// +// n >= 0: at most n lines +// n < 0: whole file +func readLinesOffsetN(filename string, offset uint, n int) ([]string, error) { + f, err := os.Open(filename) + if err != nil { + return []string{""}, err + } + defer f.Close() + + var ret []string + + r := bufio.NewReader(f) + for i := 0; i < n+int(offset) || n < 0; i++ { + line, err := r.ReadString('\n') + if err != nil { + break + } + if i < int(offset) { + continue + } + ret = append(ret, strings.Trim(line, "\n")) + } + + return ret, nil +} diff --git a/plugin/ratelimiter/bbr/img.jpg b/plugin/ratelimiter/bbr/img.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1fb4d84199060da874220a738dacca6d2ad500fd GIT binary patch literal 89650 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�)3kNU66(b1-&Rmk>`@Ykmpt4J+ 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 lo -1 { // maybe time backwards + return v + } + return r.size +} + +// apply applies function f with value val on +// current offset bucket, expired bucket will be reset +func (r *RollingPolicy) apply(f func(offset int, val float64), val float64) { + r.mu.Lock() + defer r.mu.Unlock() + + // calculate current offset + timespan := r.timespan() + oriTimespan := timespan + if timespan > 0 { + start := (r.offset + 1) % r.size + end := (r.offset + timespan) % r.size + if timespan > r.size { + timespan = r.size + } + // reset the expired buckets + r.window.ResetBuckets(start, timespan) + r.offset = end + r.lastAppendTime = r.lastAppendTime.Add(time.Duration(oriTimespan * int(r.bucketDuration))) + } + f(r.offset, val) +} + +// Append appends the given points to the window. +func (r *RollingPolicy) Append(val float64) { + r.apply(r.window.Append, val) +} + +// Add adds the given value to the latest point within bucket. +func (r *RollingPolicy) Add(val float64) { + r.apply(r.window.Add, val) +} + +// Reduce applies the reduction function to all buckets within the window. +func (r *RollingPolicy) Reduce(f func(Iterator) float64) (val float64) { + r.mu.RLock() + defer r.mu.RUnlock() + + timespan := r.timespan() + if count := r.size - timespan; count > 0 { + offset := r.offset + timespan + 1 + if offset >= r.size { + offset = offset - r.size + } + val = f(r.window.Iterator(offset, count)) + } + return val +} diff --git a/plugin/ratelimiter/bbr/window/policy_test.go b/plugin/ratelimiter/bbr/window/policy_test.go new file mode 100644 index 00000000..22e30946 --- /dev/null +++ b/plugin/ratelimiter/bbr/window/policy_test.go @@ -0,0 +1,106 @@ +package window + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func GetRollingPolicy() *RollingPolicy { + w := NewWindow(Options{Size: 3}) + return NewRollingPolicy(w, RollingPolicyOpts{BucketDuration: 100 * time.Millisecond}) +} + +func TestRollingPolicy_Add(t *testing.T) { + // test func timespan return real span + tests := []struct { + timeSleep []int + offset []int + points []int + }{ + { + timeSleep: []int{150, 51}, + offset: []int{1, 2}, + points: []int{1, 1}, + }, + { + timeSleep: []int{94, 250}, + offset: []int{0, 0}, + points: []int{1, 1}, + }, + { + timeSleep: []int{150, 300, 600}, + offset: []int{1, 1, 1}, + points: []int{1, 1, 1}, + }, + } + + for _, test := range tests { + t.Run("test policy add", func(t *testing.T) { + var totalTs, lastOffset int + timeSleep := test.timeSleep + policy := GetRollingPolicy() + for i, n := range timeSleep { + totalTs += n + time.Sleep(time.Duration(n) * time.Millisecond) + policy.Add(float64(test.points[i])) + offset, points := test.offset[i], test.points[i] + + assert.Equal(t, points, int(policy.window.buckets[offset].Points[0]), + fmt.Sprintf("error, time since last append: %vms, last offset: %v", totalTs, lastOffset)) + lastOffset = offset + } + }) + } +} + +func TestRollingPolicy_AddWithTimespan(t *testing.T) { + t.Run("timespan < bucket number", func(t *testing.T) { + policy := GetRollingPolicy() + // bucket 0 + policy.Add(0) + // bucket 1 + time.Sleep(101 * time.Millisecond) + policy.Add(1) + // bucket 2 + time.Sleep(101 * time.Millisecond) + policy.Add(2) + // bucket 1 + time.Sleep(201 * time.Millisecond) + policy.Add(4) + + for _, bkt := range policy.window.buckets { + t.Logf("%+v", bkt) + } + + assert.Equal(t, 0, len(policy.window.buckets[0].Points)) + assert.Equal(t, 4, int(policy.window.buckets[1].Points[0])) + assert.Equal(t, 2, int(policy.window.buckets[2].Points[0])) + }) + + t.Run("timespan > bucket number", func(t *testing.T) { + policy := GetRollingPolicy() + + // bucket 0 + policy.Add(0) + // bucket 1 + time.Sleep(101 * time.Millisecond) + policy.Add(1) + // bucket 2 + time.Sleep(101 * time.Millisecond) + policy.Add(2) + // bucket 1 + time.Sleep(501 * time.Millisecond) + policy.Add(4) + + for _, bkt := range policy.window.buckets { + t.Logf("%+v", bkt) + } + + assert.Equal(t, 0, len(policy.window.buckets[0].Points)) + assert.Equal(t, 4, int(policy.window.buckets[1].Points[0])) + assert.Equal(t, 0, len(policy.window.buckets[2].Points)) + }) +} diff --git a/plugin/ratelimiter/bbr/window/reduce.go b/plugin/ratelimiter/bbr/window/reduce.go new file mode 100644 index 00000000..17e60578 --- /dev/null +++ b/plugin/ratelimiter/bbr/window/reduce.go @@ -0,0 +1,77 @@ +package window + +// Sum the values within the window. +func Sum(iterator Iterator) float64 { + var result = 0.0 + for iterator.Next() { + bucket := iterator.Bucket() + for _, p := range bucket.Points { + result = result + p + } + } + return result +} + +// Avg the values within the window. +func Avg(iterator Iterator) float64 { + var result = 0.0 + var count = 0.0 + for iterator.Next() { + bucket := iterator.Bucket() + for _, p := range bucket.Points { + result = result + p + count = count + 1 + } + } + return result / count +} + +// Min the values within the window. +func Min(iterator Iterator) float64 { + var result = 0.0 + var started = false + for iterator.Next() { + bucket := iterator.Bucket() + for _, p := range bucket.Points { + if !started { + result = p + started = true + continue + } + if p < result { + result = p + } + } + } + return result +} + +// Max the values within the window. +func Max(iterator Iterator) float64 { + var result = 0.0 + var started = false + for iterator.Next() { + bucket := iterator.Bucket() + for _, p := range bucket.Points { + if !started { + result = p + started = true + continue + } + if p > result { + result = p + } + } + } + return result +} + +// Count sums the count value within the window. +func Count(iterator Iterator) float64 { + var result int64 + for iterator.Next() { + bucket := iterator.Bucket() + result += bucket.Count + } + return float64(result) +} diff --git a/plugin/ratelimiter/bbr/window/window.go b/plugin/ratelimiter/bbr/window/window.go new file mode 100644 index 00000000..b4a06aa7 --- /dev/null +++ b/plugin/ratelimiter/bbr/window/window.go @@ -0,0 +1,108 @@ +package window + +// Bucket contains multiple float64 points. +type Bucket struct { + Points []float64 + Count int64 + next *Bucket +} + +// Append appends the given value to the bucket. +func (b *Bucket) Append(val float64) { + b.Points = append(b.Points, val) + b.Count++ +} + +// Add adds the given value to the point. +func (b *Bucket) Add(offset int, val float64) { + b.Points[offset] += val + b.Count++ +} + +// Reset empties the bucket. +func (b *Bucket) Reset() { + b.Points = b.Points[:0] + b.Count = 0 +} + +// Next returns the next bucket. +func (b *Bucket) Next() *Bucket { + return b.next +} + +// Window contains multiple buckets. +type Window struct { + buckets []Bucket + size int +} + +// Options contains the arguments for creating Window. +type Options struct { + Size int +} + +// NewWindow creates a new Window based on WindowOpts. +func NewWindow(opts Options) *Window { + buckets := make([]Bucket, opts.Size) + for offset := range buckets { + buckets[offset].Points = make([]float64, 0) + nextOffset := offset + 1 + if nextOffset == opts.Size { + nextOffset = 0 + } + buckets[offset].next = &buckets[nextOffset] + } + return &Window{buckets: buckets, size: opts.Size} +} + +// ResetWindow empties all buckets within the window. +func (w *Window) ResetWindow() { + for offset := range w.buckets { + w.ResetBucket(offset) + } +} + +// ResetBucket empties the bucket based on the given offset. +func (w *Window) ResetBucket(offset int) { + w.buckets[offset%w.size].Reset() +} + +// ResetBuckets empties the buckets based on the given offsets. +func (w *Window) ResetBuckets(offset int, count int) { + for i := 0; i < count; i++ { + w.ResetBucket(offset + i) + } +} + +// Append appends the given value to the bucket where index equals the given offset. +func (w *Window) Append(offset int, val float64) { + w.buckets[offset%w.size].Append(val) +} + +// Add adds the given value to the latest point within bucket where index equals the given offset. +func (w *Window) Add(offset int, val float64) { + offset %= w.size + if w.buckets[offset].Count == 0 { + w.buckets[offset].Append(val) + return + } + w.buckets[offset].Add(0, val) +} + +// Bucket returns the bucket where index equals the given offset. +func (w *Window) Bucket(offset int) Bucket { + return w.buckets[offset%w.size] +} + +// Size returns the size of the window. +func (w *Window) Size() int { + return w.size +} + +// Iterator returns the count number buckets iterator from offset. +func (w *Window) Iterator(offset int, count int) Iterator { + return Iterator{ + count: count, + cur: &w.buckets[offset%w.size], + } +} diff --git a/plugin/ratelimiter/bbr/window/window_test.go b/plugin/ratelimiter/bbr/window/window_test.go new file mode 100644 index 00000000..36f6ce33 --- /dev/null +++ b/plugin/ratelimiter/bbr/window/window_test.go @@ -0,0 +1,68 @@ +package window + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestWindowResetWindow(t *testing.T) { + opts := Options{Size: 3} + window := NewWindow(opts) + for i := 0; i < opts.Size; i++ { + window.Append(i, 1.0) + } + window.ResetWindow() + for i := 0; i < opts.Size; i++ { + assert.Equal(t, len(window.Bucket(i).Points), 0) + } +} + +func TestWindowResetBucket(t *testing.T) { + opts := Options{Size: 3} + window := NewWindow(opts) + for i := 0; i < opts.Size; i++ { + window.Append(i, 1.0) + } + window.ResetBucket(1) + assert.Equal(t, len(window.Bucket(1).Points), 0) + assert.Equal(t, window.Bucket(0).Points[0], float64(1.0)) + assert.Equal(t, window.Bucket(2).Points[0], float64(1.0)) +} + +func TestWindowResetBuckets(t *testing.T) { + opts := Options{Size: 3} + window := NewWindow(opts) + for i := 0; i < opts.Size; i++ { + window.Append(i, 1.0) + } + window.ResetBuckets(0, 3) + for i := 0; i < opts.Size; i++ { + assert.Equal(t, len(window.Bucket(i).Points), 0) + } +} + +func TestWindowAppend(t *testing.T) { + opts := Options{Size: 3} + window := NewWindow(opts) + for i := 0; i < opts.Size; i++ { + window.Append(i, 1.0) + } + for i := 0; i < opts.Size; i++ { + assert.Equal(t, window.Bucket(i).Points[0], float64(1.0)) + } +} + +func TestWindowAdd(t *testing.T) { + opts := Options{Size: 3} + window := NewWindow(opts) + window.Append(0, 1.0) + window.Add(0, 1.0) + assert.Equal(t, window.Bucket(0).Points[0], float64(2.0)) +} + +func TestWindowSize(t *testing.T) { + opts := Options{Size: 3} + window := NewWindow(opts) + assert.Equal(t, window.Size(), 3) +} diff --git a/plugin/ratelimiter/cpubbr/bucket.go b/plugin/ratelimiter/cpubbr/bucket.go deleted file mode 100644 index 29c13660..00000000 --- a/plugin/ratelimiter/cpubbr/bucket.go +++ /dev/null @@ -1,76 +0,0 @@ -package cpubbr - -import ( - "github.com/polarismesh/polaris-go/pkg/model" - "github.com/polarismesh/polaris-go/pkg/model/pb" - "github.com/polarismesh/polaris-go/pkg/plugin/ratelimiter" - apitraffic "github.com/polarismesh/specification/source/go/api/v1/traffic_manage" - - aegislimiter "github.com/go-kratos/aegis/ratelimit" - "github.com/go-kratos/aegis/ratelimit/bbr" -) - -type CpuBbrQuota struct { - aegislimiter.Limiter -} - -// GetQuota 获取限额 -func (b *CpuBbrQuota) GetQuota(curTimeMs int64, token uint32) *model.QuotaResponse { - // 默认返回 ok - resp := &model.QuotaResponse{Code: model.QuotaResultOk} - - // 如果触发限流,err 值将等于 aegislimiter.ErrLimitExceed - done, err := b.Limiter.Allow() - if err != nil { - resp.Code = model.QuotaResultLimited - return resp - } - - // 返回函数执行 - done(aegislimiter.DoneInfo{}) - - return resp -} - -// Release 释放资源 -func (b *CpuBbrQuota) Release() {} - -// OnRemoteUpdate 远端更新的时候通知,cpu限流策略是本地模式,不用实现 -func (b *CpuBbrQuota) OnRemoteUpdate(result ratelimiter.RemoteQuotaResult) { - -} - -// GetQuotaUsed 返回本地限流信息用于上报,cpu限流策略本地模式,不用实现 -func (b *CpuBbrQuota) GetQuotaUsed(curTimeMilli int64) ratelimiter.UsageInfo { - return ratelimiter.UsageInfo{} -} - -// GetAmountInfos 获取规则的限流阈值信息,用于与服务端pb交互 -func (b *CpuBbrQuota) GetAmountInfos() []ratelimiter.AmountInfo { - return nil -} - -// createCpuBbrLimiter 初始化一个CPU策略桶 -func createCpuBbrLimiter(amount *apitraffic.SystemResourceAmount) *CpuBbrQuota { - cpuQuota := &CpuBbrQuota{} - - var options []bbr.Option - - // 统计时间窗口,默认 10s - window, _ := pb.ConvertDuration(amount.GetWindow()) - if window > 0 { - options = append(options, bbr.WithWindow(window)) - } - // 观测时间窗口内 计数桶 的个数,默认100个 - precision := int(amount.GetPrecision().GetValue()) - if precision > 0 { - options = append(options, bbr.WithBucket(precision)) - } - // CPU使用率阈值,默认80% - threshold := int64(amount.GetThreshold().GetValue() * 1000) - if threshold > 0 { - options = append(options, bbr.WithCPUThreshold(threshold)) - } - cpuQuota.Limiter = bbr.NewLimiter(options...) - return cpuQuota -} diff --git a/plugin/ratelimiter/reject/bucket.go b/plugin/ratelimiter/reject/bucket.go index f058d254..95920466 100644 --- a/plugin/ratelimiter/reject/bucket.go +++ b/plugin/ratelimiter/reject/bucket.go @@ -31,6 +31,11 @@ func (q *QuotaBucketReject) GetQuota(curTimeMs int64, token uint32) *model.Quota return q.bucket.Allocate(curTimeMs, token) } +// GetQuotaWithRelease 在令牌桶/漏桶中进行单个配额的划扣,并返回本次分配的结果 +func (q *QuotaBucketReject) GetQuotaWithRelease(curTimeMs int64, token uint32) (*model.QuotaResponse, func()) { + return q.bucket.Allocate(curTimeMs, token), nil +} + // Release 释放配额(仅对于并发数限流有用) func (q *QuotaBucketReject) Release() { q.bucket.Release() diff --git a/plugin/ratelimiter/unirate/bucket_leaky.go b/plugin/ratelimiter/unirate/bucket_leaky.go index 1c1076c8..8b1edfca 100644 --- a/plugin/ratelimiter/unirate/bucket_leaky.go +++ b/plugin/ratelimiter/unirate/bucket_leaky.go @@ -156,6 +156,11 @@ func (l *LeakyBucket) GetQuota(curTimeMs int64, token uint32) *model.QuotaRespon return l.allocateQuota() } +// GetQuotaWithRelease 在令牌桶/漏桶中进行单个配额的划扣,并返回本次分配的结果 +func (l *LeakyBucket) GetQuotaWithRelease(_ int64, _ uint32) (*model.QuotaResponse, func()) { + return l.allocateQuota(), nil +} + // Release 释放配额(仅对于并发数限流有用) func (l *LeakyBucket) Release() { diff --git a/plugin/serverconnector/common/util.go b/plugin/serverconnector/common/util.go index 40961889..2138c854 100644 --- a/plugin/serverconnector/common/util.go +++ b/plugin/serverconnector/common/util.go @@ -49,6 +49,9 @@ const ( reqIDPrefixRateLimitAcquire reqIDPrefixGetConfigFile reqIDPrefixWatchConfigFiles + reqIDPrefixCreateConfigFile + reqIDPrefixUpdateConfigFile + reqIDPrefixPublishConfigFile ) const ( @@ -63,6 +66,9 @@ const ( OpKeyRateLimitMetricReport = "RateLimitMetricReport" OpKeyGetConfigFile = "GetConfigFile" OpKeyWatchConfigFiles = "WatchConfigFiles" + OpKeyCreateConfigFile = "CreateConfigFile" + OpKeyUpdateConfigFile = "UpdateConfigFile" + OpKeyPublishConfigFile = "PublishConfigFile" ) // NextDiscoverReqID 生成GetInstances调用的请求Id @@ -110,6 +116,21 @@ func NextWatchConfigFilesReqID() string { return fmt.Sprintf("%d%d", reqIDPrefixWatchConfigFiles, uuid.New().ID()) } +// NextCreateConfigFileReqID 生成CreateConfigFile调用的请求Id +func NextCreateConfigFileReqID() string { + return fmt.Sprintf("%d%d", reqIDPrefixCreateConfigFile, uuid.New().ID()) +} + +// NextUpdateConfigFileReqID 生成UpdateConfigFile调用的请求Id +func NextUpdateConfigFileReqID() string { + return fmt.Sprintf("%d%d", reqIDPrefixUpdateConfigFile, uuid.New().ID()) +} + +// NextPublishConfigFileReqID 生成PublishConfigFile调用的请求Id +func NextPublishConfigFileReqID() string { + return fmt.Sprintf("%d%d", reqIDPrefixPublishConfigFile, uuid.New().ID()) +} + // GetConnErrorCode 获取连接错误码 func GetConnErrorCode(err error) int32 { code, ok := status.FromError(err) diff --git a/polaris.yaml b/polaris.yaml index 8d510980..2116f3ed 100644 --- a/polaris.yaml +++ b/polaris.yaml @@ -338,6 +338,20 @@ config: propertiesValueCacheSize: 100 # 类型转化缓存的过期时间,默认为1分钟 propertiesValueExpireTime: 60000 + # 本地缓存配置 + localCache: + #描述: 配置文件持久化到本地开关 + persistEnable: true + #描述: 配置文件持久化目录,SDK在配置文件变更后,把相关的配置持久化到本地磁盘 + persistDir: ./polaris/backup/config + #描述: 配置文件写盘失败的最大重试次数 + persistMaxWriteRetry: 1 + #描述: 配置文件从磁盘读取失败的最大重试次数 + persistMaxReadRetry: 0 + #描述: 缓存读写磁盘的重试间隔 + persistRetryInterval: 500ms + #描述: 远端获取配置文件失败,兜底降级到本地文件缓存 + fallbackToLocalCache: true # 连接器配置,默认为北极星服务端 configConnector: id: polaris-config