diff --git a/README.md b/README.md index 8aabed4e..203d8075 100644 --- a/README.md +++ b/README.md @@ -126,18 +126,19 @@ metadata: ### Sink Configure Supported Sinks: -| Sink Name | Description | -| ---------------------------- | :-------------------------------- | -| dingtalk | sink to dingtalk bot | -| sls | sink to alibaba cloud sls service | +| Sink Name | Description | +|-----------------------------------------------------------|:----------------------------------| +| dingtalk | sink to dingtalk bot | +| sls | sink to alibaba cloud sls service | | elasticsearch | sink to elasticsearch | -| honeycomb | sink to honeycomb | -| influxdb | sink to influxdb | -| kafka | sink to kafka | -| mysql | sink to mysql database | -| wechat | sink to wechat | -| webhook | sink to webhook | -| mongodb | sink to mongodb | +| honeycomb | sink to honeycomb | +| influxdb | sink to influxdb | +| kafka | sink to kafka | +| mysql | sink to mysql database | +| wechat | sink to wechat | +| webhook | sink to webhook | +| mongodb | sink to mongodb | +| pulsar | sink to pulsar | ### Contributing Please check CONTRIBUTING.md diff --git a/common/pulsar/pulsar.go b/common/pulsar/pulsar.go new file mode 100644 index 00000000..ffab843d --- /dev/null +++ b/common/pulsar/pulsar.go @@ -0,0 +1,116 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pulsar + +import ( + "context" + "encoding/json" + "fmt" + "github.com/apache/pulsar-client-go/pulsar" + "k8s.io/klog" + "net/url" + "time" +) + +type PulsarClient interface { + Name() string + Stop() + ProducePulsarMessage(msgData interface{}) error +} + +type pulsarSink struct { + topic string + producer pulsar.Producer +} + +func (p *pulsarSink) Name() string { + return "Apache Pulsar Sink" +} + +func (p *pulsarSink) Stop() { + p.producer.Close() + +} + +func (p *pulsarSink) ProducePulsarMessage(msgData interface{}) error { + start := time.Now() + msgJson, err := json.Marshal(msgData) + if err != nil { + return fmt.Errorf("failed to transform the items to json : %s", err) + } + send, err := p.producer.Send(context.Background(), &pulsar.ProducerMessage{ + Payload: msgJson, + Properties: nil, + }) + if err != nil { + return fmt.Errorf("failed to produce message to Pulsar: %s", err) + } + end := time.Now() + klog.V(4).Infof("Exported %d data to Pulsar in %s, messageID: %s", len(msgJson), end.Sub(start), send.String()) + return nil +} + +func NewPulsarClient(uri *url.URL) (PulsarClient, error) { + opts, err := url.ParseQuery(uri.RawQuery) + if err != nil { + return nil, fmt.Errorf("failed to parse url's query string: %s", err) + } + klog.V(3).Infof("Pulsar opts: %v", opts) + + var ( + serviceURL []string + token, topic string + client pulsar.Client + ) + if len(opts["serviceurl"]) < 1 { + return nil, fmt.Errorf("there is no broker assigned for connecting Pulsar") + } + serviceURL = append(serviceURL, opts["serviceurl"]...) + + if len(opts["eventstopic"]) != 1 { + return nil, fmt.Errorf("there is no topic assigned for connecting Pulsar") + } + topic = opts["eventstopic"][0] + + if len(opts["token"]) > 0 { + token = opts["token"][0] + } + + if len(token) == 0 { + client, err = pulsar.NewClient(pulsar.ClientOptions{ + URL: serviceURL[0], + }) + if err != nil { + return nil, fmt.Errorf("failed to create Pulsar client: %v", err) + } + } else { + client, err = pulsar.NewClient(pulsar.ClientOptions{ + URL: serviceURL[0], + Authentication: pulsar.NewAuthenticationToken(token), + }) + if err != nil { + return nil, fmt.Errorf("failed to create Pulsar client: %v", err) + } + } + + producer, err := client.CreateProducer(pulsar.ProducerOptions{ + Name: "kube-eventer", + Topic: topic, + }) + + return &pulsarSink{ + producer: producer, + }, nil +} diff --git a/docs/en/pulsar-sink.md b/docs/en/pulsar-sink.md new file mode 100644 index 00000000..8ec333a9 --- /dev/null +++ b/docs/en/pulsar-sink.md @@ -0,0 +1,15 @@ +### Pulsar sink + +To use the Pulsar sink add the following flag: + + --sink=Pulsar:> + +* `serviceurl` - Pulsar's broker or proxy. +* `eventstopic` - Pulsar's topic for events. +* `token` - Pulsar's JWT token, If you enable [JWT](https://pulsar.apache.org/docs/next/security-jwt/). + +For example, + + --sink=pulsar:?serviceurl=pulsar://127.0.0.1:6650&eventstopic=persistent://public/default/event&token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9 + or + --sink=pulsar:?serviceurl=pulsar://127.0.0.1:6650&eventstopic=persistent://public/default/event \ No newline at end of file diff --git a/go.mod b/go.mod index 574072b7..59dd899b 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,13 @@ require ( github.com/Shopify/sarama v1.22.1 github.com/alibabacloud-go/eventbridge-sdk v1.2.6 github.com/alibabacloud-go/tea-utils v1.3.7 + github.com/apache/pulsar-client-go v0.10.0 github.com/aws/aws-sdk-go v1.34.28 github.com/denverdino/aliyungo v0.0.0-20190410085603-611ead8a6fed github.com/go-sql-driver/mysql v1.5.0 - github.com/golang/protobuf v1.4.3 + github.com/golang/protobuf v1.5.2 github.com/google/cadvisor v0.33.1 - github.com/google/uuid v1.1.1 + github.com/google/uuid v1.1.2 github.com/imdario/mergo v0.3.7 // indirect github.com/influxdata/influxdb v1.7.7 github.com/mailru/easyjson v0.7.0 // indirect @@ -22,7 +23,7 @@ require ( github.com/riemann/riemann-go-client v0.4.0 github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 github.com/smartystreets/gunit v1.0.0 // indirect - github.com/stretchr/testify v1.6.1 + github.com/stretchr/testify v1.8.0 go.mongodb.org/mongo-driver v1.5.1 golang.org/x/sys v0.2.0 // indirect gopkg.in/olivere/elastic.v3 v3.0.75 diff --git a/go.sum b/go.sum index 97a340b6..f8a792a5 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,42 @@ 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/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/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/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/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= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= +github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= +github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= +github.com/AthenZ/athenz v1.10.39 h1:mtwHTF/v62ewY2Z5KWhuZgVXftBej1/Tn80zx4DcawY= +github.com/AthenZ/athenz v1.10.39/go.mod h1:3Tg8HLsiQZp81BJY58JBeU2BR6B/H4/0MQGfCwhHNEA= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= @@ -9,8 +45,10 @@ github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxB github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798 h1:2T/jmrHeTezcCM58lvEQXs0UpQJCo5SoGAcg+mbSTIg= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.5.0 h1:+K/VEwIAaPcHiMtQvpLD4lqW7f0Gk3xdYZmI1hD+CXo= +github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= @@ -41,17 +79,34 @@ github.com/alibabacloud-go/tea-utils v1.3.7 h1:oWLLV21JHimM8yiQcRajMYxy+dggFW7jC github.com/alibabacloud-go/tea-utils v1.3.7/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= github.com/aliyun/credentials-go v1.1.2 h1:qU1vwGIBb3UJ8BwunHDRFtAhS6jnQLnde/yk0+Ih2GY= github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= +github.com/apache/pulsar-client-go v0.10.0 h1:ccwjmmaCjaE6bLYnrILpm8V4WQQ8rB3J98pOW0O2nyo= +github.com/apache/pulsar-client-go v0.10.0/go.mod h1:l9ZNSafZdle1cpyFE5CkUL3uRYJMvoHjHHLlK0kL7c8= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/ardielle/ardielle-go v1.5.2 h1:TilHTpHIQJ27R1Tl/iITBzMwiUGSlVfiVhwDNGM3Zj4= +github.com/ardielle/ardielle-go v1.5.2/go.mod h1:I4hy1n795cUhaVt/ojz83SNVCYIGsAFAONtv2Dr7HUI= +github.com/ardielle/ardielle-tools v1.5.4/go.mod h1:oZN+JRMnqGiIhrzkRN9l26Cej9dEx4jeNG6A+AdkShk= github.com/aws/aws-sdk-go v1.19.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.32.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk= github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= 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/bits-and-blooms/bitset v1.4.0 h1:+YZ8ePm+He2pU3dZlIZiOeAKfrBkXi1lSrXJ/Xzgbu8= +github.com/bits-and-blooms/bitset v1.4.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/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/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= +github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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= @@ -59,7 +114,11 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/denverdino/aliyungo v0.0.0-20190410085603-611ead8a6fed h1:WtFFp2kd7j/ATD3dT5tdjyoXuynxHu6D0AJVG9Be1q4= github.com/denverdino/aliyungo v0.0.0-20190410085603-611ead8a6fed/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimfeld/httptreemux v5.0.1+incompatible h1:Qj3gVcDNoOthBAqftuD596rm4wg/adLLz5xh5CmpiCA= +github.com/dimfeld/httptreemux v5.0.1+incompatible/go.mod h1:rbUlSV+CCpv/SuqUTP/8Bk2O3LyUV436/yaRGkhP6Z0= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= +github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= @@ -68,12 +127,21 @@ github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/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= @@ -89,6 +157,7 @@ github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gG github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= @@ -113,26 +182,44 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= +github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +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/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 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 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= 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.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -144,6 +231,9 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a 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.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= @@ -152,11 +242,22 @@ github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSN github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= 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/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-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= @@ -165,17 +266,26 @@ github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3 github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= 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/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +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/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb v1.7.7 h1:UvNzAPfBrKMENVbQ4mr4ccA9sW+W1Ihl0Yh1s0BiVAg= github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/jawher/mow.cli v1.0.4/go.mod h1:5hQj2V8g+qYmLUVWqu4Wuja1pI57M83EChYLVZ0sMKk= +github.com/jawher/mow.cli v1.2.0/go.mod h1:y+pcA3jBAdo/GIZx/0rFjw/K2bVEODP9rfZOfaiq8Ko= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -189,6 +299,7 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 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= @@ -197,16 +308,21 @@ github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaR github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.14.4 h1:eijASRJcobkVtSt81Olfh7JX43osYLwy5krOJo6YEu4= +github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= 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.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= 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.0/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/linkedin/goavro/v2 v2.9.8 h1:jN50elxBsGBDGVDEKqUlDuU1cFwJ11K/yrJCBMe/7Wg= +github.com/linkedin/goavro/v2 v2.9.8/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -224,12 +340,17 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= +github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/olivere/elastic v6.2.23+incompatible h1:oRGUA/8fKcnkDcqLuwGb5YCzgbgEBo+Y9gamsWqZ0qU= github.com/olivere/elastic v6.2.23+incompatible/go.mod h1:J+q1zQJTgAz9woqsbVRqGeB5G1iqDKVBWLNSYW8yfJ8= github.com/olivere/elastic/v7 v7.0.6 h1:BIzjaAYGL8Ur1pIPIpiYDvly4HkHrO/uakiV22WDEQQ= @@ -238,10 +359,22 @@ github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= @@ -267,6 +400,7 @@ github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqr github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/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.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -287,10 +421,12 @@ github.com/riemann/riemann-go-client v0.4.0/go.mod h1:F+UlZkpX4Bd/sO5rdI2g5uqkIG github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= @@ -302,8 +438,11 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/gunit v1.0.0 h1:RyPDUFcJbvtXlhJPk7v+wnxZRY2EUokhEYl2EJOPToI= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -311,13 +450,19 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An 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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 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 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 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 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= @@ -330,17 +475,29 @@ github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhe github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +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.30/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= go.mongodb.org/mongo-driver v1.5.1 h1:9nOVLGDfOaZ9R0tBumx/BcuqkbFpyTCU2r/Po7A2azI= go.mongodb.org/mongo-driver v1.5.1/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= 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.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/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-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +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-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -348,10 +505,37 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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/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.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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= @@ -362,18 +546,41 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r 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-20191004110552-13f9640d40b9/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-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/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-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 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 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= 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-20210402161424-2e8d93401602 h1:0Ja1LBD+yisY6RWM/BH7TJVXWsSjs2VwBSmvSX4HdBc= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 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= @@ -382,6 +589,8 @@ golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-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 h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -392,98 +601,248 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/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-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/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-20190531175056-4c3a928424d2/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-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/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-20200509044756-6aff5f38e54f/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-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-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/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-20210819135213-f52c844e1c1c/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-20220204135822-1c1b9b1eba6a/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 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +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.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.3/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 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/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-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190420181800-aa740d480789/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-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +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-20200509030707-2212a7e161a5/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-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= 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/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 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= 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 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +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-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/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= 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/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.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ= +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 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 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-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.56.0 h1:DPMeDvGTM54DXbPkVIZsp19fp/I2K7zwA/itHYHKo8Y= gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/olivere/elastic.v3 v3.0.75 h1:u3B8p1VlHF3yNLVOlhIWFT3F1ICcHfM5V6FFJe6pPSo= gopkg.in/olivere/elastic.v3 v3.0.75/go.mod h1:yDEuSnrM51Pc8dM5ov7U8aI/ToR3PG0llA8aRv2qmw0= gopkg.in/olivere/elastic.v5 v5.0.81 h1:21Vu9RMT2qXVLqXINtiOhwVPYz/87+Omsxh/Re+gK4k= gopkg.in/olivere/elastic.v5 v5.0.81/go.mod h1:uhHoB4o3bvX5sorxBU29rPcmBQdV2Qfg0FBrx5D6pV0= gopkg.in/olivere/elastic.v6 v6.2.23 h1:wDrXwXXecu8t/mTPbvMu8zONtTJA201IKq1RxSeEU38= gopkg.in/olivere/elastic.v6 v6.2.23/go.mod h1:2cTT8Z+/LcArSWpCgvZqBgt3VOqXiy7v00w12Lz8bd4= +gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 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.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 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +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-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-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= k8s.io/api v0.17.4 h1:HbwOhDapkguO8lTAE8OX3hdF2qp8GtpC9CW/MQATXXo= k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA= k8s.io/apimachinery v0.17.4 h1:UzM+38cPUJnzqSQ+E1PY4YxMHIzQyCg29LOoGfo79Zw= @@ -498,6 +857,9 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +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= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/sinks/factory.go b/sinks/factory.go index 503dd01e..e8d9d80a 100755 --- a/sinks/factory.go +++ b/sinks/factory.go @@ -27,6 +27,7 @@ import ( "github.com/AliyunContainerService/kube-eventer/sinks/log" "github.com/AliyunContainerService/kube-eventer/sinks/mongo" "github.com/AliyunContainerService/kube-eventer/sinks/mysql" + "github.com/AliyunContainerService/kube-eventer/sinks/pulsar" "github.com/AliyunContainerService/kube-eventer/sinks/riemann" "github.com/AliyunContainerService/kube-eventer/sinks/sls" "github.com/AliyunContainerService/kube-eventer/sinks/webhook" @@ -65,6 +66,8 @@ func (this *SinkFactory) Build(uri flags.Uri) (core.EventSink, error) { return eventbridge.NewEventBridgeSink(&uri.Val) case "mongo": return mongo.CreateMongoSink(&uri.Val) + case "pulsar": + return pulsar.NewPulsarSink(&uri.Val) default: return nil, fmt.Errorf("Sink not recognized: %s", uri.Key) } diff --git a/sinks/pulsar/pulsar.go b/sinks/pulsar/pulsar.go new file mode 100644 index 00000000..2218076c --- /dev/null +++ b/sinks/pulsar/pulsar.go @@ -0,0 +1,93 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pulsar + +import ( + "encoding/json" + pulsar_common "github.com/AliyunContainerService/kube-eventer/common/pulsar" + event_core "github.com/AliyunContainerService/kube-eventer/core" + "github.com/AliyunContainerService/kube-eventer/metrics/core" + kube_api "k8s.io/api/core/v1" + "k8s.io/klog" + "net/url" + "sync" + "time" +) + +type PulsarSinkPoint struct { + EventValue interface{} + EventTimestamp time.Time + EventTags map[string]string +} + +type pulsarSink struct { + pulsar_common.PulsarClient + sync.RWMutex +} + +func (p *pulsarSink) ExportEvents(batch *event_core.EventBatch) { + p.Lock() + defer p.Unlock() + for _, event := range batch.Events { + point, err := eventToPoint(event) + if err != nil { + klog.Warningf("Failed to convert event to point: %v", err) + } + + err = p.ProducePulsarMessage(*point) + if err != nil { + klog.Errorf("Failed to produce event message: %s", err) + } + } +} + +func getEventValue(event *kube_api.Event) (string, error) { + bytes, err := json.MarshalIndent(event, "", " ") + if err != nil { + return "", err + } + return string(bytes), nil +} + +func eventToPoint(event *kube_api.Event) (*PulsarSinkPoint, error) { + value, err := getEventValue(event) + if err != nil { + return nil, err + } + point := PulsarSinkPoint{ + EventTimestamp: event.LastTimestamp.Time.UTC(), + EventValue: value, + EventTags: map[string]string{ + "eventID": string(event.UID), + }, + } + if event.InvolvedObject.Kind == "Pod" { + point.EventTags[core.LabelPodId.Key] = string(event.InvolvedObject.UID) + point.EventTags[core.LabelPodName.Key] = event.InvolvedObject.Name + } + point.EventTags[core.LabelHostname.Key] = event.Source.Host + return &point, nil +} + +func NewPulsarSink(uri *url.URL) (event_core.EventSink, error) { + client, err := pulsar_common.NewPulsarClient(uri) + if err != nil { + return nil, err + } + + return &pulsarSink{ + PulsarClient: client, + }, nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/LICENSE b/vendor/github.com/apache/pulsar-client-go/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/apache/pulsar-client-go/NOTICE b/vendor/github.com/apache/pulsar-client-go/NOTICE new file mode 100644 index 00000000..92236a67 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/NOTICE @@ -0,0 +1,6 @@ + +Apache Pulsar +Copyright 2017-2019 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). \ No newline at end of file diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/auth.go b/vendor/github.com/apache/pulsar-client-go/oauth2/auth.go new file mode 100644 index 00000000..d44bd350 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/auth.go @@ -0,0 +1,133 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package oauth2 + +import ( + "fmt" + "time" + + "github.com/apache/pulsar-client-go/oauth2/clock" + "github.com/golang-jwt/jwt" + "golang.org/x/oauth2" +) + +const ( + ClaimNameUserName = "https://pulsar.apache.org/username" + ClaimNameName = "name" + ClaimNameSubject = "sub" +) + +// Flow abstracts an OAuth 2.0 authentication and authorization flow +type Flow interface { + // Authorize obtains an authorization grant based on an OAuth 2.0 authorization flow. + // The method returns a grant which may contain an initial access token. + Authorize(audience string) (*AuthorizationGrant, error) +} + +// AuthorizationGrantRefresher refreshes OAuth 2.0 authorization grant +type AuthorizationGrantRefresher interface { + // Refresh refreshes an authorization grant to contain a fresh access token + Refresh(grant *AuthorizationGrant) (*AuthorizationGrant, error) +} + +type AuthorizationGrantType string + +const ( + // GrantTypeClientCredentials represents a client credentials grant + GrantTypeClientCredentials AuthorizationGrantType = "client_credentials" + + // GrantTypeDeviceCode represents a device code grant + GrantTypeDeviceCode AuthorizationGrantType = "device_code" +) + +// AuthorizationGrant is a credential representing the resource owner's authorization +// to access its protected resources, and is used by the client to obtain an access token +type AuthorizationGrant struct { + // Type describes the type of authorization grant represented by this structure + Type AuthorizationGrantType `json:"type"` + + // Audience is the intended audience of the access tokens + Audience string `json:"audience,omitempty"` + + // ClientID is an OAuth2 client identifier used by some flows + ClientID string `json:"client_id,omitempty"` + + // ClientCredentials is credentials data for the client credentials grant type + ClientCredentials *KeyFile `json:"client_credentials,omitempty"` + + // the token endpoint + TokenEndpoint string `json:"token_endpoint"` + + // Token contains an access token in the client credentials grant type, + // and a refresh token in the device authorization grant type + Token *oauth2.Token `json:"token,omitempty"` + + // Scopes contains the scopes associated with the grant, or the scopes + // to request in the client credentials grant type + Scopes []string `json:"scopes,omitempty"` +} + +// TokenResult holds token information +type TokenResult struct { + AccessToken string `json:"access_token"` + IDToken string `json:"id_token"` + RefreshToken string `json:"refresh_token"` + ExpiresIn int `json:"expires_in"` +} + +// Issuer holds information about the issuer of tokens +type Issuer struct { + IssuerEndpoint string + ClientID string + Audience string +} + +func convertToOAuth2Token(token *TokenResult, clock clock.Clock) oauth2.Token { + return oauth2.Token{ + AccessToken: token.AccessToken, + TokenType: "bearer", + RefreshToken: token.RefreshToken, + Expiry: clock.Now().Add(time.Duration(token.ExpiresIn) * time.Second), + } +} + +// ExtractUserName extracts the username claim from an authorization grant +// conforms to draft-ietf-oauth-access-token-jwt +func ExtractUserName(token oauth2.Token) (string, error) { + p := jwt.Parser{} + claims := jwt.MapClaims{} + if _, _, err := p.ParseUnverified(token.AccessToken, claims); err != nil { + return "", fmt.Errorf("unable to decode the access token: %v", err) + } + username, ok := claims[ClaimNameUserName] + if !ok { + username, ok = claims[ClaimNameName] + } + if !ok { + username, ok = claims[ClaimNameSubject] + } + if !ok { + return "", fmt.Errorf("access token doesn't contain a username claim") + } + switch v := username.(type) { + case string: + return v, nil + default: + return "", fmt.Errorf("access token contains an unsupported username claim") + } +} diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/authorization_tokenretriever.go b/vendor/github.com/apache/pulsar-client-go/oauth2/authorization_tokenretriever.go new file mode 100644 index 00000000..cc9d3269 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/authorization_tokenretriever.go @@ -0,0 +1,353 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package oauth2 + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "mime" + "net/http" + "net/url" + "strconv" + "strings" + "time" +) + +// TokenRetriever implements AuthTokenExchanger in order to facilitate getting +// Tokens +type TokenRetriever struct { + transport HTTPAuthTransport +} + +// AuthorizationTokenResponse is the HTTP response when asking for a new token. +// Note that not all fields will contain data based on what kind of request was +// sent +type AuthorizationTokenResponse struct { + AccessToken string `json:"access_token"` + ExpiresIn int `json:"expires_in"` + IDToken string `json:"id_token"` + RefreshToken string `json:"refresh_token"` + TokenType string `json:"token_type"` +} + +// AuthorizationCodeExchangeRequest is used to request the exchange of an +// authorization code for a token +type AuthorizationCodeExchangeRequest struct { + TokenEndpoint string + ClientID string + CodeVerifier string + Code string + RedirectURI string +} + +// RefreshTokenExchangeRequest is used to request the exchange of a refresh +// token for a refreshed token +type RefreshTokenExchangeRequest struct { + TokenEndpoint string + ClientID string + RefreshToken string +} + +// ClientCredentialsExchangeRequest is used to request the exchange of +// client credentials for a token +type ClientCredentialsExchangeRequest struct { + TokenEndpoint string + ClientID string + ClientSecret string + Audience string + Scopes []string +} + +// DeviceCodeExchangeRequest is used to request the exchange of +// a device code for a token +type DeviceCodeExchangeRequest struct { + TokenEndpoint string + ClientID string + DeviceCode string + PollInterval time.Duration +} + +// TokenErrorResponse is used to parse error responses from the token endpoint +type TokenErrorResponse struct { + Error string `json:"error"` + ErrorDescription string `json:"error_description"` +} + +type TokenError struct { + ErrorCode string + ErrorDescription string +} + +func (e *TokenError) Error() string { + if e.ErrorDescription != "" { + return fmt.Sprintf("%s (%s)", e.ErrorDescription, e.ErrorCode) + } + return e.ErrorCode +} + +// HTTPAuthTransport abstracts how an HTTP exchange request is sent and received +type HTTPAuthTransport interface { + Do(request *http.Request) (*http.Response, error) +} + +// NewTokenRetriever allows a TokenRetriever the internal of a new +// TokenRetriever to be easily set up +func NewTokenRetriever(authTransport HTTPAuthTransport) *TokenRetriever { + return &TokenRetriever{ + transport: authTransport, + } +} + +// newExchangeCodeRequest builds a new AuthTokenRequest wrapped in an +// http.Request +func (ce *TokenRetriever) newExchangeCodeRequest( + req AuthorizationCodeExchangeRequest) (*http.Request, error) { + uv := url.Values{} + uv.Set("grant_type", "authorization_code") + uv.Set("client_id", req.ClientID) + uv.Set("code_verifier", req.CodeVerifier) + uv.Set("code", req.Code) + uv.Set("redirect_uri", req.RedirectURI) + + euv := uv.Encode() + + request, err := http.NewRequest("POST", + req.TokenEndpoint, + strings.NewReader(euv), + ) + if err != nil { + return nil, err + } + + request.Header.Add("Content-Type", "application/x-www-form-urlencoded") + request.Header.Add("Content-Length", strconv.Itoa(len(euv))) + + return request, nil +} + +// newDeviceCodeExchangeRequest builds a new DeviceCodeExchangeRequest wrapped in an +// http.Request +func (ce *TokenRetriever) newDeviceCodeExchangeRequest( + req DeviceCodeExchangeRequest) (*http.Request, error) { + uv := url.Values{} + uv.Set("grant_type", "urn:ietf:params:oauth:grant-type:device_code") + uv.Set("client_id", req.ClientID) + uv.Set("device_code", req.DeviceCode) + euv := uv.Encode() + + request, err := http.NewRequest("POST", + req.TokenEndpoint, + strings.NewReader(euv), + ) + if err != nil { + return nil, err + } + + request.Header.Add("Content-Type", "application/x-www-form-urlencoded") + request.Header.Add("Content-Length", strconv.Itoa(len(euv))) + + return request, nil +} + +// newRefreshTokenRequest builds a new RefreshTokenRequest wrapped in an +// http.Request +func (ce *TokenRetriever) newRefreshTokenRequest(req RefreshTokenExchangeRequest) (*http.Request, error) { + uv := url.Values{} + uv.Set("grant_type", "refresh_token") + uv.Set("client_id", req.ClientID) + uv.Set("refresh_token", req.RefreshToken) + + euv := uv.Encode() + + request, err := http.NewRequest("POST", + req.TokenEndpoint, + strings.NewReader(euv), + ) + if err != nil { + return nil, err + } + + request.Header.Add("Content-Type", "application/x-www-form-urlencoded") + request.Header.Add("Content-Length", strconv.Itoa(len(euv))) + + return request, nil +} + +// newClientCredentialsRequest builds a new ClientCredentialsExchangeRequest wrapped in an +// http.Request +func (ce *TokenRetriever) newClientCredentialsRequest(req ClientCredentialsExchangeRequest) (*http.Request, error) { + uv := url.Values{} + uv.Set("grant_type", "client_credentials") + uv.Set("client_id", req.ClientID) + uv.Set("client_secret", req.ClientSecret) + if len(req.Scopes) > 0 { + uv.Set("scope", strings.Join(req.Scopes, " ")) + } + if req.Audience != "" { + // Audience is an Auth0 extension; other providers use scopes to similar effect. + uv.Set("audience", req.Audience) + } + + euv := uv.Encode() + + request, err := http.NewRequest("POST", + req.TokenEndpoint, + strings.NewReader(euv), + ) + if err != nil { + return nil, err + } + + request.Header.Add("Content-Type", "application/x-www-form-urlencoded") + request.Header.Add("Content-Length", strconv.Itoa(len(euv))) + + return request, nil +} + +// ExchangeCode uses the AuthCodeExchangeRequest to exchange an authorization +// code for tokens +func (ce *TokenRetriever) ExchangeCode(req AuthorizationCodeExchangeRequest) (*TokenResult, error) { + request, err := ce.newExchangeCodeRequest(req) + if err != nil { + return nil, err + } + + response, err := ce.transport.Do(request) + if err != nil { + return nil, err + } + + return ce.handleAuthTokensResponse(response) +} + +// handleAuthTokensResponse takes care of checking an http.Response that has +// auth tokens for errors and parsing the raw body to a TokenResult struct +func (ce *TokenRetriever) handleAuthTokensResponse(resp *http.Response) (*TokenResult, error) { + if resp.Body != nil { + defer resp.Body.Close() + } + if resp.StatusCode < 200 || resp.StatusCode > 299 { + cth := resp.Header.Get("Content-Type") + if cth == "" { + cth = "application/json" + } + ct, _, err := mime.ParseMediaType(cth) + if err != nil { + return nil, fmt.Errorf("unprocessable content type: %s: %w", cth, err) + } + if ct == "application/json" { + er := TokenErrorResponse{} + err := json.NewDecoder(resp.Body).Decode(&er) + if err != nil { + return nil, err + } + return nil, &TokenError{ErrorCode: er.Error, ErrorDescription: er.ErrorDescription} + } + return nil, fmt.Errorf("a non-success status code was received: %d", resp.StatusCode) + } + + atr := AuthorizationTokenResponse{} + err := json.NewDecoder(resp.Body).Decode(&atr) + if err != nil { + return nil, err + } + + return &TokenResult{ + AccessToken: atr.AccessToken, + IDToken: atr.IDToken, + RefreshToken: atr.RefreshToken, + ExpiresIn: atr.ExpiresIn, + }, nil +} + +// ExchangeDeviceCode uses the DeviceCodeExchangeRequest to exchange a device +// code for tokens +func (ce *TokenRetriever) ExchangeDeviceCode(ctx context.Context, req DeviceCodeExchangeRequest) (*TokenResult, error) { + for { + request, err := ce.newDeviceCodeExchangeRequest(req) + if err != nil { + return nil, err + } + + response, err := ce.transport.Do(request) + if err != nil { + return nil, err + } + token, err := ce.handleAuthTokensResponse(response) + if err == nil { + return token, nil + } + terr, ok := err.(*TokenError) + if !ok { + return nil, err + } + switch terr.ErrorCode { + case "expired_token": + // The user has not authorized the device quickly enough, so the device_code has expired. + return nil, fmt.Errorf("the device code has expired") + case "access_denied": + // The user refused to authorize the device + return nil, fmt.Errorf("the device was not authorized") + case "authorization_pending": + // Still waiting for the user to take action + case "slow_down": + // You are polling too fast + } + + select { + case <-time.After(req.PollInterval): + continue + case <-ctx.Done(): + return nil, errors.New("cancelled") + } + } +} + +// ExchangeRefreshToken uses the RefreshTokenExchangeRequest to exchange a +// refresh token for refreshed tokens +func (ce *TokenRetriever) ExchangeRefreshToken(req RefreshTokenExchangeRequest) (*TokenResult, error) { + request, err := ce.newRefreshTokenRequest(req) + if err != nil { + return nil, err + } + + response, err := ce.transport.Do(request) + if err != nil { + return nil, err + } + + return ce.handleAuthTokensResponse(response) +} + +// ExchangeClientCredentials uses the ClientCredentialsExchangeRequest to exchange +// client credentials for tokens +func (ce *TokenRetriever) ExchangeClientCredentials(req ClientCredentialsExchangeRequest) (*TokenResult, error) { + request, err := ce.newClientCredentialsRequest(req) + if err != nil { + return nil, err + } + + response, err := ce.transport.Do(request) + if err != nil { + return nil, err + } + + return ce.handleAuthTokensResponse(response) +} diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/cache/cache.go b/vendor/github.com/apache/pulsar-client-go/oauth2/cache/cache.go new file mode 100644 index 00000000..b7f89b21 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/cache/cache.go @@ -0,0 +1,142 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package cache + +import ( + "fmt" + "sync" + "time" + + "github.com/apache/pulsar-client-go/oauth2" + "github.com/apache/pulsar-client-go/oauth2/store" + + "github.com/apache/pulsar-client-go/oauth2/clock" + xoauth2 "golang.org/x/oauth2" +) + +// A CachingTokenSource is anything that can return a token, and is backed by a cache. +type CachingTokenSource interface { + xoauth2.TokenSource + + // InvalidateToken is called when the token is rejected by the resource server. + InvalidateToken() error +} + +const ( + // expiryDelta adjusts the token TTL to avoid using tokens which are almost expired + expiryDelta = time.Duration(60) * time.Second +) + +// tokenCache implements a cache for the token associated with a specific audience. +// it interacts with the store when the access token is near expiration or invalidated. +// it is advisable to use a token cache instance per audience. +type tokenCache struct { + clock clock.Clock + lock sync.Mutex + store store.Store + audience string + refresher oauth2.AuthorizationGrantRefresher + token *xoauth2.Token +} + +func NewDefaultTokenCache(store store.Store, audience string, + refresher oauth2.AuthorizationGrantRefresher) (CachingTokenSource, error) { + cache := &tokenCache{ + clock: clock.RealClock{}, + store: store, + audience: audience, + refresher: refresher, + } + return cache, nil +} + +var _ CachingTokenSource = &tokenCache{} + +// Token returns a valid access token, if available. +func (t *tokenCache) Token() (*xoauth2.Token, error) { + t.lock.Lock() + defer t.lock.Unlock() + + // use the cached access token if it isn't expired + if t.token != nil && t.validateAccessToken(*t.token) { + return t.token, nil + } + + // load from the store and use the access token if it isn't expired + grant, err := t.store.LoadGrant(t.audience) + if err != nil { + return nil, fmt.Errorf("LoadGrant: %v", err) + } + t.token = grant.Token + if t.token != nil && t.validateAccessToken(*t.token) { + return t.token, nil + } + + // obtain and cache a fresh access token + grant, err = t.refresher.Refresh(grant) + if err != nil { + return nil, fmt.Errorf("RefreshGrant: %v", err) + } + t.token = grant.Token + err = t.store.SaveGrant(t.audience, *grant) + if err != nil { + // TODO log rather than throw + return nil, fmt.Errorf("SaveGrant: %v", err) + } + + return t.token, nil +} + +// InvalidateToken clears the access token (likely due to a response from the resource server). +// Note that the token within the grant may contain a refresh token which should survive. +func (t *tokenCache) InvalidateToken() error { + t.lock.Lock() + defer t.lock.Unlock() + + previous := t.token + t.token = nil + + // clear from the store the access token that was returned earlier (unless the store has since been updated) + if previous == nil || previous.AccessToken == "" { + return nil + } + grant, err := t.store.LoadGrant(t.audience) + if err != nil { + return fmt.Errorf("LoadGrant: %v", err) + } + if grant.Token != nil && grant.Token.AccessToken == previous.AccessToken { + grant.Token.Expiry = time.Unix(0, 0).Add(expiryDelta) + err = t.store.SaveGrant(t.audience, *grant) + if err != nil { + // TODO log rather than throw + return fmt.Errorf("SaveGrant: %v", err) + } + } + return nil +} + +// validateAccessToken checks the validity of the cached access token +func (t *tokenCache) validateAccessToken(token xoauth2.Token) bool { + if token.AccessToken == "" { + return false + } + if !token.Expiry.IsZero() && t.clock.Now().After(token.Expiry.Round(0).Add(-expiryDelta)) { + return false + } + return true +} diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/client_credentials_flow.go b/vendor/github.com/apache/pulsar-client-go/oauth2/client_credentials_flow.go new file mode 100644 index 00000000..2252144a --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/client_credentials_flow.go @@ -0,0 +1,161 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package oauth2 + +import ( + "net/http" + + "github.com/apache/pulsar-client-go/oauth2/clock" + + "github.com/pkg/errors" +) + +// ClientCredentialsFlow takes care of the mechanics needed for getting an access +// token using the OAuth 2.0 "Client Credentials Flow" +type ClientCredentialsFlow struct { + options ClientCredentialsFlowOptions + oidcWellKnownEndpoints OIDCWellKnownEndpoints + keyfile *KeyFile + exchanger ClientCredentialsExchanger + clock clock.Clock +} + +// ClientCredentialsProvider abstracts getting client credentials +type ClientCredentialsProvider interface { + GetClientCredentials() (*KeyFile, error) +} + +// ClientCredentialsExchanger abstracts exchanging client credentials for tokens +type ClientCredentialsExchanger interface { + ExchangeClientCredentials(req ClientCredentialsExchangeRequest) (*TokenResult, error) +} + +type ClientCredentialsFlowOptions struct { + KeyFile string + AdditionalScopes []string +} + +func newClientCredentialsFlow( + options ClientCredentialsFlowOptions, + keyfile *KeyFile, + oidcWellKnownEndpoints OIDCWellKnownEndpoints, + exchanger ClientCredentialsExchanger, + clock clock.Clock) *ClientCredentialsFlow { + return &ClientCredentialsFlow{ + options: options, + oidcWellKnownEndpoints: oidcWellKnownEndpoints, + keyfile: keyfile, + exchanger: exchanger, + clock: clock, + } +} + +// NewDefaultClientCredentialsFlow provides an easy way to build up a default +// client credentials flow with all the correct configuration. +func NewDefaultClientCredentialsFlow(options ClientCredentialsFlowOptions) (*ClientCredentialsFlow, error) { + + credsProvider := NewClientCredentialsProviderFromKeyFile(options.KeyFile) + keyFile, err := credsProvider.GetClientCredentials() + if err != nil { + return nil, errors.Wrap(err, "could not get client credentials") + } + + wellKnownEndpoints, err := GetOIDCWellKnownEndpointsFromIssuerURL(keyFile.IssuerURL) + if err != nil { + return nil, err + } + + tokenRetriever := NewTokenRetriever(&http.Client{}) + + return newClientCredentialsFlow( + options, + keyFile, + *wellKnownEndpoints, + tokenRetriever, + clock.RealClock{}), nil +} + +var _ Flow = &ClientCredentialsFlow{} + +func (c *ClientCredentialsFlow) Authorize(audience string) (*AuthorizationGrant, error) { + var err error + grant := &AuthorizationGrant{ + Type: GrantTypeClientCredentials, + Audience: audience, + ClientID: c.keyfile.ClientID, + ClientCredentials: c.keyfile, + TokenEndpoint: c.oidcWellKnownEndpoints.TokenEndpoint, + Scopes: c.options.AdditionalScopes, + } + + // test the credentials and obtain an initial access token + refresher := &ClientCredentialsGrantRefresher{ + exchanger: c.exchanger, + clock: c.clock, + } + grant, err = refresher.Refresh(grant) + if err != nil { + return nil, errors.Wrap(err, "authentication failed using client credentials") + } + return grant, nil +} + +type ClientCredentialsGrantRefresher struct { + exchanger ClientCredentialsExchanger + clock clock.Clock +} + +func NewDefaultClientCredentialsGrantRefresher(clock clock.Clock) (*ClientCredentialsGrantRefresher, error) { + tokenRetriever := NewTokenRetriever(&http.Client{}) + return &ClientCredentialsGrantRefresher{ + exchanger: tokenRetriever, + clock: clock, + }, nil +} + +var _ AuthorizationGrantRefresher = &ClientCredentialsGrantRefresher{} + +func (g *ClientCredentialsGrantRefresher) Refresh(grant *AuthorizationGrant) (*AuthorizationGrant, error) { + if grant.Type != GrantTypeClientCredentials { + return nil, errors.New("unsupported grant type") + } + + exchangeRequest := ClientCredentialsExchangeRequest{ + TokenEndpoint: grant.TokenEndpoint, + Audience: grant.Audience, + ClientID: grant.ClientCredentials.ClientID, + ClientSecret: grant.ClientCredentials.ClientSecret, + Scopes: grant.Scopes, + } + tr, err := g.exchanger.ExchangeClientCredentials(exchangeRequest) + if err != nil { + return nil, errors.Wrap(err, "could not exchange client credentials") + } + + token := convertToOAuth2Token(tr, g.clock) + grant = &AuthorizationGrant{ + Type: GrantTypeClientCredentials, + Audience: grant.Audience, + ClientID: grant.ClientID, + ClientCredentials: grant.ClientCredentials, + TokenEndpoint: grant.TokenEndpoint, + Token: &token, + Scopes: grant.Scopes, + } + return grant, nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/client_credentials_provider.go b/vendor/github.com/apache/pulsar-client-go/oauth2/client_credentials_provider.go new file mode 100644 index 00000000..3eb8ba44 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/client_credentials_provider.go @@ -0,0 +1,80 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package oauth2 + +import ( + "encoding/json" + "os" + "strings" +) + +const ( + FILE = "file://" + DATA = "data://" +) + +type KeyFileProvider struct { + KeyFile string +} + +type KeyFile struct { + Type string `json:"type"` + ClientID string `json:"client_id"` + ClientSecret string `json:"client_secret"` + ClientEmail string `json:"client_email"` + IssuerURL string `json:"issuer_url"` +} + +func NewClientCredentialsProviderFromKeyFile(keyFile string) *KeyFileProvider { + return &KeyFileProvider{ + KeyFile: keyFile, + } +} + +var _ ClientCredentialsProvider = &KeyFileProvider{} + +func (k *KeyFileProvider) GetClientCredentials() (*KeyFile, error) { + var keyFile []byte + var err error + switch { + case strings.HasPrefix(k.KeyFile, FILE): + filename := strings.TrimPrefix(k.KeyFile, FILE) + keyFile, err = os.ReadFile(filename) + case strings.HasPrefix(k.KeyFile, DATA): + keyFile = []byte(strings.TrimPrefix(k.KeyFile, DATA)) + case strings.HasPrefix(k.KeyFile, "data:"): + url, err := newDataURL(k.KeyFile) + if err != nil { + return nil, err + } + keyFile = url.Data + default: + keyFile, err = os.ReadFile(k.KeyFile) + } + if err != nil { + return nil, err + } + + var v KeyFile + err = json.Unmarshal(keyFile, &v) + if err != nil { + return nil, err + } + + return &v, nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/clock/clock.go b/vendor/github.com/apache/pulsar-client-go/oauth2/clock/clock.go new file mode 100644 index 00000000..f170d9af --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/clock/clock.go @@ -0,0 +1,98 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package clock + +import "time" + +// Clock allows for injecting fake or real clocks into code that +// needs to do arbitrary things based on time. +type Clock interface { + Now() time.Time + Since(time.Time) time.Duration + After(d time.Duration) <-chan time.Time + NewTimer(d time.Duration) Timer + Sleep(d time.Duration) + Tick(d time.Duration) <-chan time.Time +} + +var _ = Clock(RealClock{}) + +// RealClock really calls time.Now() +type RealClock struct{} + +// Now returns the current time. +func (RealClock) Now() time.Time { + return time.Now() +} + +// Since returns time since the specified timestamp. +func (RealClock) Since(ts time.Time) time.Duration { + return time.Since(ts) +} + +// After is the same as time.After(d). +func (RealClock) After(d time.Duration) <-chan time.Time { + return time.After(d) +} + +// NewTimer is the same as time.NewTimer(d) +func (RealClock) NewTimer(d time.Duration) Timer { + return &realTimer{ + timer: time.NewTimer(d), + } +} + +// Tick is the same as time.Tick(d) +func (RealClock) Tick(d time.Duration) <-chan time.Time { + return time.Tick(d) +} + +// Sleep is the same as time.Sleep(d) +func (RealClock) Sleep(d time.Duration) { + time.Sleep(d) +} + +// Timer allows for injecting fake or real timers into code that +// needs to do arbitrary things based on time. +type Timer interface { + C() <-chan time.Time + Stop() bool + Reset(d time.Duration) bool +} + +var _ = Timer(&realTimer{}) + +// realTimer is backed by an actual time.Timer. +type realTimer struct { + timer *time.Timer +} + +// C returns the underlying timer's channel. +func (r *realTimer) C() <-chan time.Time { + return r.timer.C +} + +// Stop calls Stop() on the underlying timer. +func (r *realTimer) Stop() bool { + return r.timer.Stop() +} + +// Reset calls Reset() on the underlying timer. +func (r *realTimer) Reset(d time.Duration) bool { + return r.timer.Reset(d) +} diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/config_tokenprovider.go b/vendor/github.com/apache/pulsar-client-go/oauth2/config_tokenprovider.go new file mode 100644 index 00000000..627749fb --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/config_tokenprovider.go @@ -0,0 +1,57 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package oauth2 + +import "fmt" + +type configProvider interface { + GetTokens(identifier string) (string, string) + SaveTokens(identifier, accessToken, refreshToken string) +} + +// ConfigBackedCachingProvider wraps a configProvider in order to conform to +// the cachingProvider interface +type ConfigBackedCachingProvider struct { + identifier string + config configProvider +} + +// NewConfigBackedCachingProvider builds and returns a CachingTokenProvider +// that utilizes a configProvider to cache tokens +func NewConfigBackedCachingProvider(clientID, audience string, config configProvider) *ConfigBackedCachingProvider { + return &ConfigBackedCachingProvider{ + identifier: fmt.Sprintf("%s-%s", clientID, audience), + config: config, + } +} + +// GetTokens gets the tokens from the cache and returns them as a TokenResult +func (c *ConfigBackedCachingProvider) GetTokens() (*TokenResult, error) { + accessToken, refreshToken := c.config.GetTokens(c.identifier) + return &TokenResult{ + AccessToken: accessToken, + RefreshToken: refreshToken, + }, nil +} + +// CacheTokens caches the id and refresh token from TokenResult in the +// configProvider +func (c *ConfigBackedCachingProvider) CacheTokens(toCache *TokenResult) error { + c.config.SaveTokens(c.identifier, toCache.AccessToken, toCache.RefreshToken) + return nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/data_url.go b/vendor/github.com/apache/pulsar-client-go/oauth2/data_url.go new file mode 100644 index 00000000..8d711f83 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/data_url.go @@ -0,0 +1,70 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package oauth2 + +import ( + "encoding/base64" + "errors" + "regexp" +) + +var errDataURLInvalid = errors.New("invalid data URL") + +// https://datatracker.ietf.org/doc/html/rfc2397 +var dataURLRegex = regexp.MustCompile("^data:(?P[^;,]+)?(;(?Pcharset=[^;,]+))?" + + "(;(?Pbase64))?,(?P.+)") + +type dataURL struct { + url string + Mimetype string + Data []byte +} + +func newDataURL(url string) (*dataURL, error) { + if !dataURLRegex.Match([]byte(url)) { + return nil, errDataURLInvalid + } + + match := dataURLRegex.FindStringSubmatch(url) + if len(match) != 7 { + return nil, errDataURLInvalid + } + + dataURL := &dataURL{ + url: url, + } + + mimetype := match[dataURLRegex.SubexpIndex("mimetype")] + if mimetype == "" { + mimetype = "text/plain" + } + dataURL.Mimetype = mimetype + + data := match[dataURLRegex.SubexpIndex("data")] + if match[dataURLRegex.SubexpIndex("base64")] == "" { + dataURL.Data = []byte(data) + } else { + data, err := base64.StdEncoding.DecodeString(data) + if err != nil { + return nil, err + } + dataURL.Data = data + } + + return dataURL, nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/device_code_flow.go b/vendor/github.com/apache/pulsar-client-go/oauth2/device_code_flow.go new file mode 100644 index 00000000..d46148a8 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/device_code_flow.go @@ -0,0 +1,205 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package oauth2 + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/apache/pulsar-client-go/oauth2/clock" + + "github.com/pkg/errors" +) + +// DeviceCodeFlow takes care of the mechanics needed for getting an access +// token using the OAuth 2.0 "Device Code Flow" +type DeviceCodeFlow struct { + options DeviceCodeFlowOptions + oidcWellKnownEndpoints OIDCWellKnownEndpoints + codeProvider DeviceCodeProvider + exchanger DeviceTokenExchanger + callback DeviceCodeCallback + clock clock.Clock +} + +// AuthorizationCodeProvider abstracts getting an authorization code +type DeviceCodeProvider interface { + GetCode(audience string, additionalScopes ...string) (*DeviceCodeResult, error) +} + +// DeviceTokenExchanger abstracts exchanging for tokens +type DeviceTokenExchanger interface { + ExchangeDeviceCode(ctx context.Context, req DeviceCodeExchangeRequest) (*TokenResult, error) + ExchangeRefreshToken(req RefreshTokenExchangeRequest) (*TokenResult, error) +} + +type DeviceCodeCallback func(code *DeviceCodeResult) error + +type DeviceCodeFlowOptions struct { + IssuerEndpoint string + ClientID string + AdditionalScopes []string + AllowRefresh bool +} + +func newDeviceCodeFlow( + options DeviceCodeFlowOptions, + oidcWellKnownEndpoints OIDCWellKnownEndpoints, + codeProvider DeviceCodeProvider, + exchanger DeviceTokenExchanger, + callback DeviceCodeCallback, + clock clock.Clock) *DeviceCodeFlow { + return &DeviceCodeFlow{ + options: options, + oidcWellKnownEndpoints: oidcWellKnownEndpoints, + codeProvider: codeProvider, + exchanger: exchanger, + callback: callback, + clock: clock, + } +} + +// NewDefaultDeviceCodeFlow provides an easy way to build up a default +// device code flow with all the correct configuration. If refresh tokens should +// be allowed pass in true for +func NewDefaultDeviceCodeFlow(options DeviceCodeFlowOptions, + callback DeviceCodeCallback) (*DeviceCodeFlow, error) { + wellKnownEndpoints, err := GetOIDCWellKnownEndpointsFromIssuerURL(options.IssuerEndpoint) + if err != nil { + return nil, err + } + + codeProvider := NewLocalDeviceCodeProvider( + LocalDeviceCodeProviderOptions{ + ClientID: options.ClientID, + }, + *wellKnownEndpoints, + &http.Client{}, + ) + + tokenRetriever := NewTokenRetriever(&http.Client{}) + + return newDeviceCodeFlow( + options, + *wellKnownEndpoints, + codeProvider, + tokenRetriever, + callback, + clock.RealClock{}), nil +} + +var _ Flow = &DeviceCodeFlow{} + +func (p *DeviceCodeFlow) Authorize(audience string) (*AuthorizationGrant, error) { + + var additionalScopes []string + additionalScopes = append(additionalScopes, p.options.AdditionalScopes...) + if p.options.AllowRefresh { + additionalScopes = append(additionalScopes, "offline_access") + } + + codeResult, err := p.codeProvider.GetCode(audience, additionalScopes...) + if err != nil { + return nil, err + } + + if p.callback != nil { + err := p.callback(codeResult) + if err != nil { + return nil, err + } + } + + exchangeRequest := DeviceCodeExchangeRequest{ + TokenEndpoint: p.oidcWellKnownEndpoints.TokenEndpoint, + ClientID: p.options.ClientID, + DeviceCode: codeResult.DeviceCode, + PollInterval: time.Duration(codeResult.Interval) * time.Second, + } + + tr, err := p.exchanger.ExchangeDeviceCode(context.Background(), exchangeRequest) + if err != nil { + return nil, errors.Wrap(err, "could not exchange code") + } + + token := convertToOAuth2Token(tr, p.clock) + grant := &AuthorizationGrant{ + Type: GrantTypeDeviceCode, + Audience: audience, + ClientID: p.options.ClientID, + TokenEndpoint: p.oidcWellKnownEndpoints.TokenEndpoint, + Token: &token, + Scopes: additionalScopes, + } + return grant, nil +} + +type DeviceAuthorizationGrantRefresher struct { + exchanger DeviceTokenExchanger + clock clock.Clock +} + +// NewDefaultDeviceAuthorizationGrantRefresher constructs a grant refresher based on the result +// of the device authorization flow. +func NewDefaultDeviceAuthorizationGrantRefresher(clock clock.Clock) (*DeviceAuthorizationGrantRefresher, error) { + tokenRetriever := NewTokenRetriever(&http.Client{}) + return &DeviceAuthorizationGrantRefresher{ + exchanger: tokenRetriever, + clock: clock, + }, nil +} + +var _ AuthorizationGrantRefresher = &DeviceAuthorizationGrantRefresher{} + +func (g *DeviceAuthorizationGrantRefresher) Refresh(grant *AuthorizationGrant) (*AuthorizationGrant, error) { + if grant.Type != GrantTypeDeviceCode { + return nil, errors.New("unsupported grant type") + } + if grant.Token == nil || grant.Token.RefreshToken == "" { + return nil, fmt.Errorf("the authorization grant has expired (no refresh token); please re-login") + } + + exchangeRequest := RefreshTokenExchangeRequest{ + TokenEndpoint: grant.TokenEndpoint, + ClientID: grant.ClientID, + RefreshToken: grant.Token.RefreshToken, + } + tr, err := g.exchanger.ExchangeRefreshToken(exchangeRequest) + if err != nil { + return nil, errors.Wrap(err, "could not exchange refresh token") + } + + // RFC 6749 Section 1.5 - token exchange MAY issue a new refresh token (otherwise the result is blank). + // also see: https://tools.ietf.org/html/draft-ietf-oauth-security-topics-13#section-4.12 + if tr.RefreshToken == "" { + tr.RefreshToken = grant.Token.RefreshToken + } + + token := convertToOAuth2Token(tr, g.clock) + grant = &AuthorizationGrant{ + Type: GrantTypeDeviceCode, + Audience: grant.Audience, + ClientID: grant.ClientID, + Token: &token, + TokenEndpoint: grant.TokenEndpoint, + Scopes: grant.Scopes, + } + return grant, nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/device_code_provider.go b/vendor/github.com/apache/pulsar-client-go/oauth2/device_code_provider.go new file mode 100644 index 00000000..77e1eb90 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/device_code_provider.go @@ -0,0 +1,137 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package oauth2 + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + "strconv" + "strings" +) + +// DeviceCodeProvider holds the information needed to easily get a +// device code locally. +type LocalDeviceCodeProvider struct { + options LocalDeviceCodeProviderOptions + oidcWellKnownEndpoints OIDCWellKnownEndpoints + transport HTTPAuthTransport +} + +type DeviceCodeRequest struct { + ClientID string + Scopes []string + Audience string +} + +// DeviceCodeResult holds the device code gotten from the device code URL. +type DeviceCodeResult struct { + DeviceCode string `json:"device_code"` + UserCode string `json:"user_code"` + VerificationURI string `json:"verification_uri"` + VerificationURIComplete string `json:"verification_uri_complete"` + ExpiresIn int `json:"expires_in"` + Interval int `json:"interval"` +} + +type LocalDeviceCodeProviderOptions struct { + ClientID string +} + +// NewLocalDeviceCodeProvider allows for the easy setup of LocalDeviceCodeProvider +func NewLocalDeviceCodeProvider( + options LocalDeviceCodeProviderOptions, + oidcWellKnownEndpoints OIDCWellKnownEndpoints, + authTransport HTTPAuthTransport) *LocalDeviceCodeProvider { + return &LocalDeviceCodeProvider{ + options, + oidcWellKnownEndpoints, + authTransport, + } +} + +// GetCode obtains a new device code. Additional scopes +// beyond openid and email can be sent by passing in arguments for +// . +func (cp *LocalDeviceCodeProvider) GetCode(audience string, additionalScopes ...string) (*DeviceCodeResult, error) { + request, err := cp.newDeviceCodeRequest(&DeviceCodeRequest{ + ClientID: cp.options.ClientID, + Scopes: append([]string{"openid", "email"}, additionalScopes...), + Audience: audience, + }) + if err != nil { + return nil, err + } + + response, err := cp.transport.Do(request) + if err != nil { + return nil, err + } + + dcr, err := cp.handleDeviceCodeResponse(response) + if err != nil { + return nil, err + } + + return dcr, nil +} + +// newDeviceCodeRequest builds a new DeviceCodeRequest wrapped in an +// http.Request +func (cp *LocalDeviceCodeProvider) newDeviceCodeRequest( + req *DeviceCodeRequest) (*http.Request, error) { + uv := url.Values{} + uv.Set("client_id", req.ClientID) + if len(req.Scopes) > 0 { + uv.Set("scope", strings.Join(req.Scopes, " ")) + } + if req.Audience != "" { + uv.Set("audience", req.Audience) + } + euv := uv.Encode() + + request, err := http.NewRequest("POST", + cp.oidcWellKnownEndpoints.DeviceAuthorizationEndpoint, + strings.NewReader(euv), + ) + if err != nil { + return nil, err + } + + request.Header.Add("Content-Type", "application/x-www-form-urlencoded") + request.Header.Add("Content-Length", strconv.Itoa(len(euv))) + + return request, nil +} + +func (cp *LocalDeviceCodeProvider) handleDeviceCodeResponse(resp *http.Response) (*DeviceCodeResult, error) { + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return nil, fmt.Errorf("a non-success status code was received: %d", resp.StatusCode) + } + + defer resp.Body.Close() + + dcr := DeviceCodeResult{} + err := json.NewDecoder(resp.Body).Decode(&dcr) + if err != nil { + return nil, err + } + + return &dcr, nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/oidc_endpoint_provider.go b/vendor/github.com/apache/pulsar-client-go/oauth2/oidc_endpoint_provider.go new file mode 100644 index 00000000..32986b73 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/oidc_endpoint_provider.go @@ -0,0 +1,58 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package oauth2 + +import ( + "encoding/json" + "net/http" + "net/url" + "path" + + "github.com/pkg/errors" +) + +// OIDCWellKnownEndpoints holds the well known OIDC endpoints +type OIDCWellKnownEndpoints struct { + AuthorizationEndpoint string `json:"authorization_endpoint"` + TokenEndpoint string `json:"token_endpoint"` + DeviceAuthorizationEndpoint string `json:"device_authorization_endpoint"` +} + +// GetOIDCWellKnownEndpointsFromIssuerURL gets the well known endpoints for the +// passed in issuer url +func GetOIDCWellKnownEndpointsFromIssuerURL(issuerURL string) (*OIDCWellKnownEndpoints, error) { + u, err := url.Parse(issuerURL) + if err != nil { + return nil, errors.Wrap(err, "could not parse issuer url to build well known endpoints") + } + u.Path = path.Join(u.Path, ".well-known/openid-configuration") + + r, err := http.Get(u.String()) + if err != nil { + return nil, errors.Wrapf(err, "could not get well known endpoints from url %s", u.String()) + } + defer r.Body.Close() + + var wkEndpoints OIDCWellKnownEndpoints + err = json.NewDecoder(r.Body).Decode(&wkEndpoints) + if err != nil { + return nil, errors.Wrap(err, "could not decode json body when getting well known endpoints") + } + + return &wkEndpoints, nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/store/keyring.go b/vendor/github.com/apache/pulsar-client-go/oauth2/store/keyring.go new file mode 100644 index 00000000..8a024f59 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/store/keyring.go @@ -0,0 +1,194 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package store + +import ( + "crypto/sha1" + "encoding/json" + "fmt" + "sync" + + "github.com/99designs/keyring" + "github.com/apache/pulsar-client-go/oauth2" + "github.com/apache/pulsar-client-go/oauth2/clock" +) + +type KeyringStore struct { + kr keyring.Keyring + clock clock.Clock + lock sync.Mutex +} + +// storedItem represents an item stored in the keyring +type storedItem struct { + Audience string + UserName string + Grant oauth2.AuthorizationGrant +} + +// NewKeyringStore creates a store based on a keyring. +func NewKeyringStore(kr keyring.Keyring) (*KeyringStore, error) { + return &KeyringStore{ + kr: kr, + clock: clock.RealClock{}, + }, nil +} + +var _ Store = &KeyringStore{} + +func (f *KeyringStore) SaveGrant(audience string, grant oauth2.AuthorizationGrant) error { + f.lock.Lock() + defer f.lock.Unlock() + + var err error + var userName string + switch grant.Type { + case oauth2.GrantTypeClientCredentials: + if grant.ClientCredentials == nil { + return ErrUnsupportedAuthData + } + userName = grant.ClientCredentials.ClientEmail + case oauth2.GrantTypeDeviceCode: + if grant.Token == nil { + return ErrUnsupportedAuthData + } + userName, err = oauth2.ExtractUserName(*grant.Token) + if err != nil { + return err + } + default: + return ErrUnsupportedAuthData + } + item := storedItem{ + Audience: audience, + UserName: userName, + Grant: grant, + } + err = f.setItem(item) + if err != nil { + return err + } + return nil +} + +func (f *KeyringStore) LoadGrant(audience string) (*oauth2.AuthorizationGrant, error) { + f.lock.Lock() + defer f.lock.Unlock() + + item, err := f.getItem(audience) + if err != nil { + if err == keyring.ErrKeyNotFound { + return nil, ErrNoAuthenticationData + } + return nil, err + } + switch item.Grant.Type { + case oauth2.GrantTypeClientCredentials: + if item.Grant.ClientCredentials == nil { + return nil, ErrUnsupportedAuthData + } + case oauth2.GrantTypeDeviceCode: + if item.Grant.Token == nil { + return nil, ErrUnsupportedAuthData + } + default: + return nil, ErrUnsupportedAuthData + } + return &item.Grant, nil +} + +func (f *KeyringStore) WhoAmI(audience string) (string, error) { + f.lock.Lock() + defer f.lock.Unlock() + + key := hashKeyringKey(audience) + authItem, err := f.kr.Get(key) + if err != nil { + if err == keyring.ErrKeyNotFound { + return "", ErrNoAuthenticationData + } + return "", fmt.Errorf("unable to get information from the keyring: %v", err) + } + return authItem.Label, nil +} + +func (f *KeyringStore) Logout() error { + f.lock.Lock() + defer f.lock.Unlock() + + var err error + keys, err := f.kr.Keys() + if err != nil { + return fmt.Errorf("unable to get information from the keyring: %v", err) + } + for _, key := range keys { + err = f.kr.Remove(key) + } + if err != nil { + return fmt.Errorf("unable to update the keyring: %v", err) + } + return nil +} + +func (f *KeyringStore) getItem(audience string) (storedItem, error) { + key := hashKeyringKey(audience) + i, err := f.kr.Get(key) + if err != nil { + return storedItem{}, err + } + var grant oauth2.AuthorizationGrant + err = json.Unmarshal(i.Data, &grant) + if err != nil { + // the grant appears to be invalid + return storedItem{}, ErrUnsupportedAuthData + } + return storedItem{ + Audience: audience, + UserName: i.Label, + Grant: grant, + }, nil +} + +func (f *KeyringStore) setItem(item storedItem) error { + key := hashKeyringKey(item.Audience) + data, err := json.Marshal(item.Grant) + if err != nil { + return err + } + i := keyring.Item{ + Key: key, + Data: data, + Label: item.UserName, + Description: "authorization grant", + KeychainNotTrustApplication: false, + KeychainNotSynchronizable: false, + } + err = f.kr.Set(i) + if err != nil { + return fmt.Errorf("unable to update the keyring: %v", err) + } + return nil +} + +// hashKeyringKey creates a safe key based on the given string +func hashKeyringKey(s string) string { + h := sha1.New() + h.Write([]byte(s)) + bs := h.Sum(nil) + return fmt.Sprintf("%x", bs) +} diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/store/memory.go b/vendor/github.com/apache/pulsar-client-go/oauth2/store/memory.go new file mode 100644 index 00000000..07c75947 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/store/memory.go @@ -0,0 +1,87 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package store + +import ( + "sync" + + "github.com/apache/pulsar-client-go/oauth2" + "github.com/apache/pulsar-client-go/oauth2/clock" +) + +type MemoryStore struct { + clock clock.Clock + lock sync.Mutex + grants map[string]*oauth2.AuthorizationGrant +} + +func NewMemoryStore() Store { + return &MemoryStore{ + clock: clock.RealClock{}, + grants: make(map[string]*oauth2.AuthorizationGrant), + } +} + +var _ Store = &MemoryStore{} + +func (f *MemoryStore) SaveGrant(audience string, grant oauth2.AuthorizationGrant) error { + f.lock.Lock() + defer f.lock.Unlock() + f.grants[audience] = &grant + return nil +} + +func (f *MemoryStore) LoadGrant(audience string) (*oauth2.AuthorizationGrant, error) { + f.lock.Lock() + defer f.lock.Unlock() + grant, ok := f.grants[audience] + if !ok { + return nil, ErrNoAuthenticationData + } + return grant, nil +} + +func (f *MemoryStore) WhoAmI(audience string) (string, error) { + f.lock.Lock() + defer f.lock.Unlock() + grant, ok := f.grants[audience] + if !ok { + return "", ErrNoAuthenticationData + } + switch grant.Type { + case oauth2.GrantTypeClientCredentials: + if grant.ClientCredentials == nil { + return "", ErrUnsupportedAuthData + } + return grant.ClientCredentials.ClientEmail, nil + case oauth2.GrantTypeDeviceCode: + if grant.Token == nil { + return "", ErrUnsupportedAuthData + } + return oauth2.ExtractUserName(*grant.Token) + default: + return "", ErrUnsupportedAuthData + } +} + +func (f *MemoryStore) Logout() error { + f.lock.Lock() + defer f.lock.Unlock() + f.grants = map[string]*oauth2.AuthorizationGrant{} + return nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/oauth2/store/store.go b/vendor/github.com/apache/pulsar-client-go/oauth2/store/store.go new file mode 100644 index 00000000..55d4c9ec --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/oauth2/store/store.go @@ -0,0 +1,45 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package store + +import ( + "errors" + + "github.com/apache/pulsar-client-go/oauth2" +) + +// ErrNoAuthenticationData indicates that stored authentication data is not available +var ErrNoAuthenticationData = errors.New("authentication data is not available") + +// ErrUnsupportedAuthData ndicates that stored authentication data is unusable +var ErrUnsupportedAuthData = errors.New("authentication data is not usable") + +// Store is responsible for persisting authorization grants +type Store interface { + // SaveGrant stores an authorization grant for a given audience + SaveGrant(audience string, grant oauth2.AuthorizationGrant) error + + // LoadGrant loads an authorization grant for a given audience + LoadGrant(audience string) (*oauth2.AuthorizationGrant, error) + + // WhoAmI returns the current user name (or an error if nobody is logged in) + WhoAmI(audience string) (string, error) + + // Logout deletes all stored credentials + Logout() error +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/ack_grouping_tracker.go b/vendor/github.com/apache/pulsar-client-go/pulsar/ack_grouping_tracker.go new file mode 100644 index 00000000..dd051868 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/ack_grouping_tracker.go @@ -0,0 +1,266 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "sync" + "sync/atomic" + "time" + + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "github.com/bits-and-blooms/bitset" +) + +type ackGroupingTracker interface { + add(id MessageID) + + addCumulative(id MessageID) + + isDuplicate(id MessageID) bool + + flush() + + flushAndClean() + + close() +} + +func newAckGroupingTracker(options *AckGroupingOptions, + ackIndividual func(id MessageID), + ackCumulative func(id MessageID), + ackList func(ids []*pb.MessageIdData)) ackGroupingTracker { + if options == nil { + options = &AckGroupingOptions{ + MaxSize: 1000, + MaxTime: 100 * time.Millisecond, + } + } + + if options.MaxSize <= 1 { + return &immediateAckGroupingTracker{ + ackIndividual: ackIndividual, + ackCumulative: ackCumulative, + } + } + + t := &timedAckGroupingTracker{ + maxNumAcks: int(options.MaxSize), + ackCumulative: ackCumulative, + ackList: ackList, + pendingAcks: make(map[[2]uint64]*bitset.BitSet), + lastCumulativeAck: EarliestMessageID(), + } + + if options.MaxTime > 0 { + t.ticker = time.NewTicker(options.MaxTime) + t.exitCh = make(chan struct{}) + go func() { + for { + select { + case <-t.exitCh: + return + case <-t.ticker.C: + t.flush() + } + } + }() + } + + return t +} + +type immediateAckGroupingTracker struct { + ackIndividual func(id MessageID) + ackCumulative func(id MessageID) +} + +func (i *immediateAckGroupingTracker) add(id MessageID) { + i.ackIndividual(id) +} + +func (i *immediateAckGroupingTracker) addCumulative(id MessageID) { + i.ackCumulative(id) +} + +func (i *immediateAckGroupingTracker) isDuplicate(id MessageID) bool { + return false +} + +func (i *immediateAckGroupingTracker) flush() { +} + +func (i *immediateAckGroupingTracker) flushAndClean() { +} + +func (i *immediateAckGroupingTracker) close() { +} + +type timedAckGroupingTracker struct { + sync.RWMutex + + maxNumAcks int + ackCumulative func(id MessageID) + ackList func(ids []*pb.MessageIdData) + ticker *time.Ticker + + // Key is the pair of the ledger id and the entry id, + // Value is the bit set that represents which messages are acknowledged if the entry stores a batch. + // The bit 1 represents the message has been acknowledged, i.e. the bits "111" represents all messages + // in the batch whose batch size is 3 are not acknowledged. + // After the 1st message (i.e. batch index is 0) is acknowledged, the bits will become "011". + // Value is nil if the entry represents a single message. + pendingAcks map[[2]uint64]*bitset.BitSet + + lastCumulativeAck MessageID + cumulativeAckRequired int32 + + exitCh chan struct{} +} + +func (t *timedAckGroupingTracker) add(id MessageID) { + if acks := t.tryAddIndividual(id); acks != nil { + t.flushIndividual(acks) + } +} + +func (t *timedAckGroupingTracker) tryAddIndividual(id MessageID) map[[2]uint64]*bitset.BitSet { + t.Lock() + defer t.Unlock() + key := [2]uint64{uint64(id.LedgerID()), uint64(id.EntryID())} + + batchIdx := id.BatchIdx() + batchSize := id.BatchSize() + + if batchIdx >= 0 && batchSize > 0 { + bs, found := t.pendingAcks[key] + if !found { + if batchSize > 1 { + bs = bitset.New(uint(batchSize)) + for i := uint(0); i < uint(batchSize); i++ { + bs.Set(i) + } + } + t.pendingAcks[key] = bs + } + if bs != nil { + bs.Clear(uint(batchIdx)) + } + } else { + t.pendingAcks[key] = nil + } + + if len(t.pendingAcks) >= t.maxNumAcks { + pendingAcks := t.pendingAcks + t.pendingAcks = make(map[[2]uint64]*bitset.BitSet) + return pendingAcks + } + return nil +} + +func (t *timedAckGroupingTracker) addCumulative(id MessageID) { + if t.tryUpdateCumulative(id) && t.ticker == nil { + t.ackCumulative(id) + } +} + +func (t *timedAckGroupingTracker) tryUpdateCumulative(id MessageID) bool { + t.Lock() + defer t.Unlock() + if messageIDCompare(t.lastCumulativeAck, id) < 0 { + t.lastCumulativeAck = id + atomic.StoreInt32(&t.cumulativeAckRequired, 1) + return true + } + return false +} + +func (t *timedAckGroupingTracker) isDuplicate(id MessageID) bool { + t.RLock() + defer t.RUnlock() + if messageIDCompare(t.lastCumulativeAck, id) >= 0 { + return true + } + key := [2]uint64{uint64(id.LedgerID()), uint64(id.EntryID())} + if bs, found := t.pendingAcks[key]; found { + if bs == nil { + return true + } + if !bs.Test(uint(id.BatchIdx())) { + return true + } + } + return false +} + +func (t *timedAckGroupingTracker) flush() { + if acks := t.clearPendingAcks(); len(acks) > 0 { + t.flushIndividual(acks) + } + if atomic.CompareAndSwapInt32(&t.cumulativeAckRequired, 1, 0) { + t.RLock() + id := t.lastCumulativeAck + t.RUnlock() + t.ackCumulative(id) + } +} + +func (t *timedAckGroupingTracker) flushAndClean() { + if acks := t.clearPendingAcks(); len(acks) > 0 { + t.flushIndividual(acks) + } + if atomic.CompareAndSwapInt32(&t.cumulativeAckRequired, 1, 0) { + t.Lock() + id := t.lastCumulativeAck + t.lastCumulativeAck = EarliestMessageID() + t.Unlock() + t.ackCumulative(id) + } +} + +func (t *timedAckGroupingTracker) clearPendingAcks() map[[2]uint64]*bitset.BitSet { + t.Lock() + defer t.Unlock() + pendingAcks := t.pendingAcks + t.pendingAcks = make(map[[2]uint64]*bitset.BitSet) + return pendingAcks +} + +func (t *timedAckGroupingTracker) close() { + t.flushAndClean() + if t.exitCh != nil { + close(t.exitCh) + } +} + +func (t *timedAckGroupingTracker) flushIndividual(pendingAcks map[[2]uint64]*bitset.BitSet) { + msgIDs := make([]*pb.MessageIdData, 0, len(pendingAcks)) + for k, v := range pendingAcks { + ledgerID := k[0] + entryID := k[1] + msgID := &pb.MessageIdData{LedgerId: &ledgerID, EntryId: &entryID} + if v != nil && !v.None() { + bytes := v.Bytes() + msgID.AckSet = make([]int64, len(bytes)) + for i := 0; i < len(bytes); i++ { + msgID.AckSet[i] = int64(bytes[i]) + } + } + msgIDs = append(msgIDs, msgID) + } + t.ackList(msgIDs) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/auth/athenz.go b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/athenz.go new file mode 100644 index 00000000..35b3cc4e --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/athenz.go @@ -0,0 +1,268 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package auth + +import ( + "crypto/tls" + "encoding/base64" + "errors" + "net/http" + "os" + "regexp" + "strings" + "time" + + zms "github.com/AthenZ/athenz/libs/go/zmssvctoken" + zts "github.com/AthenZ/athenz/libs/go/ztsroletoken" +) + +const ( + minExpire = 2 * time.Hour + maxExpire = 24 * time.Hour + defaultKeyID = "0" + defaultRoleHeader = "Athenz-Role-Auth" +) + +type athenzAuthProvider struct { + providerDomain string + tenantDomain string + tenantService string + privateKey string + keyID string + x509CertChain string + caCert string + principalHeader string + roleHeader string + ztsURL string + tokenBuilder zms.TokenBuilder + roleToken zts.RoleToken + zmsNewTokenBuilder func(domain, name string, privateKeyPEM []byte, keyVersion string) (zms.TokenBuilder, error) + ztsNewRoleToken func(tok zms.Token, domain string, opts zts.RoleTokenOptions) zts.RoleToken + ztsNewRoleTokenFromCert func(certFile, keyFile, domain string, opts zts.RoleTokenOptions) zts.RoleToken + + T http.RoundTripper +} + +type parsedURI struct { + Scheme string + MediaTypeAndEncodingType string + Data string + Path string +} + +func NewAuthenticationAthenzWithParams(params map[string]string) (Provider, error) { + return NewAuthenticationAthenz( + params["providerDomain"], + params["tenantDomain"], + params["tenantService"], + params["privateKey"], + params["keyId"], + params["x509CertChain"], + params["caCert"], + params["principalHeader"], + params["roleHeader"], + params["ztsUrl"], + ), nil +} + +func NewAuthenticationAthenz( + providerDomain string, + tenantDomain string, + tenantService string, + privateKey string, + keyID string, + x509CertChain string, + caCert string, + principalHeader string, + roleHeader string, + ztsURL string) Provider { + fixedKeyID := defaultKeyID + if keyID != "" { + fixedKeyID = keyID + } + + fixedRoleHeader := defaultRoleHeader + if roleHeader != "" { + fixedRoleHeader = roleHeader + } + + ztsNewRoleToken := func(tok zms.Token, domain string, opts zts.RoleTokenOptions) zts.RoleToken { + return zts.RoleToken(zts.NewRoleToken(tok, domain, opts)) + } + + ztsNewRoleTokenFromCert := func(certFile, keyFile, domain string, opts zts.RoleTokenOptions) zts.RoleToken { + return zts.RoleToken(zts.NewRoleTokenFromCert(certFile, keyFile, domain, opts)) + } + + return &athenzAuthProvider{ + providerDomain: providerDomain, + tenantDomain: tenantDomain, + tenantService: tenantService, + privateKey: privateKey, + keyID: fixedKeyID, + x509CertChain: x509CertChain, + caCert: caCert, + principalHeader: principalHeader, + roleHeader: fixedRoleHeader, + ztsURL: strings.TrimSuffix(ztsURL, "/"), + zmsNewTokenBuilder: zms.NewTokenBuilder, + ztsNewRoleToken: ztsNewRoleToken, + ztsNewRoleTokenFromCert: ztsNewRoleTokenFromCert, + } +} + +func (p *athenzAuthProvider) Init() error { + if p.providerDomain == "" || p.privateKey == "" || p.ztsURL == "" { + return errors.New("missing required parameters") + } + + var roleToken zts.RoleToken + opts := zts.RoleTokenOptions{ + BaseZTSURL: p.ztsURL + "/zts/v1", + MinExpire: minExpire, + MaxExpire: maxExpire, + AuthHeader: p.principalHeader, + } + + if p.x509CertChain != "" { + // use Copper Argos + certURISt := parseURI(p.x509CertChain) + keyURISt := parseURI(p.privateKey) + + if certURISt.Scheme != "file" || keyURISt.Scheme != "file" { + return errors.New("x509CertChain and privateKey must be specified as file paths") + } + + if p.caCert != "" { + caCertData, err := loadPEM(p.caCert) + if err != nil { + return err + } + opts.CACert = caCertData + } + + roleToken = p.ztsNewRoleTokenFromCert(certURISt.Path, keyURISt.Path, p.providerDomain, opts) + } else { + if p.tenantDomain == "" || p.tenantService == "" { + return errors.New("missing required parameters") + } + + keyData, err := loadPEM(p.privateKey) + if err != nil { + return err + } + + tb, err := p.zmsNewTokenBuilder(p.tenantDomain, p.tenantService, keyData, p.keyID) + if err != nil { + return err + } + p.tokenBuilder = tb + + roleToken = p.ztsNewRoleToken(p.tokenBuilder.Token(), p.providerDomain, opts) + } + + p.roleToken = roleToken + return nil +} + +func (p *athenzAuthProvider) Name() string { + return "athenz" +} + +func (p *athenzAuthProvider) GetTLSCertificate() (*tls.Certificate, error) { + return nil, nil +} + +func (p *athenzAuthProvider) GetData() ([]byte, error) { + tok, err := p.roleToken.RoleTokenValue() + if err != nil { + return nil, err + } + + return []byte(tok), nil +} + +func (p *athenzAuthProvider) Close() error { + return nil +} + +func parseURI(uri string) parsedURI { + var uriSt parsedURI + // scheme mediatype[;base64] path file + const expression = `^(?:([^:/?#]+):)(?:([;/\\\-\w]*),)?(?:/{0,2}((?:[^?#/]*/)*))?([^?#]*)` + + // when expression cannot be parsed, then panics + re := regexp.MustCompile(expression) + if re.MatchString(uri) { + groups := re.FindStringSubmatch(uri) + uriSt.Scheme = groups[1] + uriSt.MediaTypeAndEncodingType = groups[2] + uriSt.Data = groups[4] + uriSt.Path = groups[3] + groups[4] + } else { + // consider a file path specified instead of a URI + uriSt.Scheme = "file" + uriSt.Path = uri + } + + return uriSt +} + +func loadPEM(uri string) ([]byte, error) { + uriSt := parseURI(uri) + var pemData []byte + + if uriSt.Scheme == "data" { + if uriSt.MediaTypeAndEncodingType != "application/x-pem-file;base64" { + return nil, errors.New("Unsupported mediaType or encodingType: " + uriSt.MediaTypeAndEncodingType) + } + pem, err := base64.StdEncoding.DecodeString(uriSt.Data) + if err != nil { + return nil, err + } + pemData = pem + } else if uriSt.Scheme == "file" { + pem, err := os.ReadFile(uriSt.Path) + if err != nil { + return nil, err + } + pemData = pem + } else { + return nil, errors.New("Unsupported URI Scheme: " + uriSt.Scheme) + } + + return pemData, nil +} + +func (p *athenzAuthProvider) RoundTrip(req *http.Request) (*http.Response, error) { + tok, err := p.roleToken.RoleTokenValue() + if err != nil { + return nil, err + } + req.Header.Add(p.roleHeader, tok) + return p.T.RoundTrip(req) +} + +func (p *athenzAuthProvider) Transport() http.RoundTripper { + return p.T +} + +func (p *athenzAuthProvider) WithTransport(tripper http.RoundTripper) error { + p.T = tripper + return nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/auth/basic.go b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/basic.go new file mode 100644 index 00000000..58a87f51 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/basic.go @@ -0,0 +1,84 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package auth + +import ( + "crypto/tls" + "encoding/base64" + "errors" + "net/http" +) + +type basicAuthProvider struct { + rt http.RoundTripper + commandAuthToken []byte + httpAuthToken string +} + +func NewAuthenticationBasic(username, password string) (Provider, error) { + if username == "" { + return nil, errors.New("username cannot be empty") + } + if password == "" { + return nil, errors.New("password cannot be empty") + } + + commandAuthToken := []byte(username + ":" + password) + return &basicAuthProvider{ + commandAuthToken: commandAuthToken, + httpAuthToken: "Basic " + base64.StdEncoding.EncodeToString(commandAuthToken), + }, nil +} + +func NewAuthenticationBasicWithParams(params map[string]string) (Provider, error) { + return NewAuthenticationBasic(params["username"], params["password"]) +} + +func (b *basicAuthProvider) Init() error { + return nil +} + +func (b *basicAuthProvider) Name() string { + return "basic" +} + +func (b *basicAuthProvider) GetTLSCertificate() (*tls.Certificate, error) { + return nil, nil +} + +func (b *basicAuthProvider) GetData() ([]byte, error) { + return b.commandAuthToken, nil +} + +func (b *basicAuthProvider) Close() error { + return nil +} + +func (b *basicAuthProvider) RoundTrip(req *http.Request) (*http.Response, error) { + req.Header.Add("Authorization", b.httpAuthToken) + return b.rt.RoundTrip(req) +} + +func (b *basicAuthProvider) Transport() http.RoundTripper { + return b.rt +} + +func (b *basicAuthProvider) WithTransport(tr http.RoundTripper) error { + b.rt = tr + return nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/auth/disabled.go b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/disabled.go new file mode 100644 index 00000000..0389a39b --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/disabled.go @@ -0,0 +1,62 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package auth + +import ( + "crypto/tls" + "net/http" +) + +type disabled struct{} + +// NewAuthDisabled return a interface of Provider +func NewAuthDisabled() Provider { + return &disabled{} +} + +func (disabled) Init() error { + return nil +} + +func (disabled) GetData() ([]byte, error) { + return nil, nil +} + +func (disabled) Name() string { + return "" +} + +func (disabled) GetTLSCertificate() (*tls.Certificate, error) { + return nil, nil +} + +func (disabled) Close() error { + return nil +} + +func (d disabled) RoundTrip(req *http.Request) (*http.Response, error) { + return nil, nil +} + +func (d disabled) Transport() http.RoundTripper { + return nil +} + +func (d disabled) WithTransport(tripper http.RoundTripper) error { + return nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/auth/oauth2.go b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/oauth2.go new file mode 100644 index 00000000..e162e4ed --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/oauth2.go @@ -0,0 +1,205 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package auth + +import ( + "crypto/tls" + "fmt" + "net/http" + "strings" + + xoauth2 "golang.org/x/oauth2" + + "github.com/apache/pulsar-client-go/oauth2" + "github.com/apache/pulsar-client-go/oauth2/cache" + "github.com/apache/pulsar-client-go/oauth2/clock" + "github.com/apache/pulsar-client-go/oauth2/store" +) + +const ( + ConfigParamType = "type" + ConfigParamTypeClientCredentials = "client_credentials" + ConfigParamIssuerURL = "issuerUrl" + ConfigParamAudience = "audience" + ConfigParamScope = "scope" + ConfigParamKeyFile = "privateKey" + ConfigParamClientID = "clientId" +) + +type oauth2AuthProvider struct { + clock clock.Clock + issuer oauth2.Issuer + store store.Store + source cache.CachingTokenSource + defaultTransport http.RoundTripper + tokenTransport *transport +} + +// NewAuthenticationOAuth2WithParams return a interface of Provider with string map. +func NewAuthenticationOAuth2WithParams(params map[string]string) (Provider, error) { + issuer := oauth2.Issuer{ + IssuerEndpoint: params[ConfigParamIssuerURL], + ClientID: params[ConfigParamClientID], + Audience: params[ConfigParamAudience], + } + + // initialize a store of authorization grants + st := store.NewMemoryStore() + switch params[ConfigParamType] { + case ConfigParamTypeClientCredentials: + flow, err := oauth2.NewDefaultClientCredentialsFlow(oauth2.ClientCredentialsFlowOptions{ + KeyFile: params[ConfigParamKeyFile], + AdditionalScopes: strings.Split(params[ConfigParamScope], " "), + }) + if err != nil { + return nil, err + } + grant, err := flow.Authorize(issuer.Audience) + if err != nil { + return nil, err + } + err = st.SaveGrant(issuer.Audience, *grant) + if err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("unsupported authentication type: %s", params[ConfigParamType]) + } + + return NewAuthenticationOAuth2(issuer, st), nil +} + +func NewAuthenticationOAuth2( + issuer oauth2.Issuer, + store store.Store) Provider { + + return &oauth2AuthProvider{ + clock: clock.RealClock{}, + issuer: issuer, + store: store, + } +} + +func (p *oauth2AuthProvider) Init() error { + grant, err := p.store.LoadGrant(p.issuer.Audience) + if err != nil { + if err == store.ErrNoAuthenticationData { + return nil + } + return err + } + refresher, err := p.getRefresher(grant.Type) + if err != nil { + return err + } + + source, err := cache.NewDefaultTokenCache(p.store, p.issuer.Audience, refresher) + if err != nil { + return err + } + p.source = source + return nil +} + +func (p *oauth2AuthProvider) Name() string { + return "token" +} + +func (p *oauth2AuthProvider) GetTLSCertificate() (*tls.Certificate, error) { + return nil, nil +} + +func (p *oauth2AuthProvider) GetData() ([]byte, error) { + if p.source == nil { + // anonymous access + return nil, nil + } + token, err := p.source.Token() + if err != nil { + return nil, err + } + return []byte(token.AccessToken), nil +} + +func (p *oauth2AuthProvider) Close() error { + return nil +} + +func (p *oauth2AuthProvider) getRefresher(t oauth2.AuthorizationGrantType) (oauth2.AuthorizationGrantRefresher, error) { + switch t { + case oauth2.GrantTypeClientCredentials: + return oauth2.NewDefaultClientCredentialsGrantRefresher(p.clock) + case oauth2.GrantTypeDeviceCode: + return oauth2.NewDefaultDeviceAuthorizationGrantRefresher(p.clock) + default: + return nil, store.ErrUnsupportedAuthData + } +} + +type transport struct { + source cache.CachingTokenSource + wrapped *xoauth2.Transport +} + +func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { + if len(req.Header.Get("Authorization")) != 0 { + return t.wrapped.Base.RoundTrip(req) + } + + res, err := t.wrapped.RoundTrip(req) + if err != nil { + return nil, err + } + + if res.StatusCode == 401 { + err := t.source.InvalidateToken() + if err != nil { + return nil, err + } + } + + return res, nil +} + +func (t *transport) WrappedRoundTripper() http.RoundTripper { return t.wrapped.Base } + +func (p *oauth2AuthProvider) RoundTrip(req *http.Request) (*http.Response, error) { + return p.tokenTransport.RoundTrip(req) +} + +func (p *oauth2AuthProvider) Transport() http.RoundTripper { + return &transport{ + source: p.source, + wrapped: &xoauth2.Transport{ + Source: p.source, + Base: p.defaultTransport, + }, + } +} + +func (p *oauth2AuthProvider) WithTransport(tripper http.RoundTripper) error { + p.defaultTransport = tripper + p.tokenTransport = &transport{ + source: p.source, + wrapped: &xoauth2.Transport{ + Source: p.source, + Base: p.defaultTransport, + }, + } + return nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/auth/provider.go b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/provider.go new file mode 100644 index 00000000..031ea8d6 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/provider.go @@ -0,0 +1,98 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package auth + +import ( + "crypto/tls" + "encoding/json" + "fmt" + "io" + "net/http" +) + +// Provider is an interface of authentication providers. +type Provider interface { + // Init the authentication provider. + Init() error + + // Name func returns the identifier for this authentication method. + Name() string + + // GetTLSCertificate returns a client certificate chain, or nil if the data are not available + GetTLSCertificate() (*tls.Certificate, error) + + // GetData returns the authentication data identifying this client that will be sent to the broker. + GetData() ([]byte, error) + + io.Closer + + HTTPAuthProvider +} + +type HTTPAuthProvider interface { + RoundTrip(req *http.Request) (*http.Response, error) + Transport() http.RoundTripper + WithTransport(tripper http.RoundTripper) error +} + +type HTTPTransport struct { + T http.RoundTripper +} + +// NewProvider get/create an authentication data provider which provides the data +// that this client will be sent to the broker. +// Some authentication method need to auth between each client channel. So it need +// the broker, who it will talk to. +func NewProvider(name string, params string) (Provider, error) { + m, err := parseParams(params) + if err != nil { + return nil, err + } + + switch name { + case "": + return NewAuthDisabled(), nil + + case "tls", "org.apache.pulsar.client.impl.auth.AuthenticationTls": + return NewAuthenticationTLSWithParams(m), nil + + case "token", "org.apache.pulsar.client.impl.auth.AuthenticationToken": + return NewAuthenticationTokenWithParams(m) + + case "athenz", "org.apache.pulsar.client.impl.auth.AuthenticationAthenz": + return NewAuthenticationAthenzWithParams(m) + + case "oauth2", "org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2": + return NewAuthenticationOAuth2WithParams(m) + + case "basic", "org.apache.pulsar.client.impl.auth.AuthenticationBasic": + return NewAuthenticationBasicWithParams(m) + + default: + return nil, fmt.Errorf("invalid auth provider '%s'", name) + } +} + +func parseParams(params string) (map[string]string, error) { + var mapString map[string]string + if err := json.Unmarshal([]byte(params), &mapString); err != nil { + return nil, err + } + + return mapString, nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/auth/tls.go b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/tls.go new file mode 100644 index 00000000..4b5b9cd9 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/tls.go @@ -0,0 +1,101 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package auth + +import ( + "crypto/tls" + "net/http" +) + +type tlsAuthProvider struct { + certificatePath string + privateKeyPath string + tlsCertSupplier func() (*tls.Certificate, error) + T http.RoundTripper +} + +// NewAuthenticationTLSWithParams initialize the authentication provider with map param. +func NewAuthenticationTLSWithParams(params map[string]string) Provider { + return NewAuthenticationTLS( + params["tlsCertFile"], + params["tlsKeyFile"], + ) +} + +// NewAuthenticationTLS initialize the authentication provider +func NewAuthenticationTLS(certificatePath string, privateKeyPath string) Provider { + return &tlsAuthProvider{ + certificatePath: certificatePath, + privateKeyPath: privateKeyPath, + } +} + +func NewAuthenticationFromTLSCertSupplier(tlsCertSupplier func() (*tls.Certificate, error)) Provider { + return &tlsAuthProvider{ + tlsCertSupplier: tlsCertSupplier, + } +} + +func (p *tlsAuthProvider) Init() error { + // Try to read certificates immediately to provide better error at startup + _, err := p.GetTLSCertificate() + return err +} + +func (p *tlsAuthProvider) Name() string { + return "tls" +} + +func (p *tlsAuthProvider) GetTLSCertificate() (*tls.Certificate, error) { + if p.tlsCertSupplier != nil { + return p.tlsCertSupplier() + } + cert, err := tls.LoadX509KeyPair(p.certificatePath, p.privateKeyPath) + return &cert, err +} + +func (p *tlsAuthProvider) GetData() ([]byte, error) { + return nil, nil +} + +func (tlsAuthProvider) Close() error { + return nil +} + +func (p *tlsAuthProvider) RoundTrip(req *http.Request) (*http.Response, error) { + return p.T.RoundTrip(req) +} + +func (p *tlsAuthProvider) Transport() http.RoundTripper { + return p.T +} + +func (p *tlsAuthProvider) WithTransport(tripper http.RoundTripper) error { + p.T = tripper + return p.configTLS() +} + +func (p *tlsAuthProvider) configTLS() error { + cert, err := p.GetTLSCertificate() + if err != nil { + return err + } + transport := p.T.(*http.Transport) + transport.TLSClientConfig.Certificates = []tls.Certificate{*cert} + return nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/auth/token.go b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/token.go new file mode 100644 index 00000000..898b6537 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/auth/token.go @@ -0,0 +1,125 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package auth + +import ( + "crypto/tls" + "fmt" + "net/http" + "os" + "strings" + + "github.com/pkg/errors" +) + +type tokenAuthProvider struct { + tokenSupplier func() (string, error) + T http.RoundTripper +} + +// NewAuthenticationTokenWithParams return a interface of Provider with string map. +func NewAuthenticationTokenWithParams(params map[string]string) (Provider, error) { + if params["token"] != "" { + return NewAuthenticationToken(params["token"]), nil + } else if params["file"] != "" { + return NewAuthenticationTokenFromFile(params["file"]), nil + } else { + return nil, errors.New("missing configuration for token auth") + } +} + +// NewAuthenticationToken returns a token auth provider that will use the specified token to +// talk with Pulsar brokers +func NewAuthenticationToken(token string) Provider { + return &tokenAuthProvider{ + tokenSupplier: func() (string, error) { + if token == "" { + return "", errors.New("empty token credentials") + } + return token, nil + }, + } +} + +// NewAuthenticationTokenFromSupplier returns a token auth provider that get +// the token data from a user supplied function. The function is invoked each +// time the client library needs to use a token in talking with Pulsar brokers +func NewAuthenticationTokenFromSupplier(tokenSupplier func() (string, error)) Provider { + return &tokenAuthProvider{ + tokenSupplier: tokenSupplier, + } +} + +// NewAuthenticationTokenFromFile return a interface of a Provider with a string token file path. +func NewAuthenticationTokenFromFile(tokenFilePath string) Provider { + return &tokenAuthProvider{ + tokenSupplier: func() (string, error) { + data, err := os.ReadFile(tokenFilePath) + if err != nil { + return "", err + } + + token := strings.Trim(string(data), " \n") + if token == "" { + return "", errors.New("empty token credentials") + } + return token, nil + }, + } +} + +func (p *tokenAuthProvider) Init() error { + // Try to read certificates immediately to provide better error at startup + _, err := p.GetData() + return err +} + +func (p *tokenAuthProvider) Name() string { + return "token" +} + +func (p *tokenAuthProvider) GetTLSCertificate() (*tls.Certificate, error) { + return nil, nil +} + +func (p *tokenAuthProvider) GetData() ([]byte, error) { + t, err := p.tokenSupplier() + if err != nil { + return nil, err + } + return []byte(t), nil +} + +func (p *tokenAuthProvider) Close() error { + return nil +} + +func (p *tokenAuthProvider) RoundTrip(req *http.Request) (*http.Response, error) { + token, _ := p.tokenSupplier() + req.Header.Add("Authorization", strings.TrimSpace(fmt.Sprintf("Bearer %s", token))) + return p.T.RoundTrip(req) +} + +func (p *tokenAuthProvider) Transport() http.RoundTripper { + return p.T +} + +func (p *tokenAuthProvider) WithTransport(tripper http.RoundTripper) error { + p.T = tripper + return nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/batcher_builder.go b/vendor/github.com/apache/pulsar-client-go/pulsar/batcher_builder.go new file mode 100644 index 00000000..05e059b0 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/batcher_builder.go @@ -0,0 +1,42 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "github.com/apache/pulsar-client-go/pulsar/internal" +) + +type BatcherBuilderType int + +const ( + DefaultBatchBuilder BatcherBuilderType = iota + KeyBasedBatchBuilder +) + +func GetBatcherBuilderProvider(typ BatcherBuilderType) ( + internal.BatcherBuilderProvider, error, +) { + switch typ { + case DefaultBatchBuilder: + return internal.NewBatchBuilder, nil + case KeyBasedBatchBuilder: + return internal.NewKeyBasedBatchBuilder, nil + default: + return nil, newError(InvalidBatchBuilderType, "unsupported batcher builder provider type") + } +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/client.go b/vendor/github.com/apache/pulsar-client-go/pulsar/client.go new file mode 100644 index 00000000..bc3f4f58 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/client.go @@ -0,0 +1,200 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "crypto/tls" + "time" + + "github.com/apache/pulsar-client-go/pulsar/auth" + "github.com/apache/pulsar-client-go/pulsar/log" + "github.com/prometheus/client_golang/prometheus" +) + +// NewClient Creates a pulsar client instance +func NewClient(options ClientOptions) (Client, error) { + return newClient(options) +} + +// Authentication Opaque interface that represents the authentication credentials +type Authentication interface{} + +// NewAuthentication Creates an authentication by name and params +func NewAuthentication(name string, params string) (Authentication, error) { + return auth.NewProvider(name, params) +} + +// NewAuthenticationToken Creates new Authentication provider with specified auth token +func NewAuthenticationToken(token string) Authentication { + return auth.NewAuthenticationToken(token) +} + +// NewAuthenticationTokenFromSupplier returns a token auth provider that +// gets the token data from a user supplied function. The function is +// invoked each time the client library needs to use a token in talking +// with Pulsar brokers +func NewAuthenticationTokenFromSupplier(tokenSupplier func() (string, error)) Authentication { + return auth.NewAuthenticationTokenFromSupplier(tokenSupplier) +} + +// NewAuthenticationTokenFromFile Creates new Authentication provider with specified auth token from a file +func NewAuthenticationTokenFromFile(tokenFilePath string) Authentication { + return auth.NewAuthenticationTokenFromFile(tokenFilePath) +} + +// NewAuthenticationTLS Creates new Authentication provider with specified TLS certificate and private key +func NewAuthenticationTLS(certificatePath string, privateKeyPath string) Authentication { + return auth.NewAuthenticationTLS(certificatePath, privateKeyPath) +} + +// NewAuthenticationFromTLSCertSupplier Create new Authentication provider with specified TLS certificate supplier +func NewAuthenticationFromTLSCertSupplier(tlsCertSupplier func() (*tls.Certificate, error)) Authentication { + return auth.NewAuthenticationFromTLSCertSupplier(tlsCertSupplier) +} + +// NewAuthenticationAthenz Creates Athenz Authentication provider +func NewAuthenticationAthenz(authParams map[string]string) Authentication { + athenz, _ := auth.NewAuthenticationAthenzWithParams(authParams) + return athenz +} + +// NewAuthenticationOAuth2 Creates OAuth2 Authentication provider +func NewAuthenticationOAuth2(authParams map[string]string) Authentication { + oauth, _ := auth.NewAuthenticationOAuth2WithParams(authParams) + return oauth +} + +// NewAuthenticationBasic Creates Basic Authentication provider +func NewAuthenticationBasic(username, password string) (Authentication, error) { + return auth.NewAuthenticationBasic(username, password) +} + +// ClientOptions is used to construct a Pulsar Client instance. +type ClientOptions struct { + // Configure the service URL for the Pulsar service. + // This parameter is required + URL string + + // Timeout for the establishment of a TCP connection (default: 5 seconds) + ConnectionTimeout time.Duration + + // Set the operation timeout (default: 30 seconds) + // Producer-create, subscribe and unsubscribe operations will be retried until this interval, after which the + // operation will be marked as failed + OperationTimeout time.Duration + + // Configure the ping send and check interval, default to 30 seconds. + KeepAliveInterval time.Duration + + // Configure the authentication provider. (default: no authentication) + // Example: `Authentication: NewAuthenticationTLS("my-cert.pem", "my-key.pem")` + Authentication + + // Set the path to the TLS key file + TLSKeyFilePath string + + // Set the path to the TLS certificate file + TLSCertificateFile string + + // Set the path to the trusted TLS certificate file + TLSTrustCertsFilePath string + + // Configure whether the Pulsar client accept untrusted TLS certificate from broker (default: false) + TLSAllowInsecureConnection bool + + // Configure whether the Pulsar client verify the validity of the host name from broker (default: false) + TLSValidateHostname bool + + // Configure the net model for vpc user to connect the pulsar broker + ListenerName string + + // Max number of connections to a single broker that will kept in the pool. (Default: 1 connection) + MaxConnectionsPerBroker int + + // Configure the logger used by the client. + // By default, a wrapped logrus.StandardLogger will be used, namely, + // log.NewLoggerWithLogrus(logrus.StandardLogger()) + // FIXME: use `logger` as internal field name instead of `log` as it's more idiomatic + Logger log.Logger + + // Specify metric cardinality to the tenant, namespace or topic levels, or remove it completely. + // Default: MetricsCardinalityNamespace + MetricsCardinality MetricsCardinality + + // Add custom labels to all the metrics reported by this client instance + CustomMetricsLabels map[string]string + + // Specify metric registerer used to register metrics. + // Default prometheus.DefaultRegisterer + MetricsRegisterer prometheus.Registerer + + // Release the connection if it is not used for more than ConnectionMaxIdleTime. + // Default is 60 seconds, negative such as -1 to disable. + ConnectionMaxIdleTime time.Duration + + EnableTransaction bool + + // Limit of client memory usage (in byte). The 64M default can guarantee a high producer throughput. + // Config less than 0 indicates off memory limit. + MemoryLimitBytes int64 +} + +// Client represents a pulsar client +type Client interface { + // CreateProducer Creates the producer instance + // This method will block until the producer is created successfully + CreateProducer(ProducerOptions) (Producer, error) + + // Subscribe Creates a `Consumer` by subscribing to a topic. + // + // If the subscription does not exist, a new subscription will be created and all messages published after the + // creation will be retained until acknowledged, even if the consumer is not connected + Subscribe(ConsumerOptions) (Consumer, error) + + // CreateReader Creates a Reader instance. + // This method will block until the reader is created successfully. + CreateReader(ReaderOptions) (Reader, error) + + // CreateTableView creates a table view instance. + // This method will block until the table view is created successfully. + CreateTableView(TableViewOptions) (TableView, error) + + // TopicPartitions Fetches the list of partitions for a given topic + // + // If the topic is partitioned, this will return a list of partition names. + // If the topic is not partitioned, the returned list will contain the topic + // name itself. + // + // This can be used to discover the partitions and create {@link Reader}, + // {@link Consumer} or {@link Producer} instances directly on a particular partition. + TopicPartitions(topic string) ([]string, error) + + // Close Closes the Client and free associated resources + Close() +} + +// MetricsCardinality represents the specificty of labels on a per-metric basis +type MetricsCardinality int + +const ( + _ MetricsCardinality = iota + MetricsCardinalityNone // Do not add additional labels to metrics + MetricsCardinalityTenant // Label metrics by tenant + MetricsCardinalityNamespace // Label metrics by tenant and namespace + MetricsCardinalityTopic // Label metrics by topic +) diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/client_impl.go b/vendor/github.com/apache/pulsar-client-go/pulsar/client_impl.go new file mode 100644 index 00000000..53225975 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/client_impl.go @@ -0,0 +1,261 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "fmt" + "net/url" + "time" + + "github.com/apache/pulsar-client-go/pulsar/auth" + "github.com/apache/pulsar-client-go/pulsar/internal" + "github.com/apache/pulsar-client-go/pulsar/log" + "github.com/prometheus/client_golang/prometheus" + "github.com/sirupsen/logrus" +) + +const ( + defaultConnectionTimeout = 10 * time.Second + defaultOperationTimeout = 30 * time.Second + defaultKeepAliveInterval = 30 * time.Second + defaultMemoryLimitBytes = 64 * 1024 * 1024 + defaultMemoryLimitTriggerThreshold = 0.95 + defaultConnMaxIdleTime = 180 * time.Second + minConnMaxIdleTime = 60 * time.Second +) + +type client struct { + cnxPool internal.ConnectionPool + rpcClient internal.RPCClient + handlers internal.ClientHandlers + lookupService internal.LookupService + metrics *internal.Metrics + tcClient *transactionCoordinatorClient + memLimit internal.MemoryLimitController + + log log.Logger +} + +func newClient(options ClientOptions) (Client, error) { + var logger log.Logger + if options.Logger != nil { + logger = options.Logger + } else { + logger = log.NewLoggerWithLogrus(logrus.StandardLogger()) + } + + connectionMaxIdleTime := options.ConnectionMaxIdleTime + if connectionMaxIdleTime == 0 { + connectionMaxIdleTime = defaultConnMaxIdleTime + } else if connectionMaxIdleTime > 0 && connectionMaxIdleTime < minConnMaxIdleTime { + return nil, newError(InvalidConfiguration, fmt.Sprintf("Connection max idle time should be at least %f "+ + "seconds", minConnMaxIdleTime.Seconds())) + } else { + logger.Debugf("Disable auto release idle connections") + } + + if options.URL == "" { + return nil, newError(InvalidConfiguration, "URL is required for client") + } + + url, err := url.Parse(options.URL) + if err != nil { + logger.WithError(err).Error("Failed to parse service URL") + return nil, newError(InvalidConfiguration, "Invalid service URL") + } + + var tlsConfig *internal.TLSOptions + switch url.Scheme { + case "pulsar", "http": + tlsConfig = nil + case "pulsar+ssl", "https": + tlsConfig = &internal.TLSOptions{ + AllowInsecureConnection: options.TLSAllowInsecureConnection, + KeyFile: options.TLSKeyFilePath, + CertFile: options.TLSCertificateFile, + TrustCertsFilePath: options.TLSTrustCertsFilePath, + ValidateHostname: options.TLSValidateHostname, + ServerName: url.Hostname(), + } + default: + return nil, newError(InvalidConfiguration, fmt.Sprintf("Invalid URL scheme '%s'", url.Scheme)) + } + + var authProvider auth.Provider + var ok bool + + if options.Authentication == nil { + authProvider = auth.NewAuthDisabled() + } else { + authProvider, ok = options.Authentication.(auth.Provider) + if !ok { + return nil, newError(AuthenticationError, "invalid auth provider interface") + } + } + err = authProvider.Init() + if err != nil { + return nil, err + } + + connectionTimeout := options.ConnectionTimeout + if connectionTimeout.Nanoseconds() == 0 { + connectionTimeout = defaultConnectionTimeout + } + + operationTimeout := options.OperationTimeout + if operationTimeout.Nanoseconds() == 0 { + operationTimeout = defaultOperationTimeout + } + + maxConnectionsPerHost := options.MaxConnectionsPerBroker + if maxConnectionsPerHost <= 0 { + maxConnectionsPerHost = 1 + } + + if options.MetricsCardinality == 0 { + options.MetricsCardinality = MetricsCardinalityNamespace + } + + if options.MetricsRegisterer == nil { + options.MetricsRegisterer = prometheus.DefaultRegisterer + } + + var metrics *internal.Metrics + if options.CustomMetricsLabels != nil { + metrics = internal.NewMetricsProvider( + int(options.MetricsCardinality), options.CustomMetricsLabels, options.MetricsRegisterer) + } else { + metrics = internal.NewMetricsProvider( + int(options.MetricsCardinality), map[string]string{}, options.MetricsRegisterer) + } + + keepAliveInterval := options.KeepAliveInterval + if keepAliveInterval.Nanoseconds() == 0 { + keepAliveInterval = defaultKeepAliveInterval + } + + memLimitBytes := options.MemoryLimitBytes + if memLimitBytes == 0 { + memLimitBytes = defaultMemoryLimitBytes + } + + c := &client{ + cnxPool: internal.NewConnectionPool(tlsConfig, authProvider, connectionTimeout, keepAliveInterval, + maxConnectionsPerHost, logger, metrics, connectionMaxIdleTime), + log: logger, + metrics: metrics, + memLimit: internal.NewMemoryLimitController(memLimitBytes, defaultMemoryLimitTriggerThreshold), + } + serviceNameResolver := internal.NewPulsarServiceNameResolver(url) + + c.rpcClient = internal.NewRPCClient(url, serviceNameResolver, c.cnxPool, operationTimeout, logger, metrics) + + switch url.Scheme { + case "pulsar", "pulsar+ssl": + c.lookupService = internal.NewLookupService(c.rpcClient, url, serviceNameResolver, + tlsConfig != nil, options.ListenerName, logger, metrics) + case "http", "https": + httpClient, err := internal.NewHTTPClient(url, serviceNameResolver, tlsConfig, + operationTimeout, logger, metrics, authProvider) + if err != nil { + return nil, newError(InvalidConfiguration, fmt.Sprintf("Failed to init http client with err: '%s'", + err.Error())) + } + c.lookupService = internal.NewHTTPLookupService(httpClient, url, serviceNameResolver, + tlsConfig != nil, logger, metrics) + default: + return nil, newError(InvalidConfiguration, fmt.Sprintf("Invalid URL scheme '%s'", url.Scheme)) + } + + c.handlers = internal.NewClientHandlers() + + if options.EnableTransaction { + c.tcClient = newTransactionCoordinatorClientImpl(c) + err = c.tcClient.start() + if err != nil { + return nil, err + } + } + + return c, nil +} + +func (c *client) CreateProducer(options ProducerOptions) (Producer, error) { + producer, err := newProducer(c, &options) + if err == nil { + c.handlers.Add(producer) + } + return producer, err +} + +func (c *client) Subscribe(options ConsumerOptions) (Consumer, error) { + consumer, err := newConsumer(c, options) + if err != nil { + return nil, err + } + c.handlers.Add(consumer) + return consumer, nil +} + +func (c *client) CreateReader(options ReaderOptions) (Reader, error) { + reader, err := newReader(c, options) + if err != nil { + return nil, err + } + c.handlers.Add(reader) + return reader, nil +} + +func (c *client) CreateTableView(options TableViewOptions) (TableView, error) { + tableView, err := newTableView(c, options) + if err != nil { + return nil, err + } + c.handlers.Add(tableView) + return tableView, nil +} + +func (c *client) TopicPartitions(topic string) ([]string, error) { + topicName, err := internal.ParseTopicName(topic) + if err != nil { + return nil, err + } + + r, err := c.lookupService.GetPartitionedTopicMetadata(topic) + if err != nil { + return nil, err + } + if r != nil { + if r.Partitions > 0 { + partitions := make([]string, r.Partitions) + for i := 0; i < r.Partitions; i++ { + partitions[i] = fmt.Sprintf("%s-partition-%d", topic, i) + } + return partitions, nil + } + } + + // Non-partitioned topic + return []string{topicName.Name}, nil +} + +func (c *client) Close() { + c.handlers.Close() + c.cnxPool.Close() + c.lookupService.Close() +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/consumer.go b/vendor/github.com/apache/pulsar-client-go/pulsar/consumer.go new file mode 100644 index 00000000..64a096d5 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/consumer.go @@ -0,0 +1,319 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" + "time" + + "github.com/apache/pulsar-client-go/pulsar/internal" +) + +// ConsumerMessage represents a pair of a Consumer and Message. +type ConsumerMessage struct { + Consumer + Message +} + +// SubscriptionType of subscription supported by Pulsar +type SubscriptionType int + +const ( + // Exclusive there can be only 1 consumer on the same topic with the same subscription name + Exclusive SubscriptionType = iota + + // Shared subscription mode, multiple consumer will be able to use the same subscription name + // and the messages will be dispatched according to + // a round-robin rotation between the connected consumers + Shared + + // Failover subscription mode, multiple consumer will be able to use the same subscription name + // but only 1 consumer will receive the messages. + // If that consumer disconnects, one of the other connected consumers will start receiving messages. + Failover + + // KeyShared subscription mode, multiple consumer will be able to use the same + // subscription and all messages with the same key will be dispatched to only one consumer + KeyShared +) + +type SubscriptionInitialPosition int + +const ( + // SubscriptionPositionLatest is the latest position which means the start consuming position + // will be the last message + SubscriptionPositionLatest SubscriptionInitialPosition = iota + + // SubscriptionPositionEarliest is the earliest position which means the start consuming position + // will be the first message + SubscriptionPositionEarliest +) + +// DLQPolicy represents the configuration for the Dead Letter Queue consumer policy. +type DLQPolicy struct { + // MaxDeliveries specifies the maximum number of times that a message will be delivered before being + // sent to the dead letter queue. + MaxDeliveries uint32 + + // DeadLetterTopic specifies the name of the topic where the failing messages will be sent. + DeadLetterTopic string + + // ProducerOptions is the producer options to produce messages to the DLQ and RLQ topic + ProducerOptions ProducerOptions + + // RetryLetterTopic specifies the name of the topic where the retry messages will be sent. + RetryLetterTopic string +} + +// AckGroupingOptions controls how to group ACK requests +// If maxSize is 0 or 1, any ACK request will be sent immediately. +// Otherwise, the ACK requests will be cached until one of the following conditions meets: +// 1. There are `MaxSize` pending ACK requests. +// 2. `MaxTime` is greater than 1 microsecond and ACK requests have been cached for `maxTime`. +// Specially, for cumulative acknowledgment, only the latest ACK is cached and it will only be sent after `MaxTime`. +type AckGroupingOptions struct { + // The maximum number of ACK requests to cache + MaxSize uint32 + + // The maximum time to cache ACK requests + MaxTime time.Duration +} + +// ConsumerOptions is used to configure and create instances of Consumer. +type ConsumerOptions struct { + // Topic specifies the topic this consumer will subscribe on. + // Either a topic, a list of topics or a topics pattern are required when subscribing + Topic string + + // Topics specifies a list of topics this consumer will subscribe on. + // Either a topic, a list of topics or a topics pattern are required when subscribing + Topics []string + + // TopicsPattern specifies a regular expression to subscribe to multiple topics under the same namespace. + // Either a topic, a list of topics or a topics pattern are required when subscribing + TopicsPattern string + + // AutoDiscoveryPeriod specifies the interval in which to poll for new partitions or new topics + // if using a TopicsPattern. + AutoDiscoveryPeriod time.Duration + + // SubscriptionName specifies the subscription name for this consumer + // This argument is required when subscribing + SubscriptionName string + + // Properties represents a set of application defined properties for the consumer. + // Those properties will be visible in the topic stats + Properties map[string]string + + // SubscriptionProperties specify the subscription properties for this subscription. + // + // > Notice: SubscriptionProperties are immutable, and consumers under the same subscription will fail to create a + // > subscription if they use different properties. + SubscriptionProperties map[string]string + + // Type specifies the subscription type to be used when subscribing to a topic. + // Default is `Exclusive` + Type SubscriptionType + + // SubscriptionInitialPosition is the initial position at which the cursor will be set when subscribe + // Default is `Latest` + SubscriptionInitialPosition + + // EventListener will be called when active consumer changed (in failover subscription type) + EventListener ConsumerEventListener + + // DLQ represents the configuration for Dead Letter Queue consumer policy. + // eg. route the message to topic X after N failed attempts at processing it + // By default is nil and there's no DLQ + DLQ *DLQPolicy + + // KeySharedPolicy represents the configuration for Key Shared consumer policy. + KeySharedPolicy *KeySharedPolicy + + // RetryEnable determines whether to automatically retry sending messages to default filled DLQPolicy topics. + // Default is false + RetryEnable bool + + // MessageChannel sets a `MessageChannel` for the consumer + // When a message is received, it will be pushed to the channel for consumption + MessageChannel chan ConsumerMessage + + // ReceiverQueueSize sets the size of the consumer receive queue. + // The consumer receive queue controls how many messages can be accumulated by the `Consumer` before the + // application calls `Consumer.receive()`. Using a higher value could potentially increase the consumer + // throughput at the expense of bigger memory utilization. + // Default value is `1000` messages and should be good for most use cases. + ReceiverQueueSize int + + // EnableAutoScaledReceiverQueueSize, if enabled, the consumer receive queue will be auto-scaled + // by the consumer actual throughput. The ReceiverQueueSize will be the maximum size which consumer + // receive queue can be scaled. + // Default is false. + EnableAutoScaledReceiverQueueSize bool + + // NackRedeliveryDelay specifies the delay after which to redeliver the messages that failed to be + // processed. Default is 1 min. (See `Consumer.Nack()`) + NackRedeliveryDelay time.Duration + + // Name specifies the consumer name. + Name string + + // ReadCompacted, if enabled, the consumer will read messages from the compacted topic rather than reading the + // full message backlog of the topic. This means that, if the topic has been compacted, the consumer will only + // see the latest value for each key in the topic, up until the point in the topic message backlog that has been + // compacted. Beyond that point, the messages will be sent as normal. + // + // ReadCompacted can only be enabled subscriptions to persistent topics, which have a single active consumer (i.e. + // failure or exclusive subscriptions). Attempting to enable it on subscriptions to a non-persistent topics or on a + // shared subscription, will lead to the subscription call throwing a PulsarClientException. + ReadCompacted bool + + // ReplicateSubscriptionState marks the subscription as replicated to keep it in sync across clusters + ReplicateSubscriptionState bool + + // Interceptors is a chain of interceptors. These interceptors will be called at some points defined in + // ConsumerInterceptor interface. + Interceptors ConsumerInterceptors + + // Schema represents the schema implementation. + Schema Schema + + // MaxReconnectToBroker sets the maximum retry number of reconnectToBroker. (default: ultimate) + MaxReconnectToBroker *uint + + // BackoffPolicy parameterize the following options in the reconnection logic to + // allow users to customize the reconnection logic (minBackoff, maxBackoff and jitterPercentage) + BackoffPolicy internal.BackoffPolicy + + // Decryption represents the encryption related fields required by the consumer to decrypt a message. + Decryption *MessageDecryptionInfo + + // EnableDefaultNackBackoffPolicy, if enabled, the default implementation of NackBackoffPolicy will be used + // to calculate the delay time of + // nack backoff, Default: false. + EnableDefaultNackBackoffPolicy bool + + // NackBackoffPolicy is a redelivery backoff mechanism which we can achieve redelivery with different + // delays according to the number of times the message is retried. + // + // > Notice: the NackBackoffPolicy will not work with `consumer.NackID(MessageID)` + // > because we are not able to get the redeliveryCount from the message ID. + NackBackoffPolicy NackBackoffPolicy + + // AckWithResponse is a return value added to Ack Command, and its purpose is to confirm whether Ack Command + // is executed correctly on the Broker side. When set to true, the error information returned by the Ack + // method contains the return value of the Ack Command processed by the Broker side; when set to false, the + // error information of the Ack method only contains errors that may occur in the Go SDK's own processing. + // Default: false + AckWithResponse bool + + // MaxPendingChunkedMessage sets the maximum pending chunked messages. (default: 100) + MaxPendingChunkedMessage int + + // ExpireTimeOfIncompleteChunk sets the expiry time of discarding incomplete chunked message. (default: 60 seconds) + ExpireTimeOfIncompleteChunk time.Duration + + // AutoAckIncompleteChunk sets whether consumer auto acknowledges incomplete chunked message when it should + // be removed (e.g.the chunked message pending queue is full). (default: false) + AutoAckIncompleteChunk bool + + // Enable or disable batch index acknowledgment. To enable this feature, ensure batch index acknowledgment + // is enabled on the broker side. (default: false) + EnableBatchIndexAcknowledgment bool + + // Controls how to group ACK requests, the default value is nil, which means: + // MaxSize: 1000 + // MaxTime: 100*time.Millisecond + // NOTE: This option does not work if AckWithResponse is true + // because there are only synchronous APIs for acknowledgment + AckGroupingOptions *AckGroupingOptions +} + +// Consumer is an interface that abstracts behavior of Pulsar's consumer +type Consumer interface { + // Subscription get a subscription for the consumer + Subscription() string + + // Unsubscribe the consumer + Unsubscribe() error + + // Receive a single message. + // This calls blocks until a message is available. + Receive(context.Context) (Message, error) + + // Chan returns a channel to consume messages from + Chan() <-chan ConsumerMessage + + // Ack the consumption of a single message + Ack(Message) error + + // AckID the consumption of a single message, identified by its MessageID + AckID(MessageID) error + + // AckCumulative the reception of all the messages in the stream up to (and including) + // the provided message. + AckCumulative(msg Message) error + + // AckIDCumulative the reception of all the messages in the stream up to (and including) + // the provided message, identified by its MessageID + AckIDCumulative(msgID MessageID) error + + // ReconsumeLater mark a message for redelivery after custom delay + ReconsumeLater(msg Message, delay time.Duration) + + // ReconsumeLaterWithCustomProperties mark a message for redelivery after custom delay with custom properties + ReconsumeLaterWithCustomProperties(msg Message, customProperties map[string]string, delay time.Duration) + + // Nack acknowledges the failure to process a single message. + // + // When a message is "negatively acked" it will be marked for redelivery after + // some fixed delay. The delay is configurable when constructing the consumer + // with ConsumerOptions.NackRedeliveryDelay . + // + // This call is not blocking. + Nack(Message) + + // NackID acknowledges the failure to process a single message. + // + // When a message is "negatively acked" it will be marked for redelivery after + // some fixed delay. The delay is configurable when constructing the consumer + // with ConsumerOptions.NackRedeliveryDelay . + // + // This call is not blocking. + NackID(MessageID) + + // Close the consumer and stop the broker to push more messages + Close() + + // Seek resets the subscription associated with this consumer to a specific message id. + // The message id can either be a specific message or represent the first or last messages in the topic. + // + // Note: this operation can only be done on non-partitioned topics. For these, one can rather perform the + // seek() on the individual partitions. + Seek(MessageID) error + + // SeekByTime resets the subscription associated with this consumer to a specific message publish time. + // + // @param time + // the message publish time when to reposition the subscription + // + SeekByTime(time time.Time) error + + // Name returns the name of consumer. + Name() string +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_impl.go b/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_impl.go new file mode 100644 index 00000000..fd7fa578 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_impl.go @@ -0,0 +1,784 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" + "fmt" + "math/rand" + "strconv" + "sync" + "time" + + "github.com/apache/pulsar-client-go/pulsar/crypto" + "github.com/apache/pulsar-client-go/pulsar/internal" + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "github.com/apache/pulsar-client-go/pulsar/log" + pkgerrors "github.com/pkg/errors" +) + +const defaultNackRedeliveryDelay = 1 * time.Minute + +type acker interface { + // AckID does not handle errors returned by the Broker side, so no need to wait for doneCh to finish. + AckID(id MessageID) error + AckIDWithResponse(id MessageID) error + AckIDCumulative(msgID MessageID) error + AckIDWithResponseCumulative(msgID MessageID) error + NackID(id MessageID) + NackMsg(msg Message) +} + +type consumer struct { + sync.Mutex + topic string + client *client + options ConsumerOptions + consumers []*partitionConsumer + consumerName string + disableForceTopicCreation bool + + // channel used to deliver message to clients + messageCh chan ConsumerMessage + + dlq *dlqRouter + rlq *retryRouter + closeOnce sync.Once + closeCh chan struct{} + errorCh chan error + stopDiscovery func() + + log log.Logger + metrics *internal.LeveledMetrics +} + +func newConsumer(client *client, options ConsumerOptions) (Consumer, error) { + if options.Topic == "" && options.Topics == nil && options.TopicsPattern == "" { + return nil, newError(TopicNotFound, "topic is required") + } + + if options.SubscriptionName == "" { + return nil, newError(SubscriptionNotFound, "subscription name is required for consumer") + } + + if options.ReceiverQueueSize <= 0 { + options.ReceiverQueueSize = defaultReceiverQueueSize + } + + if options.Interceptors == nil { + options.Interceptors = defaultConsumerInterceptors + } + + if options.Name == "" { + options.Name = generateRandomName() + } + + if options.Schema != nil && options.Schema.GetSchemaInfo() != nil { + if options.Schema.GetSchemaInfo().Type == NONE { + options.Schema = NewBytesSchema(nil) + } + } + + if options.MaxPendingChunkedMessage == 0 { + options.MaxPendingChunkedMessage = 100 + } + + if options.ExpireTimeOfIncompleteChunk == 0 { + options.ExpireTimeOfIncompleteChunk = time.Minute + } + + if options.NackBackoffPolicy == nil && options.EnableDefaultNackBackoffPolicy { + options.NackBackoffPolicy = new(defaultNackBackoffPolicy) + } + + // did the user pass in a message channel? + messageCh := options.MessageChannel + if options.MessageChannel == nil { + messageCh = make(chan ConsumerMessage, 10) + } + + if options.RetryEnable { + usingTopic := "" + if options.Topic != "" { + usingTopic = options.Topic + } else if len(options.Topics) > 0 { + usingTopic = options.Topics[0] + } + tn, err := internal.ParseTopicName(usingTopic) + if err != nil { + return nil, err + } + + topicName := internal.TopicNameWithoutPartitionPart(tn) + + retryTopic := topicName + "-" + options.SubscriptionName + RetryTopicSuffix + dlqTopic := topicName + "-" + options.SubscriptionName + DlqTopicSuffix + + oldRetryTopic := tn.Domain + "://" + tn.Namespace + "/" + options.SubscriptionName + RetryTopicSuffix + oldDlqTopic := tn.Domain + "://" + tn.Namespace + "/" + options.SubscriptionName + DlqTopicSuffix + + if r, err := client.lookupService.GetPartitionedTopicMetadata(oldRetryTopic); err == nil && + r != nil && + r.Partitions > 0 { + retryTopic = oldRetryTopic + } + + if r, err := client.lookupService.GetPartitionedTopicMetadata(oldDlqTopic); err == nil && + r != nil && + r.Partitions > 0 { + dlqTopic = oldDlqTopic + } + + if options.DLQ == nil { + options.DLQ = &DLQPolicy{ + MaxDeliveries: MaxReconsumeTimes, + DeadLetterTopic: dlqTopic, + RetryLetterTopic: retryTopic, + } + } else { + if options.DLQ.DeadLetterTopic == "" { + options.DLQ.DeadLetterTopic = dlqTopic + } + if options.DLQ.RetryLetterTopic == "" { + options.DLQ.RetryLetterTopic = retryTopic + } + } + if options.Topic != "" && len(options.Topics) == 0 { + options.Topics = []string{options.Topic, options.DLQ.RetryLetterTopic} + options.Topic = "" + } else if options.Topic == "" && len(options.Topics) > 0 { + options.Topics = append(options.Topics, options.DLQ.RetryLetterTopic) + } + } + + dlq, err := newDlqRouter(client, options.DLQ, client.log) + if err != nil { + return nil, err + } + rlq, err := newRetryRouter(client, options.DLQ, options.RetryEnable, client.log) + if err != nil { + return nil, err + } + + // normalize as FQDN topics + var tns []*internal.TopicName + // single topic consumer + if options.Topic != "" || len(options.Topics) == 1 { + topic := options.Topic + if topic == "" { + topic = options.Topics[0] + } + + if tns, err = validateTopicNames(topic); err != nil { + return nil, err + } + topic = tns[0].Name + err = addMessageCryptoIfMissing(client, &options, topic) + if err != nil { + return nil, err + } + return newInternalConsumer(client, options, topic, messageCh, dlq, rlq, false) + } + + if len(options.Topics) > 1 { + if tns, err = validateTopicNames(options.Topics...); err != nil { + return nil, err + } + for i := range options.Topics { + options.Topics[i] = tns[i].Name + } + options.Topics = distinct(options.Topics) + + err = addMessageCryptoIfMissing(client, &options, options.Topics) + if err != nil { + return nil, err + } + + return newMultiTopicConsumer(client, options, options.Topics, messageCh, dlq, rlq) + } + + if options.TopicsPattern != "" { + tn, err := internal.ParseTopicName(options.TopicsPattern) + if err != nil { + return nil, err + } + + pattern, err := extractTopicPattern(tn) + if err != nil { + return nil, err + } + + err = addMessageCryptoIfMissing(client, &options, tn.Name) + if err != nil { + return nil, err + } + + return newRegexConsumer(client, options, tn, pattern, messageCh, dlq, rlq) + } + + return nil, newError(InvalidTopicName, "topic name is required for consumer") +} + +func newInternalConsumer(client *client, options ConsumerOptions, topic string, + messageCh chan ConsumerMessage, dlq *dlqRouter, rlq *retryRouter, disableForceTopicCreation bool) (*consumer, error) { + + consumer := &consumer{ + topic: topic, + client: client, + options: options, + disableForceTopicCreation: disableForceTopicCreation, + messageCh: messageCh, + closeCh: make(chan struct{}), + errorCh: make(chan error), + dlq: dlq, + rlq: rlq, + log: client.log.SubLogger(log.Fields{"topic": topic}), + consumerName: options.Name, + metrics: client.metrics.GetLeveledMetrics(topic), + } + + err := consumer.internalTopicSubscribeToPartitions() + if err != nil { + return nil, err + } + + // set up timer to monitor for new partitions being added + duration := options.AutoDiscoveryPeriod + if duration <= 0 { + duration = defaultAutoDiscoveryDuration + } + consumer.stopDiscovery = consumer.runBackgroundPartitionDiscovery(duration) + + consumer.metrics.ConsumersOpened.Inc() + return consumer, nil +} + +// Name returns the name of consumer. +func (c *consumer) Name() string { + return c.consumerName +} + +func (c *consumer) runBackgroundPartitionDiscovery(period time.Duration) (cancel func()) { + var wg sync.WaitGroup + stopDiscoveryCh := make(chan struct{}) + ticker := time.NewTicker(period) + + wg.Add(1) + go func() { + defer wg.Done() + for { + select { + case <-stopDiscoveryCh: + return + case <-ticker.C: + c.log.Debug("Auto discovering new partitions") + c.internalTopicSubscribeToPartitions() + } + } + }() + + return func() { + ticker.Stop() + close(stopDiscoveryCh) + wg.Wait() + } +} + +func (c *consumer) internalTopicSubscribeToPartitions() error { + partitions, err := c.client.TopicPartitions(c.topic) + if err != nil { + return err + } + + oldNumPartitions := 0 + newNumPartitions := len(partitions) + + c.Lock() + defer c.Unlock() + + oldConsumers := c.consumers + oldNumPartitions = len(oldConsumers) + + if oldConsumers != nil { + if oldNumPartitions == newNumPartitions { + c.log.Debug("Number of partitions in topic has not changed") + return nil + } + + c.log.WithField("old_partitions", oldNumPartitions). + WithField("new_partitions", newNumPartitions). + Info("Changed number of partitions in topic") + } + + c.consumers = make([]*partitionConsumer, newNumPartitions) + + // When for some reason (eg: forced deletion of sub partition) causes oldNumPartitions> newNumPartitions, + // we need to rebuild the cache of new consumers, otherwise the array will be out of bounds. + if oldConsumers != nil && oldNumPartitions < newNumPartitions { + // Copy over the existing consumer instances + for i := 0; i < oldNumPartitions; i++ { + c.consumers[i] = oldConsumers[i] + } + } + + type ConsumerError struct { + err error + partition int + consumer *partitionConsumer + } + + receiverQueueSize := c.options.ReceiverQueueSize + metadata := c.options.Properties + subProperties := c.options.SubscriptionProperties + + startPartition := oldNumPartitions + partitionsToAdd := newNumPartitions - oldNumPartitions + + if partitionsToAdd < 0 { + partitionsToAdd = newNumPartitions + startPartition = 0 + } + + var wg sync.WaitGroup + ch := make(chan ConsumerError, partitionsToAdd) + wg.Add(partitionsToAdd) + + for partitionIdx := startPartition; partitionIdx < newNumPartitions; partitionIdx++ { + partitionTopic := partitions[partitionIdx] + + go func(idx int, pt string) { + defer wg.Done() + + var nackRedeliveryDelay time.Duration + if c.options.NackRedeliveryDelay == 0 { + nackRedeliveryDelay = defaultNackRedeliveryDelay + } else { + nackRedeliveryDelay = c.options.NackRedeliveryDelay + } + opts := &partitionConsumerOpts{ + topic: pt, + consumerName: c.consumerName, + subscription: c.options.SubscriptionName, + subscriptionType: c.options.Type, + subscriptionInitPos: c.options.SubscriptionInitialPosition, + partitionIdx: idx, + receiverQueueSize: receiverQueueSize, + nackRedeliveryDelay: nackRedeliveryDelay, + nackBackoffPolicy: c.options.NackBackoffPolicy, + metadata: metadata, + subProperties: subProperties, + replicateSubscriptionState: c.options.ReplicateSubscriptionState, + startMessageID: nil, + subscriptionMode: durable, + readCompacted: c.options.ReadCompacted, + interceptors: c.options.Interceptors, + maxReconnectToBroker: c.options.MaxReconnectToBroker, + backoffPolicy: c.options.BackoffPolicy, + keySharedPolicy: c.options.KeySharedPolicy, + schema: c.options.Schema, + decryption: c.options.Decryption, + ackWithResponse: c.options.AckWithResponse, + maxPendingChunkedMessage: c.options.MaxPendingChunkedMessage, + expireTimeOfIncompleteChunk: c.options.ExpireTimeOfIncompleteChunk, + autoAckIncompleteChunk: c.options.AutoAckIncompleteChunk, + consumerEventListener: c.options.EventListener, + enableBatchIndexAck: c.options.EnableBatchIndexAcknowledgment, + ackGroupingOptions: c.options.AckGroupingOptions, + autoReceiverQueueSize: c.options.EnableAutoScaledReceiverQueueSize, + } + cons, err := newPartitionConsumer(c, c.client, opts, c.messageCh, c.dlq, c.metrics) + ch <- ConsumerError{ + err: err, + partition: idx, + consumer: cons, + } + }(partitionIdx, partitionTopic) + } + + go func() { + wg.Wait() + close(ch) + }() + + for ce := range ch { + if ce.err != nil { + err = ce.err + } else { + c.consumers[ce.partition] = ce.consumer + } + } + + if err != nil { + // Since there were some failures, + // cleanup all the partitions that succeeded in creating the consumer + for _, c := range c.consumers { + if c != nil { + c.Close() + } + } + return err + } + + if newNumPartitions < oldNumPartitions { + c.metrics.ConsumersPartitions.Set(float64(newNumPartitions)) + } else { + c.metrics.ConsumersPartitions.Add(float64(partitionsToAdd)) + } + return nil +} + +func (c *consumer) Subscription() string { + return c.options.SubscriptionName +} + +func (c *consumer) Unsubscribe() error { + c.Lock() + defer c.Unlock() + + var errMsg string + for _, consumer := range c.consumers { + if err := consumer.Unsubscribe(); err != nil { + errMsg += fmt.Sprintf("topic %s, subscription %s: %s", consumer.topic, c.Subscription(), err) + } + } + if errMsg != "" { + return fmt.Errorf(errMsg) + } + return nil +} + +func (c *consumer) Receive(ctx context.Context) (message Message, err error) { + for { + select { + case <-c.closeCh: + return nil, newError(ConsumerClosed, "consumer closed") + case cm, ok := <-c.messageCh: + if !ok { + return nil, newError(ConsumerClosed, "consumer closed") + } + return cm.Message, nil + case <-ctx.Done(): + return nil, ctx.Err() + } + } +} + +// Chan return the message chan to users +func (c *consumer) Chan() <-chan ConsumerMessage { + return c.messageCh +} + +// Ack the consumption of a single message +func (c *consumer) Ack(msg Message) error { + return c.AckID(msg.ID()) +} + +// AckID the consumption of a single message, identified by its MessageID +func (c *consumer) AckID(msgID MessageID) error { + if err := c.checkMsgIDPartition(msgID); err != nil { + return err + } + + if c.options.AckWithResponse { + return c.consumers[msgID.PartitionIdx()].AckIDWithResponse(msgID) + } + + return c.consumers[msgID.PartitionIdx()].AckID(msgID) +} + +// AckCumulative the reception of all the messages in the stream up to (and including) +// the provided message, identified by its MessageID +func (c *consumer) AckCumulative(msg Message) error { + return c.AckIDCumulative(msg.ID()) +} + +// AckIDCumulative the reception of all the messages in the stream up to (and including) +// the provided message, identified by its MessageID +func (c *consumer) AckIDCumulative(msgID MessageID) error { + if err := c.checkMsgIDPartition(msgID); err != nil { + return err + } + + if c.options.AckWithResponse { + return c.consumers[msgID.PartitionIdx()].AckIDWithResponseCumulative(msgID) + } + + return c.consumers[msgID.PartitionIdx()].AckIDCumulative(msgID) +} + +// ReconsumeLater mark a message for redelivery after custom delay +func (c *consumer) ReconsumeLater(msg Message, delay time.Duration) { + c.ReconsumeLaterWithCustomProperties(msg, map[string]string{}, delay) +} + +// ReconsumeLaterWithCustomProperties mark a message for redelivery after custom delay with custom properties +func (c *consumer) ReconsumeLaterWithCustomProperties(msg Message, customProperties map[string]string, + delay time.Duration) { + if delay < 0 { + delay = 0 + } + + if !checkMessageIDType(msg.ID()) { + c.log.Warnf("invalid message id type %T", msg.ID()) + return + } + + msgID := c.messageID(msg.ID()) + if msgID == nil { + return + } + + props := make(map[string]string) + for k, v := range msg.Properties() { + props[k] = v + } + + for k, v := range customProperties { + props[k] = v + } + + reconsumeTimes := 1 + if s, ok := props[SysPropertyReconsumeTimes]; ok { + reconsumeTimes, _ = strconv.Atoi(s) + reconsumeTimes++ + } else { + props[SysPropertyRealTopic] = msg.Topic() + props[SysPropertyOriginMessageID] = msgID.messageID.String() + } + props[SysPropertyReconsumeTimes] = strconv.Itoa(reconsumeTimes) + props[SysPropertyDelayTime] = fmt.Sprintf("%d", int64(delay)/1e6) + + consumerMsg := ConsumerMessage{ + Consumer: c, + Message: &message{ + payLoad: msg.Payload(), + properties: props, + msgID: msgID, + }, + } + if uint32(reconsumeTimes) > c.dlq.policy.MaxDeliveries { + c.dlq.Chan() <- consumerMsg + } else { + c.rlq.Chan() <- RetryMessage{ + consumerMsg: consumerMsg, + producerMsg: ProducerMessage{ + Payload: msg.Payload(), + Key: msg.Key(), + OrderingKey: msg.OrderingKey(), + Properties: props, + DeliverAfter: delay, + }, + } + } +} + +func (c *consumer) Nack(msg Message) { + if !checkMessageIDType(msg.ID()) { + c.log.Warnf("invalid message id type %T", msg.ID()) + return + } + if c.options.EnableDefaultNackBackoffPolicy || c.options.NackBackoffPolicy != nil { + mid := c.messageID(msg.ID()) + if mid == nil { + return + } + + if mid.consumer != nil { + mid.NackByMsg(msg) + return + } + c.consumers[mid.partitionIdx].NackMsg(msg) + return + } + + c.NackID(msg.ID()) +} + +func (c *consumer) NackID(msgID MessageID) { + if err := c.checkMsgIDPartition(msgID); err != nil { + return + } + + c.consumers[msgID.PartitionIdx()].NackID(msgID) +} + +func (c *consumer) Close() { + c.closeOnce.Do(func() { + c.stopDiscovery() + + c.Lock() + defer c.Unlock() + + var wg sync.WaitGroup + for i := range c.consumers { + wg.Add(1) + go func(pc *partitionConsumer) { + defer wg.Done() + pc.Close() + }(c.consumers[i]) + } + wg.Wait() + close(c.closeCh) + c.client.handlers.Del(c) + c.dlq.close() + c.rlq.close() + c.metrics.ConsumersClosed.Inc() + c.metrics.ConsumersPartitions.Sub(float64(len(c.consumers))) + }) +} + +func (c *consumer) Seek(msgID MessageID) error { + c.Lock() + defer c.Unlock() + + if len(c.consumers) > 1 { + return newError(SeekFailed, "for partition topic, seek command should perform on the individual partitions") + } + + if err := c.checkMsgIDPartition(msgID); err != nil { + return err + } + + if err := c.consumers[msgID.PartitionIdx()].Seek(msgID); err != nil { + return err + } + + // clear messageCh + for len(c.messageCh) > 0 { + <-c.messageCh + } + + return nil +} + +func (c *consumer) SeekByTime(time time.Time) error { + c.Lock() + defer c.Unlock() + var errs error + // run SeekByTime on every partition of topic + for _, cons := range c.consumers { + if err := cons.SeekByTime(time); err != nil { + msg := fmt.Sprintf("unable to SeekByTime for topic=%s subscription=%s", c.topic, c.Subscription()) + errs = pkgerrors.Wrap(newError(SeekFailed, err.Error()), msg) + } + } + + // clear messageCh + for len(c.messageCh) > 0 { + <-c.messageCh + } + + return errs +} + +func (c *consumer) checkMsgIDPartition(msgID MessageID) error { + partition := msgID.PartitionIdx() + if partition < 0 || int(partition) >= len(c.consumers) { + c.log.Errorf("invalid partition index %d expected a partition between [0-%d]", + partition, len(c.consumers)) + return fmt.Errorf("invalid partition index %d expected a partition between [0-%d]", + partition, len(c.consumers)) + } + return nil +} + +var r = &random{ + R: rand.New(rand.NewSource(time.Now().UnixNano())), +} + +type random struct { + sync.Mutex + R *rand.Rand +} + +func generateRandomName() string { + r.Lock() + defer r.Unlock() + chars := "abcdefghijklmnopqrstuvwxyz" + bytes := make([]byte, 5) + for i := range bytes { + bytes[i] = chars[r.R.Intn(len(chars))] + } + return string(bytes) +} + +func distinct(fqdnTopics []string) []string { + set := make(map[string]struct{}) + uniques := make([]string, 0, len(fqdnTopics)) + for _, topic := range fqdnTopics { + if _, ok := set[topic]; !ok { + set[topic] = struct{}{} + uniques = append(uniques, topic) + } + } + return uniques +} + +func toProtoSubType(st SubscriptionType) pb.CommandSubscribe_SubType { + switch st { + case Exclusive: + return pb.CommandSubscribe_Exclusive + case Shared: + return pb.CommandSubscribe_Shared + case Failover: + return pb.CommandSubscribe_Failover + case KeyShared: + return pb.CommandSubscribe_Key_Shared + } + + return pb.CommandSubscribe_Exclusive +} + +func toProtoInitialPosition(p SubscriptionInitialPosition) pb.CommandSubscribe_InitialPosition { + switch p { + case SubscriptionPositionLatest: + return pb.CommandSubscribe_Latest + case SubscriptionPositionEarliest: + return pb.CommandSubscribe_Earliest + } + + return pb.CommandSubscribe_Latest +} + +func (c *consumer) messageID(msgID MessageID) *trackingMessageID { + mid := toTrackingMessageID(msgID) + + partition := int(mid.partitionIdx) + // did we receive a valid partition index? + if partition < 0 || partition >= len(c.consumers) { + c.log.Warnf("invalid partition index %d expected a partition between [0-%d]", + partition, len(c.consumers)) + return nil + } + + return mid +} + +func addMessageCryptoIfMissing(client *client, options *ConsumerOptions, topics interface{}) error { + // decryption is enabled, use default messagecrypto if not provided + if options.Decryption != nil && options.Decryption.MessageCrypto == nil { + messageCrypto, err := crypto.NewDefaultMessageCrypto("decrypt", + false, + client.log.SubLogger(log.Fields{"topic": topics})) + if err != nil { + return err + } + options.Decryption.MessageCrypto = messageCrypto + } + return nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_interceptor.go b/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_interceptor.go new file mode 100644 index 00000000..db46b784 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_interceptor.go @@ -0,0 +1,51 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +type ConsumerInterceptor interface { + // BeforeConsume This is called just before the message is send to Consumer's ConsumerMessage channel. + BeforeConsume(message ConsumerMessage) + + // OnAcknowledge This is called consumer sends the acknowledgment to the broker. + OnAcknowledge(consumer Consumer, msgID MessageID) + + // OnNegativeAcksSend This method will be called when a redelivery from a negative acknowledge occurs. + OnNegativeAcksSend(consumer Consumer, msgIDs []MessageID) +} + +type ConsumerInterceptors []ConsumerInterceptor + +func (x ConsumerInterceptors) BeforeConsume(message ConsumerMessage) { + for i := range x { + x[i].BeforeConsume(message) + } +} + +func (x ConsumerInterceptors) OnAcknowledge(consumer Consumer, msgID MessageID) { + for i := range x { + x[i].OnAcknowledge(consumer, msgID) + } +} + +func (x ConsumerInterceptors) OnNegativeAcksSend(consumer Consumer, msgIDs []MessageID) { + for i := range x { + x[i].OnNegativeAcksSend(consumer, msgIDs) + } +} + +var defaultConsumerInterceptors = make(ConsumerInterceptors, 0) diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_multitopic.go b/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_multitopic.go new file mode 100644 index 00000000..8108c294 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_multitopic.go @@ -0,0 +1,267 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "github.com/apache/pulsar-client-go/pulsar/internal" + pkgerrors "github.com/pkg/errors" + + "github.com/apache/pulsar-client-go/pulsar/log" +) + +type multiTopicConsumer struct { + client *client + + options ConsumerOptions + + consumerName string + messageCh chan ConsumerMessage + + consumers map[string]Consumer + + dlq *dlqRouter + rlq *retryRouter + closeOnce sync.Once + closeCh chan struct{} + + log log.Logger +} + +func newMultiTopicConsumer(client *client, options ConsumerOptions, topics []string, + messageCh chan ConsumerMessage, dlq *dlqRouter, rlq *retryRouter) (Consumer, error) { + mtc := &multiTopicConsumer{ + client: client, + options: options, + messageCh: messageCh, + consumers: make(map[string]Consumer, len(topics)), + closeCh: make(chan struct{}), + dlq: dlq, + rlq: rlq, + log: client.log.SubLogger(log.Fields{"topic": topics}), + consumerName: options.Name, + } + + var errs error + for ce := range subscriber(client, topics, options, messageCh, dlq, rlq) { + if ce.err != nil { + errs = pkgerrors.Wrapf(ce.err, "unable to subscribe to topic=%s", ce.topic) + } else { + mtc.consumers[ce.topic] = ce.consumer + } + } + + if errs != nil { + for _, c := range mtc.consumers { + c.Close() + } + return nil, errs + } + + return mtc, nil +} + +func (c *multiTopicConsumer) Subscription() string { + return c.options.SubscriptionName +} + +func (c *multiTopicConsumer) Unsubscribe() error { + var errs error + for t, consumer := range c.consumers { + if err := consumer.Unsubscribe(); err != nil { + msg := fmt.Sprintf("unable to unsubscribe from topic=%s subscription=%s", + t, c.Subscription()) + errs = pkgerrors.Wrap(err, msg) + } + } + return errs +} + +func (c *multiTopicConsumer) Receive(ctx context.Context) (message Message, err error) { + for { + select { + case <-c.closeCh: + return nil, newError(ConsumerClosed, "consumer closed") + case cm, ok := <-c.messageCh: + if !ok { + return nil, newError(ConsumerClosed, "consumer closed") + } + return cm.Message, nil + case <-ctx.Done(): + return nil, ctx.Err() + } + } +} + +// Chan return the message chan to users +func (c *multiTopicConsumer) Chan() <-chan ConsumerMessage { + return c.messageCh +} + +// Ack the consumption of a single message +func (c *multiTopicConsumer) Ack(msg Message) error { + return c.AckID(msg.ID()) +} + +// AckID the consumption of a single message, identified by its MessageID +func (c *multiTopicConsumer) AckID(msgID MessageID) error { + if !checkMessageIDType(msgID) { + c.log.Warnf("invalid message id type %T", msgID) + return errors.New("invalid message id type in multi_consumer") + } + mid := toTrackingMessageID(msgID) + + if mid.consumer == nil { + c.log.Warnf("unable to ack messageID=%+v can not determine topic", msgID) + return errors.New("unable to ack message because consumer is nil") + } + + if c.options.AckWithResponse { + return mid.consumer.AckIDWithResponse(msgID) + } + + return mid.consumer.AckID(msgID) +} + +// AckCumulative the reception of all the messages in the stream up to (and including) +// the provided message +func (c *multiTopicConsumer) AckCumulative(msg Message) error { + return c.AckIDCumulative(msg.ID()) +} + +// AckIDCumulative the reception of all the messages in the stream up to (and including) +// the provided message, identified by its MessageID +func (c *multiTopicConsumer) AckIDCumulative(msgID MessageID) error { + if !checkMessageIDType(msgID) { + c.log.Warnf("invalid message id type %T", msgID) + return errors.New("invalid message id type in multi_consumer") + } + mid := toTrackingMessageID(msgID) + + if mid.consumer == nil { + c.log.Warnf("unable to ack messageID=%+v can not determine topic", msgID) + return errors.New("unable to ack message because consumer is nil") + } + + if c.options.AckWithResponse { + return mid.consumer.AckIDWithResponseCumulative(msgID) + } + + return mid.consumer.AckIDCumulative(msgID) +} + +func (c *multiTopicConsumer) ReconsumeLater(msg Message, delay time.Duration) { + c.ReconsumeLaterWithCustomProperties(msg, map[string]string{}, delay) +} + +func (c *multiTopicConsumer) ReconsumeLaterWithCustomProperties(msg Message, customProperties map[string]string, + delay time.Duration) { + names, err := validateTopicNames(msg.Topic()) + if err != nil { + c.log.Errorf("validate msg topic %q failed: %v", msg.Topic(), err) + return + } + if len(names) != 1 { + c.log.Errorf("invalid msg topic %q names: %+v ", msg.Topic(), names) + return + } + + tn := names[0] + fqdnTopic := internal.TopicNameWithoutPartitionPart(tn) + consumer, ok := c.consumers[fqdnTopic] + if !ok { + // check to see if the topic with the partition part is in the consumers + // this can happen when the consumer is configured to consume from a specific partition + if consumer, ok = c.consumers[tn.Name]; !ok { + c.log.Warnf("consumer of topic %s not exist unexpectedly", msg.Topic()) + return + } + } + consumer.ReconsumeLaterWithCustomProperties(msg, customProperties, delay) +} + +func (c *multiTopicConsumer) Nack(msg Message) { + if c.options.EnableDefaultNackBackoffPolicy || c.options.NackBackoffPolicy != nil { + msgID := msg.ID() + if !checkMessageIDType(msgID) { + c.log.Warnf("invalid message id type %T", msgID) + return + } + mid := toTrackingMessageID(msgID) + + if mid.consumer == nil { + c.log.Warnf("unable to nack messageID=%+v can not determine topic", msgID) + return + } + mid.NackByMsg(msg) + return + } + + c.NackID(msg.ID()) +} + +func (c *multiTopicConsumer) NackID(msgID MessageID) { + if !checkMessageIDType(msgID) { + c.log.Warnf("invalid message id type %T", msgID) + return + } + mid := toTrackingMessageID(msgID) + + if mid.consumer == nil { + c.log.Warnf("unable to nack messageID=%+v can not determine topic", msgID) + return + } + + mid.consumer.NackID(msgID) +} + +func (c *multiTopicConsumer) Close() { + c.closeOnce.Do(func() { + var wg sync.WaitGroup + wg.Add(len(c.consumers)) + for _, con := range c.consumers { + go func(consumer Consumer) { + defer wg.Done() + consumer.Close() + }(con) + } + wg.Wait() + close(c.closeCh) + c.client.handlers.Del(c) + c.dlq.close() + c.rlq.close() + }) +} + +func (c *multiTopicConsumer) Seek(msgID MessageID) error { + return newError(SeekFailed, "seek command not allowed for multi topic consumer") +} + +func (c *multiTopicConsumer) SeekByTime(time time.Time) error { + return newError(SeekFailed, "seek command not allowed for multi topic consumer") +} + +// Name returns the name of consumer. +func (c *multiTopicConsumer) Name() string { + return c.consumerName +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_partition.go b/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_partition.go new file mode 100644 index 00000000..fb77d0dc --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_partition.go @@ -0,0 +1,2129 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "container/list" + "encoding/hex" + "errors" + "fmt" + "math" + "strings" + "sync" + "time" + + "google.golang.org/protobuf/proto" + + "github.com/apache/pulsar-client-go/pulsar/crypto" + "github.com/apache/pulsar-client-go/pulsar/internal" + "github.com/apache/pulsar-client-go/pulsar/internal/compression" + cryptointernal "github.com/apache/pulsar-client-go/pulsar/internal/crypto" + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "github.com/apache/pulsar-client-go/pulsar/log" + "github.com/bits-and-blooms/bitset" + + uAtomic "go.uber.org/atomic" +) + +type consumerState int + +const ( + // consumer states + consumerInit = iota + consumerReady + consumerClosing + consumerClosed +) + +func (s consumerState) String() string { + switch s { + case consumerInit: + return "Initializing" + case consumerReady: + return "Ready" + case consumerClosing: + return "Closing" + case consumerClosed: + return "Closed" + default: + return "Unknown" + } +} + +type subscriptionMode int + +const ( + // Make the subscription to be backed by a durable cursor that will retain messages and persist the current + // position + durable subscriptionMode = iota + + // Lightweight subscription mode that doesn't have a durable cursor associated + nonDurable +) + +const ( + initialReceiverQueueSize = 1 + receiverQueueExpansionMemThreshold = 0.75 +) + +const ( + noMessageEntry = -1 +) + +type partitionConsumerOpts struct { + topic string + consumerName string + subscription string + subscriptionType SubscriptionType + subscriptionInitPos SubscriptionInitialPosition + partitionIdx int + receiverQueueSize int + autoReceiverQueueSize bool + nackRedeliveryDelay time.Duration + nackBackoffPolicy NackBackoffPolicy + metadata map[string]string + subProperties map[string]string + replicateSubscriptionState bool + startMessageID *trackingMessageID + startMessageIDInclusive bool + subscriptionMode subscriptionMode + readCompacted bool + disableForceTopicCreation bool + interceptors ConsumerInterceptors + maxReconnectToBroker *uint + backoffPolicy internal.BackoffPolicy + keySharedPolicy *KeySharedPolicy + schema Schema + decryption *MessageDecryptionInfo + ackWithResponse bool + maxPendingChunkedMessage int + expireTimeOfIncompleteChunk time.Duration + autoAckIncompleteChunk bool + // in failover mode, this callback will be called when consumer change + consumerEventListener ConsumerEventListener + enableBatchIndexAck bool + ackGroupingOptions *AckGroupingOptions +} + +type ConsumerEventListener interface { + BecameActive(consumer Consumer, topicName string, partition int32) + BecameInactive(consumer Consumer, topicName string, partition int32) +} + +type partitionConsumer struct { + client *client + + // this is needed for sending ConsumerMessage on the messageCh + parentConsumer Consumer + state uAtomic.Int32 + options *partitionConsumerOpts + + conn uAtomic.Value + + topic string + name string + consumerID uint64 + partitionIdx int32 + + // shared channel + messageCh chan ConsumerMessage + + // the number of message slots available + availablePermits *availablePermits + + // the size of the queue channel for buffering messages + maxQueueSize int32 + queueCh chan []*message + startMessageID atomicMessageID + lastDequeuedMsg *trackingMessageID + + currentQueueSize uAtomic.Int32 + scaleReceiverQueueHint uAtomic.Bool + incomingMessages uAtomic.Int32 + + eventsCh chan interface{} + connectedCh chan struct{} + connectClosedCh chan connectionClosed + closeCh chan struct{} + clearQueueCh chan func(id *trackingMessageID) + + nackTracker *negativeAcksTracker + dlq *dlqRouter + + log log.Logger + compressionProviders sync.Map //map[pb.CompressionType]compression.Provider + metrics *internal.LeveledMetrics + decryptor cryptointernal.Decryptor + schemaInfoCache *schemaInfoCache + + chunkedMsgCtxMap *chunkedMsgCtxMap + unAckChunksTracker *unAckChunksTracker + ackGroupingTracker ackGroupingTracker +} + +func (pc *partitionConsumer) ActiveConsumerChanged(isActive bool) { + listener := pc.options.consumerEventListener + if listener == nil { + // didn't set a listener + return + } + if isActive { + listener.BecameActive(pc.parentConsumer, pc.topic, pc.partitionIdx) + } else { + listener.BecameInactive(pc.parentConsumer, pc.topic, pc.partitionIdx) + } +} + +type availablePermits struct { + permits uAtomic.Int32 + pc *partitionConsumer +} + +func (p *availablePermits) inc() { + // atomic add availablePermits + p.add(1) +} + +func (p *availablePermits) add(delta int32) { + p.permits.Add(delta) + p.flowIfNeed() +} + +func (p *availablePermits) reset() { + p.permits.Store(0) +} + +func (p *availablePermits) get() int32 { + return p.permits.Load() +} + +func (p *availablePermits) flowIfNeed() { + // TODO implement a better flow controller + // send more permits if needed + var flowThreshold int32 + if p.pc.options.autoReceiverQueueSize { + flowThreshold = int32(math.Max(float64(p.pc.currentQueueSize.Load()/2), 1)) + } else { + flowThreshold = int32(math.Max(float64(p.pc.maxQueueSize/2), 1)) + } + + current := p.get() + if current >= flowThreshold { + availablePermits := current + requestedPermits := current + // check if permits changed + if !p.permits.CAS(current, 0) { + return + } + + p.pc.log.Debugf("requesting more permits=%d available=%d", requestedPermits, availablePermits) + if err := p.pc.internalFlow(uint32(requestedPermits)); err != nil { + p.pc.log.WithError(err).Error("unable to send permits") + } + } +} + +// atomicMessageID is a wrapper for trackingMessageID to make get and set atomic +type atomicMessageID struct { + msgID *trackingMessageID + sync.RWMutex +} + +func (a *atomicMessageID) get() *trackingMessageID { + a.RLock() + defer a.RUnlock() + return a.msgID +} + +func (a *atomicMessageID) set(msgID *trackingMessageID) { + a.Lock() + defer a.Unlock() + a.msgID = msgID +} + +type schemaInfoCache struct { + lock sync.RWMutex + cache map[string]Schema + client *client + topic string +} + +func newSchemaInfoCache(client *client, topic string) *schemaInfoCache { + return &schemaInfoCache{ + cache: make(map[string]Schema), + client: client, + topic: topic, + } +} + +func (s *schemaInfoCache) Get(schemaVersion []byte) (schema Schema, err error) { + key := hex.EncodeToString(schemaVersion) + s.lock.RLock() + schema, ok := s.cache[key] + s.lock.RUnlock() + if ok { + return schema, nil + } + + pbSchema, err := s.client.lookupService.GetSchema(s.topic, schemaVersion) + if err != nil { + return nil, err + } + + if pbSchema == nil { + err = fmt.Errorf("schema not found for topic: [ %v ], schema version : [ %v ]", s.topic, schemaVersion) + return nil, err + } + + var properties = internal.ConvertToStringMap(pbSchema.Properties) + + schema, err = NewSchema(SchemaType(*pbSchema.Type), pbSchema.SchemaData, properties) + if err != nil { + return nil, err + } + s.add(key, schema) + return schema, nil +} + +func (s *schemaInfoCache) add(schemaVersionHash string, schema Schema) { + s.lock.Lock() + defer s.lock.Unlock() + + s.cache[schemaVersionHash] = schema +} + +func newPartitionConsumer(parent Consumer, client *client, options *partitionConsumerOpts, + messageCh chan ConsumerMessage, dlq *dlqRouter, + metrics *internal.LeveledMetrics) (*partitionConsumer, error) { + pc := &partitionConsumer{ + parentConsumer: parent, + client: client, + options: options, + topic: options.topic, + name: options.consumerName, + consumerID: client.rpcClient.NewConsumerID(), + partitionIdx: int32(options.partitionIdx), + eventsCh: make(chan interface{}, 10), + maxQueueSize: int32(options.receiverQueueSize), + queueCh: make(chan []*message, options.receiverQueueSize), + startMessageID: atomicMessageID{msgID: options.startMessageID}, + connectedCh: make(chan struct{}), + messageCh: messageCh, + connectClosedCh: make(chan connectionClosed, 10), + closeCh: make(chan struct{}), + clearQueueCh: make(chan func(id *trackingMessageID)), + compressionProviders: sync.Map{}, + dlq: dlq, + metrics: metrics, + schemaInfoCache: newSchemaInfoCache(client, options.topic), + } + if pc.options.autoReceiverQueueSize { + pc.currentQueueSize.Store(initialReceiverQueueSize) + pc.client.memLimit.RegisterTrigger(pc.shrinkReceiverQueueSize) + } else { + pc.currentQueueSize.Store(int32(pc.options.receiverQueueSize)) + } + pc.availablePermits = &availablePermits{pc: pc} + pc.chunkedMsgCtxMap = newChunkedMsgCtxMap(options.maxPendingChunkedMessage, pc) + pc.unAckChunksTracker = newUnAckChunksTracker(pc) + pc.ackGroupingTracker = newAckGroupingTracker(options.ackGroupingOptions, + func(id MessageID) { pc.sendIndividualAck(id) }, + func(id MessageID) { pc.sendCumulativeAck(id) }, + func(ids []*pb.MessageIdData) { pc.eventsCh <- ids }) + pc.setConsumerState(consumerInit) + pc.log = client.log.SubLogger(log.Fields{ + "name": pc.name, + "topic": options.topic, + "subscription": options.subscription, + "consumerID": pc.consumerID, + }) + + var decryptor cryptointernal.Decryptor + if pc.options.decryption == nil { + decryptor = cryptointernal.NewNoopDecryptor() // default to noopDecryptor + } else { + decryptor = cryptointernal.NewConsumerDecryptor( + options.decryption.KeyReader, + options.decryption.MessageCrypto, + pc.log, + ) + } + + pc.decryptor = decryptor + + pc.nackTracker = newNegativeAcksTracker(pc, options.nackRedeliveryDelay, options.nackBackoffPolicy, pc.log) + + err := pc.grabConn() + if err != nil { + pc.log.WithError(err).Error("Failed to create consumer") + pc.nackTracker.Close() + return nil, err + } + pc.log.Info("Created consumer") + pc.setConsumerState(consumerReady) + + startingMessageID := pc.startMessageID.get() + if pc.options.startMessageIDInclusive && startingMessageID != nil && startingMessageID.equal(latestMessageID) { + msgID, err := pc.requestGetLastMessageID() + if err != nil { + pc.nackTracker.Close() + return nil, err + } + if msgID.entryID != noMessageEntry { + pc.startMessageID.set(msgID) + + // use the WithoutClear version because the dispatcher is not started yet + err = pc.requestSeekWithoutClear(msgID.messageID) + if err != nil { + pc.nackTracker.Close() + return nil, err + } + } + } + + go pc.dispatcher() + + go pc.runEventsLoop() + + return pc, nil +} + +func (pc *partitionConsumer) Unsubscribe() error { + if state := pc.getConsumerState(); state == consumerClosed || state == consumerClosing { + pc.log.WithField("state", state).Error("Failed to unsubscribe closing or closed consumer") + return nil + } + + req := &unsubscribeRequest{doneCh: make(chan struct{})} + pc.eventsCh <- req + + // wait for the request to complete + <-req.doneCh + return req.err +} + +func (pc *partitionConsumer) internalUnsubscribe(unsub *unsubscribeRequest) { + defer close(unsub.doneCh) + + if state := pc.getConsumerState(); state == consumerClosed || state == consumerClosing { + pc.log.WithField("state", state).Error("Failed to unsubscribe closing or closed consumer") + return + } + + pc.setConsumerState(consumerClosing) + requestID := pc.client.rpcClient.NewRequestID() + cmdUnsubscribe := &pb.CommandUnsubscribe{ + RequestId: proto.Uint64(requestID), + ConsumerId: proto.Uint64(pc.consumerID), + } + _, err := pc.client.rpcClient.RequestOnCnx(pc._getConn(), requestID, pb.BaseCommand_UNSUBSCRIBE, cmdUnsubscribe) + if err != nil { + pc.log.WithError(err).Error("Failed to unsubscribe consumer") + unsub.err = err + // Set the state to ready for closing the consumer + pc.setConsumerState(consumerReady) + // Should'nt remove the consumer handler + return + } + + pc._getConn().DeleteConsumeHandler(pc.consumerID) + if pc.nackTracker != nil { + pc.nackTracker.Close() + } + pc.log.Infof("The consumer[%d] successfully unsubscribed", pc.consumerID) + pc.setConsumerState(consumerClosed) +} + +func (pc *partitionConsumer) getLastMessageID() (*trackingMessageID, error) { + if state := pc.getConsumerState(); state == consumerClosed || state == consumerClosing { + pc.log.WithField("state", state).Error("Failed to redeliver closing or closed consumer") + return nil, errors.New("failed to redeliver closing or closed consumer") + } + req := &getLastMsgIDRequest{doneCh: make(chan struct{})} + pc.eventsCh <- req + + // wait for the request to complete + <-req.doneCh + return req.msgID, req.err +} + +func (pc *partitionConsumer) internalGetLastMessageID(req *getLastMsgIDRequest) { + defer close(req.doneCh) + req.msgID, req.err = pc.requestGetLastMessageID() +} + +func (pc *partitionConsumer) requestGetLastMessageID() (*trackingMessageID, error) { + if state := pc.getConsumerState(); state == consumerClosed || state == consumerClosing { + pc.log.WithField("state", state).Error("Failed to getLastMessageID closing or closed consumer") + return nil, errors.New("failed to getLastMessageID closing or closed consumer") + } + + requestID := pc.client.rpcClient.NewRequestID() + cmdGetLastMessageID := &pb.CommandGetLastMessageId{ + RequestId: proto.Uint64(requestID), + ConsumerId: proto.Uint64(pc.consumerID), + } + res, err := pc.client.rpcClient.RequestOnCnx(pc._getConn(), requestID, + pb.BaseCommand_GET_LAST_MESSAGE_ID, cmdGetLastMessageID) + if err != nil { + pc.log.WithError(err).Error("Failed to get last message id") + return nil, err + } + id := res.Response.GetLastMessageIdResponse.GetLastMessageId() + return convertToMessageID(id), nil +} + +func (pc *partitionConsumer) ackID(msgID MessageID, withResponse bool) error { + if state := pc.getConsumerState(); state == consumerClosed || state == consumerClosing { + pc.log.WithField("state", state).Error("Failed to ack by closing or closed consumer") + return errors.New("consumer state is closed") + } + + if cmid, ok := msgID.(*chunkMessageID); ok { + return pc.unAckChunksTracker.ack(cmid) + } + + trackingID := toTrackingMessageID(msgID) + + if trackingID != nil && trackingID.ack() { + // All messages in the same batch have been acknowledged, we only need to acknowledge the + // MessageID that represents the entry that stores the whole batch + trackingID = &trackingMessageID{ + messageID: &messageID{ + ledgerID: trackingID.ledgerID, + entryID: trackingID.entryID, + }, + } + pc.metrics.AcksCounter.Inc() + pc.metrics.ProcessingTime.Observe(float64(time.Now().UnixNano()-trackingID.receivedTime.UnixNano()) / 1.0e9) + } else if !pc.options.enableBatchIndexAck { + return nil + } + + var ackReq *ackRequest + if withResponse { + ackReq := pc.sendIndividualAck(trackingID) + <-ackReq.doneCh + } else { + pc.ackGroupingTracker.add(trackingID) + } + pc.options.interceptors.OnAcknowledge(pc.parentConsumer, msgID) + if ackReq == nil { + return nil + } + return ackReq.err +} + +func (pc *partitionConsumer) sendIndividualAck(msgID MessageID) *ackRequest { + ackReq := &ackRequest{ + doneCh: make(chan struct{}), + ackType: individualAck, + msgID: *msgID.(*trackingMessageID), + } + pc.eventsCh <- ackReq + return ackReq +} + +func (pc *partitionConsumer) AckIDWithResponse(msgID MessageID) error { + if !checkMessageIDType(msgID) { + pc.log.Errorf("invalid message id type %T", msgID) + return fmt.Errorf("invalid message id type %T", msgID) + } + return pc.ackID(msgID, true) +} + +func (pc *partitionConsumer) AckID(msgID MessageID) error { + if !checkMessageIDType(msgID) { + pc.log.Errorf("invalid message id type %T", msgID) + return fmt.Errorf("invalid message id type %T", msgID) + } + return pc.ackID(msgID, false) +} + +func (pc *partitionConsumer) AckIDCumulative(msgID MessageID) error { + if !checkMessageIDType(msgID) { + pc.log.Errorf("invalid message id type %T", msgID) + return fmt.Errorf("invalid message id type %T", msgID) + } + return pc.internalAckIDCumulative(msgID, false) +} + +func (pc *partitionConsumer) AckIDWithResponseCumulative(msgID MessageID) error { + if !checkMessageIDType(msgID) { + pc.log.Errorf("invalid message id type %T", msgID) + return fmt.Errorf("invalid message id type %T", msgID) + } + return pc.internalAckIDCumulative(msgID, true) +} + +func (pc *partitionConsumer) internalAckIDCumulative(msgID MessageID, withResponse bool) error { + if state := pc.getConsumerState(); state == consumerClosed || state == consumerClosing { + pc.log.WithField("state", state).Error("Failed to ack by closing or closed consumer") + return errors.New("consumer state is closed") + } + + // chunk message id will be converted to tracking message id + trackingID := toTrackingMessageID(msgID) + if trackingID == nil { + return errors.New("failed to convert trackingMessageID") + } + + var msgIDToAck *trackingMessageID + if trackingID.ackCumulative() || pc.options.enableBatchIndexAck { + msgIDToAck = trackingID + } else if !trackingID.tracker.hasPrevBatchAcked() { + // get previous batch message id + msgIDToAck = trackingID.prev() + trackingID.tracker.setPrevBatchAcked() + } else { + // waiting for all the msgs are acked in this batch + return nil + } + + pc.metrics.AcksCounter.Inc() + pc.metrics.ProcessingTime.Observe(float64(time.Now().UnixNano()-trackingID.receivedTime.UnixNano()) / 1.0e9) + + var ackReq *ackRequest + if withResponse { + ackReq := pc.sendCumulativeAck(msgIDToAck) + <-ackReq.doneCh + } else { + pc.ackGroupingTracker.addCumulative(msgIDToAck) + } + + pc.options.interceptors.OnAcknowledge(pc.parentConsumer, msgID) + + if cmid, ok := msgID.(*chunkMessageID); ok { + pc.unAckChunksTracker.remove(cmid) + } + + if ackReq == nil { + return nil + } + return ackReq.err +} + +func (pc *partitionConsumer) sendCumulativeAck(msgID MessageID) *ackRequest { + ackReq := &ackRequest{ + doneCh: make(chan struct{}), + ackType: cumulativeAck, + msgID: *msgID.(*trackingMessageID), + } + pc.eventsCh <- ackReq + return ackReq +} + +func (pc *partitionConsumer) NackID(msgID MessageID) { + if !checkMessageIDType(msgID) { + pc.log.Warnf("invalid message id type %T", msgID) + return + } + + if cmid, ok := msgID.(*chunkMessageID); ok { + pc.unAckChunksTracker.nack(cmid) + return + } + + trackingID := toTrackingMessageID(msgID) + + pc.nackTracker.Add(trackingID.messageID) + pc.metrics.NacksCounter.Inc() +} + +func (pc *partitionConsumer) NackMsg(msg Message) { + pc.nackTracker.AddMessage(msg) + pc.metrics.NacksCounter.Inc() +} + +func (pc *partitionConsumer) Redeliver(msgIds []messageID) { + if state := pc.getConsumerState(); state == consumerClosed || state == consumerClosing { + pc.log.WithField("state", state).Error("Failed to redeliver closing or closed consumer") + return + } + pc.eventsCh <- &redeliveryRequest{msgIds} + + iMsgIds := make([]MessageID, len(msgIds)) + for i := range iMsgIds { + iMsgIds[i] = &msgIds[i] + } + pc.options.interceptors.OnNegativeAcksSend(pc.parentConsumer, iMsgIds) +} + +func (pc *partitionConsumer) internalRedeliver(req *redeliveryRequest) { + if state := pc.getConsumerState(); state == consumerClosed || state == consumerClosing { + pc.log.WithField("state", state).Error("Failed to redeliver closing or closed consumer") + return + } + msgIds := req.msgIds + pc.log.Debug("Request redelivery after negative ack for messages", msgIds) + + msgIDDataList := make([]*pb.MessageIdData, len(msgIds)) + for i := 0; i < len(msgIds); i++ { + msgIDDataList[i] = &pb.MessageIdData{ + LedgerId: proto.Uint64(uint64(msgIds[i].ledgerID)), + EntryId: proto.Uint64(uint64(msgIds[i].entryID)), + } + } + + err := pc.client.rpcClient.RequestOnCnxNoWait(pc._getConn(), + pb.BaseCommand_REDELIVER_UNACKNOWLEDGED_MESSAGES, &pb.CommandRedeliverUnacknowledgedMessages{ + ConsumerId: proto.Uint64(pc.consumerID), + MessageIds: msgIDDataList, + }) + if err != nil { + pc.log.Error("Connection was closed when request redeliver cmd") + } +} + +func (pc *partitionConsumer) getConsumerState() consumerState { + return consumerState(pc.state.Load()) +} + +func (pc *partitionConsumer) setConsumerState(state consumerState) { + pc.state.Store(int32(state)) +} + +func (pc *partitionConsumer) Close() { + + if pc.getConsumerState() != consumerReady { + return + } + + // flush all pending ACK requests and terminate the timer goroutine + pc.ackGroupingTracker.close() + + // close chunkedMsgCtxMap + pc.chunkedMsgCtxMap.Close() + + req := &closeRequest{doneCh: make(chan struct{})} + pc.eventsCh <- req + + // wait for request to finish + <-req.doneCh +} + +func (pc *partitionConsumer) Seek(msgID MessageID) error { + if state := pc.getConsumerState(); state == consumerClosed || state == consumerClosing { + pc.log.WithField("state", state).Error("Failed to seek by closing or closed consumer") + return errors.New("failed to seek by closing or closed consumer") + } + + if !checkMessageIDType(msgID) { + pc.log.Errorf("invalid message id type %T", msgID) + return fmt.Errorf("invalid message id type %T", msgID) + } + + req := &seekRequest{ + doneCh: make(chan struct{}), + } + if cmid, ok := msgID.(*chunkMessageID); ok { + req.msgID = cmid.firstChunkID + } else { + tmid := toTrackingMessageID(msgID) + req.msgID = tmid.messageID + } + + pc.ackGroupingTracker.flushAndClean() + pc.eventsCh <- req + + // wait for the request to complete + <-req.doneCh + return req.err +} + +func (pc *partitionConsumer) internalSeek(seek *seekRequest) { + defer close(seek.doneCh) + seek.err = pc.requestSeek(seek.msgID) +} +func (pc *partitionConsumer) requestSeek(msgID *messageID) error { + if err := pc.requestSeekWithoutClear(msgID); err != nil { + return err + } + pc.clearReceiverQueue() + return nil +} + +func (pc *partitionConsumer) requestSeekWithoutClear(msgID *messageID) error { + state := pc.getConsumerState() + if state == consumerClosing || state == consumerClosed { + pc.log.WithField("state", state).Error("failed seek by consumer is closing or has closed") + return nil + } + + id := &pb.MessageIdData{} + err := proto.Unmarshal(msgID.Serialize(), id) + if err != nil { + pc.log.WithError(err).Errorf("deserialize message id error: %s", err.Error()) + return err + } + + requestID := pc.client.rpcClient.NewRequestID() + cmdSeek := &pb.CommandSeek{ + ConsumerId: proto.Uint64(pc.consumerID), + RequestId: proto.Uint64(requestID), + MessageId: id, + } + + _, err = pc.client.rpcClient.RequestOnCnx(pc._getConn(), requestID, pb.BaseCommand_SEEK, cmdSeek) + if err != nil { + pc.log.WithError(err).Error("Failed to reset to message id") + return err + } + return nil +} + +func (pc *partitionConsumer) SeekByTime(time time.Time) error { + if state := pc.getConsumerState(); state == consumerClosing || state == consumerClosed { + pc.log.WithField("state", pc.state).Error("Failed seekByTime by consumer is closing or has closed") + return errors.New("failed seekByTime by consumer is closing or has closed") + } + req := &seekByTimeRequest{ + doneCh: make(chan struct{}), + publishTime: time, + } + pc.ackGroupingTracker.flushAndClean() + pc.eventsCh <- req + + // wait for the request to complete + <-req.doneCh + return req.err +} + +func (pc *partitionConsumer) internalSeekByTime(seek *seekByTimeRequest) { + defer close(seek.doneCh) + + state := pc.getConsumerState() + if state == consumerClosing || state == consumerClosed { + pc.log.WithField("state", pc.state).Error("Failed seekByTime by consumer is closing or has closed") + return + } + + requestID := pc.client.rpcClient.NewRequestID() + cmdSeek := &pb.CommandSeek{ + ConsumerId: proto.Uint64(pc.consumerID), + RequestId: proto.Uint64(requestID), + MessagePublishTime: proto.Uint64(uint64(seek.publishTime.UnixNano() / int64(time.Millisecond))), + } + + _, err := pc.client.rpcClient.RequestOnCnx(pc._getConn(), requestID, pb.BaseCommand_SEEK, cmdSeek) + if err != nil { + pc.log.WithError(err).Error("Failed to reset to message publish time") + seek.err = err + return + } + pc.clearReceiverQueue() +} + +func (pc *partitionConsumer) internalAck(req *ackRequest) { + defer close(req.doneCh) + if state := pc.getConsumerState(); state == consumerClosed || state == consumerClosing { + pc.log.WithField("state", state).Error("Failed to ack by closing or closed consumer") + return + } + msgID := req.msgID + + messageIDs := make([]*pb.MessageIdData, 1) + messageIDs[0] = &pb.MessageIdData{ + LedgerId: proto.Uint64(uint64(msgID.ledgerID)), + EntryId: proto.Uint64(uint64(msgID.entryID)), + } + if pc.options.enableBatchIndexAck && msgID.tracker != nil { + ackSet := msgID.tracker.toAckSet() + if ackSet != nil { + messageIDs[0].AckSet = ackSet + } + } + + reqID := pc.client.rpcClient.NewRequestID() + cmdAck := &pb.CommandAck{ + ConsumerId: proto.Uint64(pc.consumerID), + MessageId: messageIDs, + } + + switch req.ackType { + case individualAck: + cmdAck.AckType = pb.CommandAck_Individual.Enum() + case cumulativeAck: + cmdAck.AckType = pb.CommandAck_Cumulative.Enum() + } + + if pc.options.ackWithResponse { + cmdAck.RequestId = proto.Uint64(reqID) + _, err := pc.client.rpcClient.RequestOnCnx(pc._getConn(), reqID, pb.BaseCommand_ACK, cmdAck) + if err != nil { + pc.log.WithError(err).Error("Ack with response error") + req.err = err + } + return + } + + err := pc.client.rpcClient.RequestOnCnxNoWait(pc._getConn(), pb.BaseCommand_ACK, cmdAck) + if err != nil { + pc.log.Error("Connection was closed when request ack cmd") + req.err = err + } +} + +func (pc *partitionConsumer) internalAckList(msgIDs []*pb.MessageIdData) { + pc.client.rpcClient.RequestOnCnxNoWait(pc._getConn(), pb.BaseCommand_ACK, &pb.CommandAck{ + AckType: pb.CommandAck_Individual.Enum(), + ConsumerId: proto.Uint64(pc.consumerID), + MessageId: msgIDs, + }) +} + +func (pc *partitionConsumer) MessageReceived(response *pb.CommandMessage, headersAndPayload internal.Buffer) error { + pbMsgID := response.GetMessageId() + + reader := internal.NewMessageReader(headersAndPayload) + brokerMetadata, err := reader.ReadBrokerMetadata() + if err != nil { + // todo optimize use more appropriate error codes + pc.discardCorruptedMessage(pbMsgID, pb.CommandAck_BatchDeSerializeError) + return err + } + msgMeta, err := reader.ReadMessageMetadata() + if err != nil { + pc.discardCorruptedMessage(pbMsgID, pb.CommandAck_ChecksumMismatch) + return err + } + decryptedPayload, err := pc.decryptor.Decrypt(headersAndPayload.ReadableSlice(), pbMsgID, msgMeta) + // error decrypting the payload + if err != nil { + // default crypto failure action + crypToFailureAction := crypto.ConsumerCryptoFailureActionFail + if pc.options.decryption != nil { + crypToFailureAction = pc.options.decryption.ConsumerCryptoFailureAction + } + + switch crypToFailureAction { + case crypto.ConsumerCryptoFailureActionFail: + pc.log.Errorf("consuming message failed due to decryption err :%v", err) + pc.NackID(newTrackingMessageID(int64(pbMsgID.GetLedgerId()), int64(pbMsgID.GetEntryId()), 0, 0, 0, nil)) + return err + case crypto.ConsumerCryptoFailureActionDiscard: + pc.discardCorruptedMessage(pbMsgID, pb.CommandAck_DecryptionError) + return fmt.Errorf("discarding message on decryption error :%v", err) + case crypto.ConsumerCryptoFailureActionConsume: + pc.log.Warnf("consuming encrypted message due to error in decryption :%v", err) + messages := []*message{ + { + publishTime: timeFromUnixTimestampMillis(msgMeta.GetPublishTime()), + eventTime: timeFromUnixTimestampMillis(msgMeta.GetEventTime()), + key: msgMeta.GetPartitionKey(), + producerName: msgMeta.GetProducerName(), + properties: internal.ConvertToStringMap(msgMeta.GetProperties()), + topic: pc.topic, + msgID: newMessageID( + int64(pbMsgID.GetLedgerId()), + int64(pbMsgID.GetEntryId()), + pbMsgID.GetBatchIndex(), + pc.partitionIdx, + pbMsgID.GetBatchSize(), + ), + payLoad: headersAndPayload.ReadableSlice(), + schema: pc.options.schema, + replicationClusters: msgMeta.GetReplicateTo(), + replicatedFrom: msgMeta.GetReplicatedFrom(), + redeliveryCount: response.GetRedeliveryCount(), + encryptionContext: createEncryptionContext(msgMeta), + orderingKey: string(msgMeta.OrderingKey), + }, + } + + if pc.options.autoReceiverQueueSize { + pc.incomingMessages.Inc() + pc.markScaleIfNeed() + } + + pc.queueCh <- messages + return nil + } + } + + isChunkedMsg := false + if msgMeta.GetNumChunksFromMsg() > 1 { + isChunkedMsg = true + } + + processedPayloadBuffer := internal.NewBufferWrapper(decryptedPayload) + if isChunkedMsg { + processedPayloadBuffer = pc.processMessageChunk(processedPayloadBuffer, msgMeta, pbMsgID) + if processedPayloadBuffer == nil { + return nil + } + } + + // decryption is success, decompress the payload + uncompressedHeadersAndPayload, err := pc.Decompress(msgMeta, processedPayloadBuffer) + if err != nil { + pc.discardCorruptedMessage(pbMsgID, pb.CommandAck_DecompressionError) + return err + } + + // Reset the reader on the uncompressed buffer + reader.ResetBuffer(uncompressedHeadersAndPayload) + + numMsgs := 1 + if msgMeta.NumMessagesInBatch != nil { + numMsgs = int(msgMeta.GetNumMessagesInBatch()) + } + + messages := make([]*message, 0) + var ackTracker *ackTracker + // are there multiple messages in this batch? + if numMsgs > 1 { + ackTracker = newAckTracker(uint(numMsgs)) + } + + var ackSet *bitset.BitSet + if response.GetAckSet() != nil { + ackSetFromResponse := response.GetAckSet() + buf := make([]uint64, len(ackSetFromResponse)) + for i := 0; i < len(buf); i++ { + buf[i] = uint64(ackSetFromResponse[i]) + } + ackSet = bitset.From(buf) + } + + pc.metrics.MessagesReceived.Add(float64(numMsgs)) + pc.metrics.PrefetchedMessages.Add(float64(numMsgs)) + + var bytesReceived int + for i := 0; i < numMsgs; i++ { + smm, payload, err := reader.ReadMessage() + if err != nil || payload == nil { + pc.discardCorruptedMessage(pbMsgID, pb.CommandAck_BatchDeSerializeError) + return err + } + if ackSet != nil && !ackSet.Test(uint(i)) { + pc.log.Debugf("Ignoring message from %vth message, which has been acknowledged", i) + continue + } + + pc.metrics.BytesReceived.Add(float64(len(payload))) + pc.metrics.PrefetchedBytes.Add(float64(len(payload))) + + trackingMsgID := newTrackingMessageID( + int64(pbMsgID.GetLedgerId()), + int64(pbMsgID.GetEntryId()), + int32(i), + pc.partitionIdx, + int32(numMsgs), + ackTracker) + // set the consumer so we know how to ack the message id + trackingMsgID.consumer = pc + + if pc.messageShouldBeDiscarded(trackingMsgID) { + pc.AckID(trackingMsgID) + continue + } + + var msgID MessageID + if isChunkedMsg { + ctx := pc.chunkedMsgCtxMap.get(msgMeta.GetUuid()) + if ctx == nil { + // chunkedMsgCtxMap has closed because of consumer closed + pc.log.Warnf("get chunkedMsgCtx for chunk with uuid %s failed because consumer has closed", + msgMeta.Uuid) + return nil + } + cmid := newChunkMessageID(ctx.firstChunkID(), ctx.lastChunkID()) + // set the consumer so we know how to ack the message id + cmid.consumer = pc + // clean chunkedMsgCtxMap + pc.chunkedMsgCtxMap.remove(msgMeta.GetUuid()) + pc.unAckChunksTracker.add(cmid, ctx.chunkedMsgIDs) + msgID = cmid + } else { + msgID = trackingMsgID + } + + if pc.ackGroupingTracker.isDuplicate(msgID) { + continue + } + + var messageIndex *uint64 + var brokerPublishTime *time.Time + if brokerMetadata != nil { + if brokerMetadata.Index != nil { + aux := brokerMetadata.GetIndex() - uint64(numMsgs) + uint64(i) + 1 + messageIndex = &aux + } + if brokerMetadata.BrokerTimestamp != nil { + aux := timeFromUnixTimestampMillis(*brokerMetadata.BrokerTimestamp) + brokerPublishTime = &aux + } + } + + var msg *message + if smm != nil { + msg = &message{ + publishTime: timeFromUnixTimestampMillis(msgMeta.GetPublishTime()), + eventTime: timeFromUnixTimestampMillis(smm.GetEventTime()), + key: smm.GetPartitionKey(), + producerName: msgMeta.GetProducerName(), + properties: internal.ConvertToStringMap(smm.GetProperties()), + topic: pc.topic, + msgID: msgID, + payLoad: payload, + schema: pc.options.schema, + replicationClusters: msgMeta.GetReplicateTo(), + replicatedFrom: msgMeta.GetReplicatedFrom(), + redeliveryCount: response.GetRedeliveryCount(), + schemaVersion: msgMeta.GetSchemaVersion(), + schemaInfoCache: pc.schemaInfoCache, + orderingKey: string(smm.OrderingKey), + index: messageIndex, + brokerPublishTime: brokerPublishTime, + } + } else { + msg = &message{ + publishTime: timeFromUnixTimestampMillis(msgMeta.GetPublishTime()), + eventTime: timeFromUnixTimestampMillis(msgMeta.GetEventTime()), + key: msgMeta.GetPartitionKey(), + producerName: msgMeta.GetProducerName(), + properties: internal.ConvertToStringMap(msgMeta.GetProperties()), + topic: pc.topic, + msgID: msgID, + payLoad: payload, + schema: pc.options.schema, + replicationClusters: msgMeta.GetReplicateTo(), + replicatedFrom: msgMeta.GetReplicatedFrom(), + redeliveryCount: response.GetRedeliveryCount(), + schemaVersion: msgMeta.GetSchemaVersion(), + schemaInfoCache: pc.schemaInfoCache, + index: messageIndex, + brokerPublishTime: brokerPublishTime, + } + } + + pc.options.interceptors.BeforeConsume(ConsumerMessage{ + Consumer: pc.parentConsumer, + Message: msg, + }) + + messages = append(messages, msg) + bytesReceived += msg.size() + } + + if pc.options.autoReceiverQueueSize { + pc.client.memLimit.ForceReserveMemory(int64(bytesReceived)) + pc.incomingMessages.Add(int32(len(messages))) + pc.markScaleIfNeed() + } + + // send messages to the dispatcher + pc.queueCh <- messages + return nil +} + +func (pc *partitionConsumer) processMessageChunk(compressedPayload internal.Buffer, + msgMeta *pb.MessageMetadata, + pbMsgID *pb.MessageIdData) internal.Buffer { + uuid := msgMeta.GetUuid() + numChunks := msgMeta.GetNumChunksFromMsg() + totalChunksSize := int(msgMeta.GetTotalChunkMsgSize()) + chunkID := msgMeta.GetChunkId() + msgID := &messageID{ + ledgerID: int64(pbMsgID.GetLedgerId()), + entryID: int64(pbMsgID.GetEntryId()), + batchIdx: -1, + partitionIdx: pc.partitionIdx, + } + + if msgMeta.GetChunkId() == 0 { + pc.chunkedMsgCtxMap.addIfAbsent(uuid, + numChunks, + totalChunksSize, + ) + } + + ctx := pc.chunkedMsgCtxMap.get(uuid) + + if ctx == nil || ctx.chunkedMsgBuffer == nil || chunkID != ctx.lastChunkedMsgID+1 { + lastChunkedMsgID := -1 + totalChunks := -1 + if ctx != nil { + lastChunkedMsgID = int(ctx.lastChunkedMsgID) + totalChunks = int(ctx.totalChunks) + ctx.chunkedMsgBuffer.Clear() + } + pc.log.Warnf(fmt.Sprintf( + "Received unexpected chunk messageId %s, last-chunk-id %d, chunkId = %d, total-chunks %d", + msgID.String(), lastChunkedMsgID, chunkID, totalChunks)) + pc.chunkedMsgCtxMap.remove(uuid) + pc.availablePermits.inc() + return nil + } + + ctx.append(chunkID, msgID, compressedPayload) + + if msgMeta.GetChunkId() != msgMeta.GetNumChunksFromMsg()-1 { + pc.availablePermits.inc() + return nil + } + + return ctx.chunkedMsgBuffer +} + +func (pc *partitionConsumer) messageShouldBeDiscarded(msgID *trackingMessageID) bool { + if pc.startMessageID.get() == nil { + return false + } + // if we start at latest message, we should never discard + if pc.options.startMessageID != nil && pc.options.startMessageID.equal(latestMessageID) { + return false + } + + if pc.options.startMessageIDInclusive { + return pc.startMessageID.get().greater(msgID.messageID) + } + + // Non inclusive + return pc.startMessageID.get().greaterEqual(msgID.messageID) +} + +// create EncryptionContext from message metadata +// this will be used to decrypt the message payload outside of this client +// it is the responsibility of end user to decrypt the payload +// It will be used only when crypto failure action is set to consume i.e crypto.ConsumerCryptoFailureActionConsume +func createEncryptionContext(msgMeta *pb.MessageMetadata) *EncryptionContext { + encCtx := EncryptionContext{ + Algorithm: msgMeta.GetEncryptionAlgo(), + Param: msgMeta.GetEncryptionParam(), + UncompressedSize: int(msgMeta.GetUncompressedSize()), + BatchSize: int(msgMeta.GetNumMessagesInBatch()), + } + + if msgMeta.Compression != nil { + encCtx.CompressionType = CompressionType(*msgMeta.Compression) + } + + keyMap := map[string]EncryptionKey{} + for _, k := range msgMeta.GetEncryptionKeys() { + metaMap := map[string]string{} + for _, m := range k.GetMetadata() { + metaMap[*m.Key] = *m.Value + } + + keyMap[*k.Key] = EncryptionKey{ + KeyValue: k.GetValue(), + Metadata: metaMap, + } + } + + encCtx.Keys = keyMap + return &encCtx +} + +func (pc *partitionConsumer) ConnectionClosed() { + // Trigger reconnection in the consumer goroutine + pc.log.Debug("connection closed and send to connectClosedCh") + pc.connectClosedCh <- connectionClosed{} +} + +// Flow command gives additional permits to send messages to the consumer. +// A typical consumer implementation will use a queue to accumulate these messages +// before the application is ready to consume them. After the consumer is ready, +// the client needs to give permission to the broker to push messages. +func (pc *partitionConsumer) internalFlow(permits uint32) error { + if state := pc.getConsumerState(); state == consumerClosed || state == consumerClosing { + pc.log.WithField("state", state).Error("Failed to redeliver closing or closed consumer") + return errors.New("consumer closing or closed") + } + if permits == 0 { + return fmt.Errorf("invalid number of permits requested: %d", permits) + } + + cmdFlow := &pb.CommandFlow{ + ConsumerId: proto.Uint64(pc.consumerID), + MessagePermits: proto.Uint32(permits), + } + err := pc.client.rpcClient.RequestOnCnxNoWait(pc._getConn(), pb.BaseCommand_FLOW, cmdFlow) + if err != nil { + pc.log.Error("Connection was closed when request flow cmd") + return err + } + + return nil +} + +// dispatcher manages the internal message queue channel +// and manages the flow control +func (pc *partitionConsumer) dispatcher() { + defer func() { + pc.log.Debug("exiting dispatch loop") + }() + var messages []*message + for { + var queueCh chan []*message + var messageCh chan ConsumerMessage + var nextMessage ConsumerMessage + var nextMessageSize int + + // are there more messages to send? + if len(messages) > 0 { + nextMessage = ConsumerMessage{ + Consumer: pc.parentConsumer, + Message: messages[0], + } + nextMessageSize = messages[0].size() + + if pc.dlq.shouldSendToDlq(&nextMessage) { + // pass the message to the DLQ router + pc.metrics.DlqCounter.Inc() + messageCh = pc.dlq.Chan() + } else { + // pass the message to application channel + messageCh = pc.messageCh + } + + pc.metrics.PrefetchedMessages.Dec() + pc.metrics.PrefetchedBytes.Sub(float64(len(messages[0].payLoad))) + } else { + queueCh = pc.queueCh + } + + select { + case <-pc.closeCh: + return + + case _, ok := <-pc.connectedCh: + if !ok { + return + } + pc.log.Debug("dispatcher received connection event") + + messages = nil + + // reset available permits + pc.availablePermits.reset() + + var initialPermits uint32 + if pc.options.autoReceiverQueueSize { + initialPermits = uint32(pc.currentQueueSize.Load()) + } else { + initialPermits = uint32(pc.maxQueueSize) + } + + pc.log.Debugf("dispatcher requesting initial permits=%d", initialPermits) + // send initial permits + if err := pc.internalFlow(initialPermits); err != nil { + pc.log.WithError(err).Error("unable to send initial permits to broker") + } + + case msgs, ok := <-queueCh: + if !ok { + return + } + // we only read messages here after the consumer has processed all messages + // in the previous batch + messages = msgs + + // if the messageCh is nil or the messageCh is full this will not be selected + case messageCh <- nextMessage: + // allow this message to be garbage collected + messages[0] = nil + messages = messages[1:] + + pc.availablePermits.inc() + + if pc.options.autoReceiverQueueSize { + pc.incomingMessages.Dec() + pc.client.memLimit.ReleaseMemory(int64(nextMessageSize)) + pc.expectMoreIncomingMessages() + } + + case clearQueueCb := <-pc.clearQueueCh: + // drain the message queue on any new connection by sending a + // special nil message to the channel so we know when to stop dropping messages + var nextMessageInQueue *trackingMessageID + go func() { + pc.queueCh <- nil + }() + + for m := range pc.queueCh { + // the queue has been drained + if m == nil { + break + } else if nextMessageInQueue == nil { + nextMessageInQueue = toTrackingMessageID(m[0].msgID) + } + if pc.options.autoReceiverQueueSize { + pc.incomingMessages.Sub(int32(len(m))) + } + } + + messages = nil + + clearQueueCb(nextMessageInQueue) + } + } +} + +const ( + individualAck = iota + cumulativeAck +) + +type ackRequest struct { + doneCh chan struct{} + msgID trackingMessageID + ackType int + err error +} + +type unsubscribeRequest struct { + doneCh chan struct{} + err error +} + +type closeRequest struct { + doneCh chan struct{} +} + +type redeliveryRequest struct { + msgIds []messageID +} + +type getLastMsgIDRequest struct { + doneCh chan struct{} + msgID *trackingMessageID + err error +} + +type seekRequest struct { + doneCh chan struct{} + msgID *messageID + err error +} + +type seekByTimeRequest struct { + doneCh chan struct{} + publishTime time.Time + err error +} + +func (pc *partitionConsumer) runEventsLoop() { + defer func() { + pc.log.Debug("exiting events loop") + }() + pc.log.Debug("get into runEventsLoop") + + go func() { + for { + select { + case <-pc.closeCh: + pc.log.Info("close consumer, exit reconnect") + return + case <-pc.connectClosedCh: + pc.log.Debug("runEventsLoop will reconnect") + pc.reconnectToBroker() + } + } + }() + + for { + for i := range pc.eventsCh { + switch v := i.(type) { + case *ackRequest: + pc.internalAck(v) + case []*pb.MessageIdData: + pc.internalAckList(v) + case *redeliveryRequest: + pc.internalRedeliver(v) + case *unsubscribeRequest: + pc.internalUnsubscribe(v) + case *getLastMsgIDRequest: + pc.internalGetLastMessageID(v) + case *seekRequest: + pc.internalSeek(v) + case *seekByTimeRequest: + pc.internalSeekByTime(v) + case *closeRequest: + pc.internalClose(v) + return + } + } + } +} + +func (pc *partitionConsumer) internalClose(req *closeRequest) { + defer close(req.doneCh) + state := pc.getConsumerState() + if state != consumerReady { + // this might be redundant but to ensure nack tracker is closed + if pc.nackTracker != nil { + pc.nackTracker.Close() + } + return + } + + if state == consumerClosed || state == consumerClosing { + pc.log.WithField("state", state).Error("Consumer is closing or has closed") + if pc.nackTracker != nil { + pc.nackTracker.Close() + } + return + } + + pc.setConsumerState(consumerClosing) + pc.log.Infof("Closing consumer=%d", pc.consumerID) + + requestID := pc.client.rpcClient.NewRequestID() + cmdClose := &pb.CommandCloseConsumer{ + ConsumerId: proto.Uint64(pc.consumerID), + RequestId: proto.Uint64(requestID), + } + _, err := pc.client.rpcClient.RequestOnCnx(pc._getConn(), requestID, pb.BaseCommand_CLOSE_CONSUMER, cmdClose) + if err != nil { + pc.log.WithError(err).Warn("Failed to close consumer") + } else { + pc.log.Info("Closed consumer") + } + + pc.compressionProviders.Range(func(_, v interface{}) bool { + if provider, ok := v.(compression.Provider); ok { + provider.Close() + } else { + err := fmt.Errorf("unexpected compression provider type: %T", v) + pc.log.WithError(err).Warn("Failed to close compression provider") + } + return true + }) + + pc.setConsumerState(consumerClosed) + pc._getConn().DeleteConsumeHandler(pc.consumerID) + if pc.nackTracker != nil { + pc.nackTracker.Close() + } + close(pc.closeCh) +} + +func (pc *partitionConsumer) reconnectToBroker() { + var maxRetry int + + if pc.options.maxReconnectToBroker == nil { + maxRetry = -1 + } else { + maxRetry = int(*pc.options.maxReconnectToBroker) + } + + for maxRetry != 0 { + if pc.getConsumerState() != consumerReady { + // Consumer is already closing + pc.log.Info("consumer state not ready, exit reconnect") + return + } + + var ( + delayReconnectTime time.Duration + defaultBackoff = internal.DefaultBackoff{} + ) + + if pc.options.backoffPolicy == nil { + delayReconnectTime = defaultBackoff.Next() + } else { + delayReconnectTime = pc.options.backoffPolicy.Next() + } + + pc.log.Info("Reconnecting to broker in ", delayReconnectTime) + time.Sleep(delayReconnectTime) + + err := pc.grabConn() + if err == nil { + // Successfully reconnected + pc.log.Info("Reconnected consumer to broker") + return + } + pc.log.WithError(err).Error("Failed to create consumer at reconnect") + errMsg := err.Error() + if strings.Contains(errMsg, errTopicNotFount) { + // when topic is deleted, we should give up reconnection. + pc.log.Warn("Topic Not Found.") + break + } + + if maxRetry > 0 { + maxRetry-- + } + pc.metrics.ConsumersReconnectFailure.Inc() + if maxRetry == 0 || defaultBackoff.IsMaxBackoffReached() { + pc.metrics.ConsumersReconnectMaxRetry.Inc() + } + } +} + +func (pc *partitionConsumer) grabConn() error { + lr, err := pc.client.lookupService.Lookup(pc.topic) + if err != nil { + pc.log.WithError(err).Warn("Failed to lookup topic") + return err + } + pc.log.Debugf("Lookup result: %+v", lr) + + subType := toProtoSubType(pc.options.subscriptionType) + initialPosition := toProtoInitialPosition(pc.options.subscriptionInitPos) + keySharedMeta := toProtoKeySharedMeta(pc.options.keySharedPolicy) + requestID := pc.client.rpcClient.NewRequestID() + + var pbSchema *pb.Schema + + if pc.options.schema != nil && pc.options.schema.GetSchemaInfo() != nil { + tmpSchemaType := pb.Schema_Type(int32(pc.options.schema.GetSchemaInfo().Type)) + pbSchema = &pb.Schema{ + Name: proto.String(pc.options.schema.GetSchemaInfo().Name), + Type: &tmpSchemaType, + SchemaData: []byte(pc.options.schema.GetSchemaInfo().Schema), + Properties: internal.ConvertFromStringMap(pc.options.schema.GetSchemaInfo().Properties), + } + pc.log.Debugf("The partition consumer schema name is: %s", pbSchema.Name) + } else { + pc.log.Debug("The partition consumer schema is nil") + } + + cmdSubscribe := &pb.CommandSubscribe{ + Topic: proto.String(pc.topic), + Subscription: proto.String(pc.options.subscription), + SubType: subType.Enum(), + ConsumerId: proto.Uint64(pc.consumerID), + RequestId: proto.Uint64(requestID), + ConsumerName: proto.String(pc.name), + PriorityLevel: nil, + Durable: proto.Bool(pc.options.subscriptionMode == durable), + Metadata: internal.ConvertFromStringMap(pc.options.metadata), + SubscriptionProperties: internal.ConvertFromStringMap(pc.options.subProperties), + ReadCompacted: proto.Bool(pc.options.readCompacted), + Schema: pbSchema, + InitialPosition: initialPosition.Enum(), + ReplicateSubscriptionState: proto.Bool(pc.options.replicateSubscriptionState), + KeySharedMeta: keySharedMeta, + } + + pc.startMessageID.set(pc.clearReceiverQueue()) + if pc.options.subscriptionMode != durable { + // For regular subscriptions the broker will determine the restarting point + cmdSubscribe.StartMessageId = convertToMessageIDData(pc.startMessageID.get()) + } + + if len(pc.options.metadata) > 0 { + cmdSubscribe.Metadata = toKeyValues(pc.options.metadata) + } + + if len(pc.options.subProperties) > 0 { + cmdSubscribe.SubscriptionProperties = toKeyValues(pc.options.subProperties) + } + + // force topic creation is enabled by default so + // we only need to set the flag when disabling it + if pc.options.disableForceTopicCreation { + cmdSubscribe.ForceTopicCreation = proto.Bool(false) + } + + res, err := pc.client.rpcClient.Request(lr.LogicalAddr, lr.PhysicalAddr, requestID, + pb.BaseCommand_SUBSCRIBE, cmdSubscribe) + + if err != nil { + pc.log.WithError(err).Error("Failed to create consumer") + return err + } + + if res.Response.ConsumerStatsResponse != nil { + pc.name = res.Response.ConsumerStatsResponse.GetConsumerName() + } + + pc._setConn(res.Cnx) + pc.log.Info("Connected consumer") + err = pc._getConn().AddConsumeHandler(pc.consumerID, pc) + if err != nil { + pc.log.WithError(err).Error("Failed to add consumer handler") + return err + } + + msgType := res.Response.GetType() + + switch msgType { + case pb.BaseCommand_SUCCESS: + // notify the dispatcher we have connection + go func() { + pc.connectedCh <- struct{}{} + }() + return nil + case pb.BaseCommand_ERROR: + errMsg := res.Response.GetError() + return fmt.Errorf("%s: %s", errMsg.GetError().String(), errMsg.GetMessage()) + default: + return newUnexpectedErrMsg(msgType, requestID) + } +} + +func (pc *partitionConsumer) clearQueueAndGetNextMessage() *trackingMessageID { + if pc.getConsumerState() != consumerReady { + return nil + } + wg := &sync.WaitGroup{} + wg.Add(1) + var msgID *trackingMessageID + + pc.clearQueueCh <- func(id *trackingMessageID) { + msgID = id + wg.Done() + } + + wg.Wait() + return msgID +} + +/** + * Clear the internal receiver queue and returns the message id of what was the 1st message in the queue that was + * not seen by the application + */ +func (pc *partitionConsumer) clearReceiverQueue() *trackingMessageID { + nextMessageInQueue := pc.clearQueueAndGetNextMessage() + + if pc.startMessageID.get() == nil { + return pc.startMessageID.get() + } + + if nextMessageInQueue != nil { + return getPreviousMessage(nextMessageInQueue) + } else if pc.lastDequeuedMsg != nil { + // If the queue was empty we need to restart from the message just after the last one that has been dequeued + // in the past + return pc.lastDequeuedMsg + } else { + // No message was received or dequeued by this consumer. Next message would still be the startMessageId + return pc.startMessageID.get() + } +} + +func getPreviousMessage(mid *trackingMessageID) *trackingMessageID { + if mid.batchIdx >= 0 { + return &trackingMessageID{ + messageID: &messageID{ + ledgerID: mid.ledgerID, + entryID: mid.entryID, + batchIdx: mid.batchIdx - 1, + partitionIdx: mid.partitionIdx, + }, + tracker: mid.tracker, + consumer: mid.consumer, + receivedTime: mid.receivedTime, + } + } + + // Get on previous message in previous entry + return &trackingMessageID{ + messageID: &messageID{ + ledgerID: mid.ledgerID, + entryID: mid.entryID - 1, + batchIdx: mid.batchIdx, + partitionIdx: mid.partitionIdx, + }, + tracker: mid.tracker, + consumer: mid.consumer, + receivedTime: mid.receivedTime, + } +} + +func (pc *partitionConsumer) expectMoreIncomingMessages() { + if !pc.options.autoReceiverQueueSize { + return + } + if pc.scaleReceiverQueueHint.CAS(true, false) { + oldSize := pc.currentQueueSize.Load() + maxSize := int32(pc.options.receiverQueueSize) + newSize := int32(math.Min(float64(maxSize), float64(oldSize*2))) + usagePercent := pc.client.memLimit.CurrentUsagePercent() + if usagePercent < receiverQueueExpansionMemThreshold && newSize > oldSize { + pc.currentQueueSize.CAS(oldSize, newSize) + pc.availablePermits.add(newSize - oldSize) + pc.log.Debugf("update currentQueueSize from %d -> %d", oldSize, newSize) + } + } +} + +func (pc *partitionConsumer) markScaleIfNeed() { + // availablePermits + incomingMessages (messages in queueCh) is the number of prefetched messages + // The result of auto-scale we expected is currentQueueSize is slightly bigger than prefetched messages + prev := pc.scaleReceiverQueueHint.Swap(pc.availablePermits.get()+pc.incomingMessages.Load() >= + pc.currentQueueSize.Load()) + if prev != pc.scaleReceiverQueueHint.Load() { + pc.log.Debugf("update scaleReceiverQueueHint from %t -> %t", prev, pc.scaleReceiverQueueHint.Load()) + } +} + +func (pc *partitionConsumer) shrinkReceiverQueueSize() { + if !pc.options.autoReceiverQueueSize { + return + } + + oldSize := pc.currentQueueSize.Load() + minSize := int32(math.Min(float64(initialReceiverQueueSize), float64(pc.options.receiverQueueSize))) + newSize := int32(math.Max(float64(minSize), float64(oldSize/2))) + if newSize < oldSize { + pc.currentQueueSize.CAS(oldSize, newSize) + pc.availablePermits.add(newSize - oldSize) + pc.log.Debugf("update currentQueueSize from %d -> %d", oldSize, newSize) + } +} + +func (pc *partitionConsumer) Decompress(msgMeta *pb.MessageMetadata, payload internal.Buffer) (internal.Buffer, error) { + providerEntry, ok := pc.compressionProviders.Load(msgMeta.GetCompression()) + if !ok { + newProvider, err := pc.initializeCompressionProvider(msgMeta.GetCompression()) + if err != nil { + pc.log.WithError(err).Error("Failed to decompress message.") + return nil, err + } + + var loaded bool + providerEntry, loaded = pc.compressionProviders.LoadOrStore(msgMeta.GetCompression(), newProvider) + if loaded { + // another thread already loaded this provider, so close the one we just initialized + newProvider.Close() + } + } + provider, ok := providerEntry.(compression.Provider) + if !ok { + err := fmt.Errorf("unexpected compression provider type: %T", providerEntry) + pc.log.WithError(err).Error("Failed to decompress message.") + return nil, err + } + + uncompressed, err := provider.Decompress(nil, payload.ReadableSlice(), int(msgMeta.GetUncompressedSize())) + if err != nil { + return nil, err + } + + return internal.NewBufferWrapper(uncompressed), nil +} + +func (pc *partitionConsumer) initializeCompressionProvider( + compressionType pb.CompressionType) (compression.Provider, error) { + switch compressionType { + case pb.CompressionType_NONE: + return compression.NewNoopProvider(), nil + case pb.CompressionType_ZLIB: + return compression.NewZLibProvider(), nil + case pb.CompressionType_LZ4: + return compression.NewLz4Provider(), nil + case pb.CompressionType_ZSTD: + return compression.NewZStdProvider(compression.Default), nil + } + + return nil, fmt.Errorf("unsupported compression type: %v", compressionType) +} + +func (pc *partitionConsumer) discardCorruptedMessage(msgID *pb.MessageIdData, + validationError pb.CommandAck_ValidationError) { + if state := pc.getConsumerState(); state == consumerClosed || state == consumerClosing { + pc.log.WithField("state", state).Error("Failed to discardCorruptedMessage " + + "by closing or closed consumer") + return + } + pc.log.WithFields(log.Fields{ + "msgID": msgID, + "validationError": validationError, + }).Error("Discarding corrupted message") + + err := pc.client.rpcClient.RequestOnCnxNoWait(pc._getConn(), + pb.BaseCommand_ACK, &pb.CommandAck{ + ConsumerId: proto.Uint64(pc.consumerID), + MessageId: []*pb.MessageIdData{msgID}, + AckType: pb.CommandAck_Individual.Enum(), + ValidationError: validationError.Enum(), + }) + if err != nil { + pc.log.Error("Connection was closed when request ack cmd") + } + pc.availablePermits.inc() +} + +// _setConn sets the internal connection field of this partition consumer atomically. +// Note: should only be called by this partition consumer when a new connection is available. +func (pc *partitionConsumer) _setConn(conn internal.Connection) { + pc.conn.Store(conn) +} + +// _getConn returns internal connection field of this partition consumer atomically. +// Note: should only be called by this partition consumer before attempting to use the connection +func (pc *partitionConsumer) _getConn() internal.Connection { + // Invariant: The conn must be non-nill for the lifetime of the partitionConsumer. + // For this reason we leave this cast unchecked and panic() if the + // invariant is broken + return pc.conn.Load().(internal.Connection) +} + +func convertToMessageIDData(msgID *trackingMessageID) *pb.MessageIdData { + if msgID == nil { + return nil + } + + return &pb.MessageIdData{ + LedgerId: proto.Uint64(uint64(msgID.ledgerID)), + EntryId: proto.Uint64(uint64(msgID.entryID)), + } +} + +func convertToMessageID(id *pb.MessageIdData) *trackingMessageID { + if id == nil { + return nil + } + + msgID := &trackingMessageID{ + messageID: &messageID{ + ledgerID: int64(*id.LedgerId), + entryID: int64(*id.EntryId), + }, + } + if id.BatchIndex != nil { + msgID.batchIdx = *id.BatchIndex + } + + return msgID +} + +type chunkedMsgCtx struct { + totalChunks int32 + chunkedMsgBuffer internal.Buffer + lastChunkedMsgID int32 + chunkedMsgIDs []*messageID + receivedTime int64 + + mu sync.Mutex +} + +func newChunkedMsgCtx(numChunksFromMsg int32, totalChunkMsgSize int) *chunkedMsgCtx { + return &chunkedMsgCtx{ + totalChunks: numChunksFromMsg, + chunkedMsgBuffer: internal.NewBuffer(totalChunkMsgSize), + lastChunkedMsgID: -1, + chunkedMsgIDs: make([]*messageID, numChunksFromMsg), + receivedTime: time.Now().Unix(), + } +} + +func (c *chunkedMsgCtx) append(chunkID int32, msgID *messageID, partPayload internal.Buffer) { + c.mu.Lock() + defer c.mu.Unlock() + c.chunkedMsgIDs[chunkID] = msgID + c.chunkedMsgBuffer.Write(partPayload.ReadableSlice()) + c.lastChunkedMsgID = chunkID +} + +func (c *chunkedMsgCtx) firstChunkID() *messageID { + c.mu.Lock() + defer c.mu.Unlock() + if len(c.chunkedMsgIDs) == 0 { + return nil + } + return c.chunkedMsgIDs[0] +} + +func (c *chunkedMsgCtx) lastChunkID() *messageID { + c.mu.Lock() + defer c.mu.Unlock() + if len(c.chunkedMsgIDs) == 0 { + return nil + } + return c.chunkedMsgIDs[len(c.chunkedMsgIDs)-1] +} + +func (c *chunkedMsgCtx) discard(pc *partitionConsumer) { + c.mu.Lock() + defer c.mu.Unlock() + + for _, mid := range c.chunkedMsgIDs { + if mid == nil { + continue + } + pc.log.Info("Removing chunk message-id", mid.String()) + tmid := toTrackingMessageID(mid) + pc.AckID(tmid) + } +} + +type chunkedMsgCtxMap struct { + chunkedMsgCtxs map[string]*chunkedMsgCtx + pendingQueue *list.List + maxPending int + pc *partitionConsumer + mu sync.Mutex + closed bool +} + +func newChunkedMsgCtxMap(maxPending int, pc *partitionConsumer) *chunkedMsgCtxMap { + return &chunkedMsgCtxMap{ + chunkedMsgCtxs: make(map[string]*chunkedMsgCtx, maxPending), + pendingQueue: list.New(), + maxPending: maxPending, + pc: pc, + mu: sync.Mutex{}, + } +} + +func (c *chunkedMsgCtxMap) addIfAbsent(uuid string, totalChunks int32, totalChunkMsgSize int) { + c.mu.Lock() + defer c.mu.Unlock() + if c.closed { + return + } + if _, ok := c.chunkedMsgCtxs[uuid]; !ok { + c.chunkedMsgCtxs[uuid] = newChunkedMsgCtx(totalChunks, totalChunkMsgSize) + c.pendingQueue.PushBack(uuid) + go c.discardChunkIfExpire(uuid, true, c.pc.options.expireTimeOfIncompleteChunk) + } + if c.maxPending > 0 && c.pendingQueue.Len() > c.maxPending { + go c.discardOldestChunkMessage(c.pc.options.autoAckIncompleteChunk) + } +} + +func (c *chunkedMsgCtxMap) get(uuid string) *chunkedMsgCtx { + c.mu.Lock() + defer c.mu.Unlock() + if c.closed { + return nil + } + return c.chunkedMsgCtxs[uuid] +} + +func (c *chunkedMsgCtxMap) remove(uuid string) { + c.mu.Lock() + defer c.mu.Unlock() + if c.closed { + return + } + delete(c.chunkedMsgCtxs, uuid) + e := c.pendingQueue.Front() + for ; e != nil; e = e.Next() { + if e.Value.(string) == uuid { + c.pendingQueue.Remove(e) + break + } + } +} + +func (c *chunkedMsgCtxMap) discardOldestChunkMessage(autoAck bool) { + c.mu.Lock() + defer c.mu.Unlock() + if c.closed || (c.maxPending > 0 && c.pendingQueue.Len() <= c.maxPending) { + return + } + oldest := c.pendingQueue.Front().Value.(string) + ctx, ok := c.chunkedMsgCtxs[oldest] + if !ok { + return + } + if autoAck { + ctx.discard(c.pc) + } + delete(c.chunkedMsgCtxs, oldest) + c.pc.log.Infof("Chunked message [%s] has been removed from chunkedMsgCtxMap", oldest) +} + +func (c *chunkedMsgCtxMap) discardChunkMessage(uuid string, autoAck bool) { + c.mu.Lock() + defer c.mu.Unlock() + if c.closed { + return + } + ctx, ok := c.chunkedMsgCtxs[uuid] + if !ok { + return + } + if autoAck { + ctx.discard(c.pc) + } + delete(c.chunkedMsgCtxs, uuid) + e := c.pendingQueue.Front() + for ; e != nil; e = e.Next() { + if e.Value.(string) == uuid { + c.pendingQueue.Remove(e) + break + } + } + c.pc.log.Infof("Chunked message [%s] has been removed from chunkedMsgCtxMap", uuid) +} + +func (c *chunkedMsgCtxMap) discardChunkIfExpire(uuid string, autoAck bool, expire time.Duration) { + timer := time.NewTimer(expire) + <-timer.C + c.discardChunkMessage(uuid, autoAck) +} + +func (c *chunkedMsgCtxMap) Close() { + c.mu.Lock() + defer c.mu.Unlock() + c.closed = true +} + +type unAckChunksTracker struct { + // TODO: use hash code of chunkMessageID as the key + chunkIDs map[chunkMessageID][]*messageID + pc *partitionConsumer + mu sync.Mutex +} + +func newUnAckChunksTracker(pc *partitionConsumer) *unAckChunksTracker { + return &unAckChunksTracker{ + chunkIDs: make(map[chunkMessageID][]*messageID), + pc: pc, + } +} + +func (u *unAckChunksTracker) add(cmid *chunkMessageID, ids []*messageID) { + u.mu.Lock() + defer u.mu.Unlock() + + u.chunkIDs[*cmid] = ids +} + +func (u *unAckChunksTracker) get(cmid *chunkMessageID) []*messageID { + u.mu.Lock() + defer u.mu.Unlock() + + return u.chunkIDs[*cmid] +} + +func (u *unAckChunksTracker) remove(cmid *chunkMessageID) { + u.mu.Lock() + defer u.mu.Unlock() + + delete(u.chunkIDs, *cmid) +} + +func (u *unAckChunksTracker) ack(cmid *chunkMessageID) error { + ids := u.get(cmid) + for _, id := range ids { + if err := u.pc.AckID(id); err != nil { + return err + } + } + u.remove(cmid) + return nil +} + +func (u *unAckChunksTracker) nack(cmid *chunkMessageID) { + ids := u.get(cmid) + for _, id := range ids { + u.pc.NackID(id) + } + u.remove(cmid) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_regex.go b/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_regex.go new file mode 100644 index 00000000..2520af5c --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/consumer_regex.go @@ -0,0 +1,488 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" + "errors" + "fmt" + "regexp" + "strings" + "sync" + "time" + + pkgerrors "github.com/pkg/errors" + + "github.com/apache/pulsar-client-go/pulsar/internal" + "github.com/apache/pulsar-client-go/pulsar/log" +) + +const ( + defaultAutoDiscoveryDuration = 1 * time.Minute +) + +type regexConsumer struct { + client *client + dlq *dlqRouter + rlq *retryRouter + + options ConsumerOptions + + messageCh chan ConsumerMessage + + namespace string + pattern *regexp.Regexp + + consumersLock sync.Mutex + consumers map[string]Consumer + subscribeCh chan []string + unsubscribeCh chan []string + + closeOnce sync.Once + closeCh chan struct{} + + ticker *time.Ticker + + log log.Logger + + consumerName string +} + +func newRegexConsumer(c *client, opts ConsumerOptions, tn *internal.TopicName, pattern *regexp.Regexp, + msgCh chan ConsumerMessage, dlq *dlqRouter, rlq *retryRouter) (Consumer, error) { + rc := ®exConsumer{ + client: c, + dlq: dlq, + rlq: rlq, + options: opts, + messageCh: msgCh, + + namespace: tn.Namespace, + pattern: pattern, + + consumers: make(map[string]Consumer), + subscribeCh: make(chan []string, 1), + unsubscribeCh: make(chan []string, 1), + + closeCh: make(chan struct{}), + + log: c.log.SubLogger(log.Fields{"topic": tn.Name}), + consumerName: opts.Name, + } + + topics, err := rc.topics() + if err != nil { + return nil, err + } + + var errs error + for ce := range subscriber(c, topics, opts, msgCh, dlq, rlq) { + if ce.err != nil { + errs = pkgerrors.Wrapf(ce.err, "unable to subscribe to topic=%s", ce.topic) + } else { + rc.consumers[ce.topic] = ce.consumer + } + } + + if errs != nil { + for _, c := range rc.consumers { + c.Close() + } + return nil, errs + } + + // set up timer + duration := opts.AutoDiscoveryPeriod + if duration <= 0 { + duration = defaultAutoDiscoveryDuration + } + rc.ticker = time.NewTicker(duration) + + go rc.monitor() + + return rc, nil +} + +func (c *regexConsumer) Subscription() string { + return c.options.SubscriptionName +} + +func (c *regexConsumer) Unsubscribe() error { + var errs error + c.consumersLock.Lock() + defer c.consumersLock.Unlock() + + for topic, consumer := range c.consumers { + if err := consumer.Unsubscribe(); err != nil { + msg := fmt.Sprintf("unable to unsubscribe from topic=%s subscription=%s", + topic, c.Subscription()) + errs = pkgerrors.Wrap(err, msg) + } + } + return errs +} + +func (c *regexConsumer) Receive(ctx context.Context) (message Message, err error) { + for { + select { + case <-c.closeCh: + return nil, newError(ConsumerClosed, "consumer closed") + case cm, ok := <-c.messageCh: + if !ok { + return nil, newError(ConsumerClosed, "consumer closed") + } + return cm.Message, nil + case <-ctx.Done(): + return nil, ctx.Err() + } + } +} + +// Chan return the messages chan to user +func (c *regexConsumer) Chan() <-chan ConsumerMessage { + return c.messageCh +} + +// Ack the consumption of a single message +func (c *regexConsumer) Ack(msg Message) error { + return c.AckID(msg.ID()) +} + +func (c *regexConsumer) ReconsumeLater(msg Message, delay time.Duration) { + c.log.Warnf("regexp consumer not support ReconsumeLater yet.") +} + +func (c *regexConsumer) ReconsumeLaterWithCustomProperties(msg Message, customProperties map[string]string, + delay time.Duration) { + c.log.Warnf("regexp consumer not support ReconsumeLaterWithCustomProperties yet.") +} + +// AckID the consumption of a single message, identified by its MessageID +func (c *regexConsumer) AckID(msgID MessageID) error { + if !checkMessageIDType(msgID) { + c.log.Warnf("invalid message id type %T", msgID) + return fmt.Errorf("invalid message id type %T", msgID) + } + + mid := toTrackingMessageID(msgID) + + if mid.consumer == nil { + c.log.Warnf("unable to ack messageID=%+v can not determine topic", msgID) + return errors.New("consumer is nil in consumer_regex") + } + + if c.options.AckWithResponse { + return mid.consumer.AckIDWithResponse(msgID) + } + + return mid.consumer.AckID(msgID) +} + +// AckCumulative the reception of all the messages in the stream up to (and including) +// the provided message. +func (c *regexConsumer) AckCumulative(msg Message) error { + return c.AckIDCumulative(msg.ID()) +} + +// AckIDCumulative the reception of all the messages in the stream up to (and including) +// the provided message, identified by its MessageID +func (c *regexConsumer) AckIDCumulative(msgID MessageID) error { + if !checkMessageIDType(msgID) { + c.log.Warnf("invalid message id type %T", msgID) + return fmt.Errorf("invalid message id type %T", msgID) + } + + mid := toTrackingMessageID(msgID) + + if mid.consumer == nil { + c.log.Warnf("unable to ack messageID=%+v can not determine topic", msgID) + return errors.New("unable to ack message because consumer is nil") + } + + if c.options.AckWithResponse { + return mid.consumer.AckIDWithResponseCumulative(msgID) + } + + return mid.consumer.AckIDCumulative(msgID) +} + +func (c *regexConsumer) Nack(msg Message) { + if c.options.EnableDefaultNackBackoffPolicy || c.options.NackBackoffPolicy != nil { + msgID := msg.ID() + if !checkMessageIDType(msgID) { + c.log.Warnf("invalid message id type %T", msgID) + return + } + mid := toTrackingMessageID(msgID) + + if mid.consumer == nil { + c.log.Warnf("unable to nack messageID=%+v can not determine topic", msgID) + return + } + mid.NackByMsg(msg) + return + } + + c.NackID(msg.ID()) +} + +func (c *regexConsumer) NackID(msgID MessageID) { + if !checkMessageIDType(msgID) { + c.log.Warnf("invalid message id type %T", msgID) + return + } + + mid := toTrackingMessageID(msgID) + + if mid.consumer == nil { + c.log.Warnf("unable to nack messageID=%+v can not determine topic", msgID) + return + } + + mid.consumer.NackID(msgID) +} + +func (c *regexConsumer) Close() { + c.closeOnce.Do(func() { + c.ticker.Stop() + close(c.closeCh) + + var wg sync.WaitGroup + c.consumersLock.Lock() + defer c.consumersLock.Unlock() + wg.Add(len(c.consumers)) + for _, con := range c.consumers { + go func(consumer Consumer) { + defer wg.Done() + consumer.Close() + }(con) + } + wg.Wait() + c.client.handlers.Del(c) + c.dlq.close() + c.rlq.close() + }) +} + +func (c *regexConsumer) Seek(msgID MessageID) error { + return newError(SeekFailed, "seek command not allowed for regex consumer") +} + +func (c *regexConsumer) SeekByTime(time time.Time) error { + return newError(SeekFailed, "seek command not allowed for regex consumer") +} + +// Name returns the name of consumer. +func (c *regexConsumer) Name() string { + return c.consumerName +} + +func (c *regexConsumer) closed() bool { + select { + case <-c.closeCh: + return true + default: + return false + } +} + +func (c *regexConsumer) monitor() { + for { + select { + case <-c.closeCh: + return + case <-c.ticker.C: + c.log.Debug("Auto discovering topics") + if !c.closed() { + c.discover() + } + case topics := <-c.subscribeCh: + if len(topics) > 0 && !c.closed() { + c.subscribe(topics, c.dlq, c.rlq) + } + case topics := <-c.unsubscribeCh: + if len(topics) > 0 && !c.closed() { + c.unsubscribe(topics) + } + } + } +} + +func (c *regexConsumer) discover() { + topics, err := c.topics() + if err != nil { + c.log.WithError(err).Errorf("Failed to discover topics") + return + } + known := c.knownTopics() + newTopics := topicsDiff(topics, known) + staleTopics := topicsDiff(known, topics) + + c.log. + WithFields(log.Fields{ + "new_topics": newTopics, + "old_topics": staleTopics, + }). + Debug("discover topics") + + c.unsubscribeCh <- staleTopics + c.subscribeCh <- newTopics +} + +func (c *regexConsumer) knownTopics() []string { + c.consumersLock.Lock() + defer c.consumersLock.Unlock() + topics := make([]string, len(c.consumers)) + n := 0 + for t := range c.consumers { + topics[n] = t + n++ + } + + return topics +} + +func (c *regexConsumer) subscribe(topics []string, dlq *dlqRouter, rlq *retryRouter) { + c.log.WithField("topics", topics).Debug("subscribe") + consumers := make(map[string]Consumer, len(topics)) + for ce := range subscriber(c.client, topics, c.options, c.messageCh, dlq, rlq) { + if ce.err != nil { + c.log.Warnf("Failed to subscribe to topic=%s", ce.topic) + } else { + consumers[ce.topic] = ce.consumer + } + } + + c.consumersLock.Lock() + defer c.consumersLock.Unlock() + for t, consumer := range consumers { + c.consumers[t] = consumer + } +} + +func (c *regexConsumer) unsubscribe(topics []string) { + c.log.WithField("topics", topics).Debug("unsubscribe") + + consumers := make(map[string]Consumer, len(topics)) + c.consumersLock.Lock() + + for _, t := range topics { + if consumer, ok := c.consumers[t]; ok { + consumers[t] = consumer + delete(c.consumers, t) + } + } + c.consumersLock.Unlock() + + for t, consumer := range consumers { + c.log.Debugf("unsubscribe from topic=%s subscription=%s", t, c.options.SubscriptionName) + if err := consumer.Unsubscribe(); err != nil { + c.log.Warnf("unable to unsubscribe from topic=%s subscription=%s", + t, c.options.SubscriptionName) + } + consumer.Close() + } +} + +func (c *regexConsumer) topics() ([]string, error) { + topics, err := c.client.lookupService.GetTopicsOfNamespace(c.namespace, internal.Persistent) + if err != nil { + return nil, err + } + + filtered := filterTopics(topics, c.pattern) + return filtered, nil +} + +type consumerError struct { + err error + topic string + consumer Consumer +} + +func subscriber(c *client, topics []string, opts ConsumerOptions, ch chan ConsumerMessage, + dlq *dlqRouter, rlq *retryRouter) <-chan consumerError { + consumerErrorCh := make(chan consumerError, len(topics)) + var wg sync.WaitGroup + wg.Add(len(topics)) + go func() { + wg.Wait() + close(consumerErrorCh) + }() + + for _, t := range topics { + go func(topic string) { + defer wg.Done() + c, err := newInternalConsumer(c, opts, topic, ch, dlq, rlq, true) + consumerErrorCh <- consumerError{ + err: err, + topic: topic, + consumer: c, + } + }(t) + } + + return consumerErrorCh +} + +func filterTopics(topics []string, regex *regexp.Regexp) []string { + matches := make(map[string]bool) + matching := make([]string, 0) + for _, t := range topics { + tn, _ := internal.ParseTopicName(t) + topic := internal.TopicNameWithoutPartitionPart(tn) + if _, ok := matches[topic]; ok { + continue + } + if regex.MatchString(topic) { + matches[topic] = true + matching = append(matching, topic) + } + } + + return matching +} + +// topicDiff returns all topics in topics1 that are not in topics2 +func topicsDiff(topics1 []string, topics2 []string) []string { + if len(topics2) == 0 { + return topics1 + } + diff := make([]string, 0) + topics := make(map[string]bool, len(topics2)) + for _, t := range topics2 { + topics[t] = true + } + + for _, t := range topics1 { + if !topics[t] { + diff = append(diff, t) + } + } + + return diff +} + +func extractTopicPattern(tn *internal.TopicName) (*regexp.Regexp, error) { + idx := strings.Index(tn.Name, tn.Namespace) + if idx > 0 { + return regexp.Compile(tn.Name[idx:]) + } + + return regexp.Compile(tn.Name) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/crypto_failure_action.go b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/crypto_failure_action.go new file mode 100644 index 00000000..0bdd289d --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/crypto_failure_action.go @@ -0,0 +1,43 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package crypto + +const ( + // ProducerCryptoFailureActionFail this is the default option to fail send if crypto operation fails. + ProducerCryptoFailureActionFail = iota + + // ProducerCryptoFailureActionSend ignore crypto failure and proceed with sending unencrypted message. + ProducerCryptoFailureActionSend +) + +const ( + // ConsumerCryptoFailureActionFail this is the default option to fail consume messages until crypto succeeds. + ConsumerCryptoFailureActionFail = iota + + // ConsumerCryptoFailureActionDiscard message is silently acknowledged and not delivered to the application + ConsumerCryptoFailureActionDiscard + + // ConsumerCryptoFailureActionConsume deliver the encrypted message to the application. + // It's the application's responsibility to decrypt the message. + // if message is also compressed, decompression will fail. + // If message contain batch messages, client will not be able to retrieve + // individual messages in the batch. + // delivered encrypted message contains EncryptionContext which contains encryption + // and compression information in it using which application can decrypt the payload. + ConsumerCryptoFailureActionConsume +) diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/crypto_key_reader.go b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/crypto_key_reader.go new file mode 100644 index 00000000..51295c13 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/crypto_key_reader.go @@ -0,0 +1,28 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package crypto + +// KeyReader implement this interface to read and provide public & private keys +// key pair can be RSA, ECDSA +type KeyReader interface { + // PublicKey get public key that is be used by the producer to encrypt data key + PublicKey(keyName string, metadata map[string]string) (*EncryptionKeyInfo, error) + + // PrivateKey get private key that is used by the consumer to decrypt data key + PrivateKey(keyName string, metadata map[string]string) (*EncryptionKeyInfo, error) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/default_crypto_Key_reader.go b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/default_crypto_Key_reader.go new file mode 100644 index 00000000..8dfb2bc0 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/default_crypto_Key_reader.go @@ -0,0 +1,51 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package crypto + +import "os" + +// FileKeyReader default implementation of KeyReader +type FileKeyReader struct { + publicKeyPath string + privateKeyPath string +} + +func NewFileKeyReader(publicKeyPath, privateKeyPath string) *FileKeyReader { + return &FileKeyReader{ + publicKeyPath: publicKeyPath, + privateKeyPath: privateKeyPath, + } +} + +// PublicKey read public key from the given path +func (d *FileKeyReader) PublicKey(keyName string, keyMeta map[string]string) (*EncryptionKeyInfo, error) { + return readKey(keyName, d.publicKeyPath, keyMeta) +} + +// PrivateKey read private key from the given path +func (d *FileKeyReader) PrivateKey(keyName string, keyMeta map[string]string) (*EncryptionKeyInfo, error) { + return readKey(keyName, d.privateKeyPath, keyMeta) +} + +func readKey(keyName, path string, keyMeta map[string]string) (*EncryptionKeyInfo, error) { + key, err := os.ReadFile(path) + if err != nil { + return nil, err + } + return NewEncryptionKeyInfo(keyName, key, keyMeta), nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/default_message_crypto.go b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/default_message_crypto.go new file mode 100644 index 00000000..74e4592d --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/default_message_crypto.go @@ -0,0 +1,365 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package crypto + +import ( + gocrypto "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/md5" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "sync" + + "github.com/apache/pulsar-client-go/pulsar/log" +) + +// DefaultMessageCrypto implementation of the interface MessageCryto +type DefaultMessageCrypto struct { + // data key which is used to encrypt/decrypt messages + dataKey []byte + + // LoadingCache used by the consumer to cache already decrypted key + loadingCache sync.Map // map[string][]byte + + encryptedDataKeyMap sync.Map // map[string]EncryptionKeyInfo + + logCtx string + + logger log.Logger + + cipherLock sync.Mutex + + encryptLock sync.Mutex +} + +// NewDefaultMessageCrypto get the instance of message crypto +func NewDefaultMessageCrypto(logCtx string, keyGenNeeded bool, logger log.Logger) (*DefaultMessageCrypto, error) { + + d := &DefaultMessageCrypto{ + logCtx: logCtx, + loadingCache: sync.Map{}, + encryptedDataKeyMap: sync.Map{}, + logger: logger, + } + + if keyGenNeeded { + key, err := generateDataKey() + if err != nil { + return d, err + } + d.dataKey = key + } + + return d, nil +} + +// AddPublicKeyCipher encrypt data key using keyCrypto and cache +func (d *DefaultMessageCrypto) AddPublicKeyCipher(keyNames []string, keyReader KeyReader) error { + key, err := generateDataKey() + if err != nil { + return err + } + + d.dataKey = key + for _, keyName := range keyNames { + err := d.addPublicKeyCipher(keyName, keyReader) + if err != nil { + return err + } + } + return nil +} + +func (d *DefaultMessageCrypto) addPublicKeyCipher(keyName string, keyReader KeyReader) error { + d.cipherLock.Lock() + defer d.cipherLock.Unlock() + if keyName == "" || keyReader == nil { + return fmt.Errorf("keyname or keyreader is null") + } + + // read the public key and its info using keyReader + keyInfo, err := keyReader.PublicKey(keyName, nil) + if err != nil { + return err + } + + parsedKey, err := d.loadPublicKey(keyInfo.Key()) + if err != nil { + return err + } + + // try to cast to RSA key + rsaPubKey, ok := parsedKey.(*rsa.PublicKey) + if !ok { + return fmt.Errorf("only RSA keys are supported") + } + + encryptedDataKey, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, rsaPubKey, d.dataKey, nil) + if err != nil { + return err + } + + d.encryptedDataKeyMap.Store(keyName, NewEncryptionKeyInfo(keyName, encryptedDataKey, keyInfo.Metadata())) + + return nil +} + +// RemoveKeyCipher remove encrypted data key from cache +func (d *DefaultMessageCrypto) RemoveKeyCipher(keyName string) bool { + if keyName == "" { + return false + } + d.encryptedDataKeyMap.Delete(keyName) + return true +} + +// Encrypt payload using encryption keys and add encrypted data key +// to message metadata. Here data key is encrypted +// using public key +func (d *DefaultMessageCrypto) Encrypt(encKeys []string, + keyReader KeyReader, + msgMetadata MessageMetadataSupplier, + payload []byte) ([]byte, error) { + d.encryptLock.Lock() + defer d.encryptLock.Unlock() + + if len(encKeys) == 0 { + return payload, nil + } + + for _, keyName := range encKeys { + // if key is not already loaded, load it + if _, ok := d.encryptedDataKeyMap.Load(keyName); !ok { + if err := d.addPublicKeyCipher(keyName, keyReader); err != nil { + d.logger.Error(err) + } + } + + // add key to the message metadata + if k, ok := d.encryptedDataKeyMap.Load(keyName); ok { + keyInfo, keyInfoOk := k.(*EncryptionKeyInfo) + + if keyInfoOk { + msgMetadata.UpsertEncryptionKey(*keyInfo) + } else { + d.logger.Error("failed to get EncryptionKeyInfo for key %v", keyName) + } + } else { + // we should never reach here + msg := fmt.Sprintf("%v Failed to find encrypted Data key for key %v", d.logCtx, keyName) + d.logger.Errorf(msg) + return nil, fmt.Errorf(msg) + } + + } + + // generate a new AES cipher with data key + c, err := aes.NewCipher(d.dataKey) + + if err != nil { + d.logger.Error("failed to create AES cipher") + return nil, err + } + + // gcm + gcm, err := cipher.NewGCM(c) + + if err != nil { + d.logger.Error("failed to create gcm") + return nil, err + } + + // create gcm param + nonce := make([]byte, gcm.NonceSize()) + _, err = rand.Read(nonce) + + if err != nil { + d.logger.Error(err) + return nil, err + } + + // Update message metadata with encryption param + msgMetadata.SetEncryptionParam(nonce) + + // encrypt payload using seal function + return gcm.Seal(nil, nonce, payload, nil), nil +} + +// Decrypt the payload using decrypted data key. +// Here data key is read from the message +// metadata and decrypted using private key. +func (d *DefaultMessageCrypto) Decrypt(msgMetadata MessageMetadataSupplier, + payload []byte, + keyReader KeyReader) ([]byte, error) { + // if data key is present, attempt to derypt using the existing key + if d.dataKey != nil { + decryptedData, err := d.getKeyAndDecryptData(msgMetadata, payload) + if err != nil { + d.logger.Error(err) + } + + if decryptedData != nil { + return decryptedData, nil + } + } + + // data key is null or decryption failed. Attempt to regenerate data key + encKeys := msgMetadata.EncryptionKeys() + var ecKeyInfo *EncryptionKeyInfo + + for _, encKey := range encKeys { + if d.decryptDataKey(encKey.Name(), encKey.Key(), encKey.Metadata(), keyReader) { + ecKeyInfo = &encKey + } + } + + if ecKeyInfo == nil || d.dataKey == nil { + // unable to decrypt data key + return nil, errors.New("unable to decrypt data key") + } + + return d.getKeyAndDecryptData(msgMetadata, payload) +} + +func (d *DefaultMessageCrypto) decryptData(dataKeySecret []byte, + msgMetadata MessageMetadataSupplier, + payload []byte) ([]byte, error) { + // get nonce from message metadata + nonce := msgMetadata.EncryptionParam() + + c, err := aes.NewCipher(dataKeySecret) + + if err != nil { + d.logger.Error(err) + return nil, err + } + + gcm, err := cipher.NewGCM(c) + if err != nil { + return nil, err + } + + decryptedData, err := gcm.Open(nil, nonce, payload, nil) + + if err != nil { + d.logger.Error(err) + } + + return decryptedData, err +} + +func (d *DefaultMessageCrypto) getKeyAndDecryptData(msgMetadata MessageMetadataSupplier, + payload []byte) ([]byte, error) { + // go through all keys to retrieve data key from cache + for _, k := range msgMetadata.EncryptionKeys() { + msgDataKey := k.Key() + keyDigest := fmt.Sprintf("%x", md5.Sum(msgDataKey)) + if storedSecretKey, ok := d.loadingCache.Load(keyDigest); ok { + decryptedData, err := d.decryptData(storedSecretKey.([]byte), msgMetadata, payload) + if err != nil { + d.logger.Error(err) + } + + if decryptedData != nil { + return decryptedData, nil + } + } else { + // First time, entry won't be present in cache + d.logger.Debugf("%s Failed to decrypt data or data key is not in cache. Will attempt to refresh", d.logCtx) + } + } + return nil, nil +} + +func (d *DefaultMessageCrypto) decryptDataKey(keyName string, + encDatakey []byte, + keyMeta map[string]string, + keyReader KeyReader) bool { + + keyInfo, err := keyReader.PrivateKey(keyName, keyMeta) + if err != nil { + d.logger.Error(err) + return false + } + + parsedKey, err := d.loadPrivateKey(keyInfo.Key()) + if err != nil { + d.logger.Error(err) + return false + } + + rsaPriKey, ok := parsedKey.(*rsa.PrivateKey) + if !ok { + d.logger.Error("only RSA keys are supported") + return false + } + + decryptedDataKey, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, rsaPriKey, encDatakey, nil) + if err != nil { + d.logger.Error(err) + return false + } + d.dataKey = decryptedDataKey + d.loadingCache.Store(fmt.Sprintf("%x", md5.Sum(encDatakey)), d.dataKey) + + return true +} + +func (d *DefaultMessageCrypto) loadPrivateKey(key []byte) (gocrypto.PrivateKey, error) { + var privateKey gocrypto.PrivateKey + priPem, _ := pem.Decode(key) + if priPem == nil { + return privateKey, fmt.Errorf("failed to decode private key") + } + genericPrivateKey, err := x509.ParsePKCS1PrivateKey(priPem.Bytes) + if err != nil { + return privateKey, err + } + privateKey = genericPrivateKey + return privateKey, nil +} + +// read the public key into RSA key +func (d *DefaultMessageCrypto) loadPublicKey(key []byte) (gocrypto.PublicKey, error) { + var publickKey gocrypto.PublicKey + + pubPem, _ := pem.Decode(key) + if pubPem == nil { + return publickKey, fmt.Errorf("failed to decode public key") + } + + genericPublicKey, err := x509.ParsePKIXPublicKey(pubPem.Bytes) + if err != nil { + return publickKey, err + } + publickKey = genericPublicKey + + return publickKey, nil +} + +func generateDataKey() ([]byte, error) { + key := make([]byte, 32) // generate key of length 256 bits + _, err := rand.Read(key) // cryptographically secure random number + return key, err +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/encryption_key_Info.go b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/encryption_key_Info.go new file mode 100644 index 00000000..11dd4449 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/encryption_key_Info.go @@ -0,0 +1,49 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package crypto + +// EncryptionKeyInfo +type EncryptionKeyInfo struct { + metadata map[string]string + key []byte + name string +} + +// NewEncryptionKeyInfo create a new EncryptionKeyInfo +func NewEncryptionKeyInfo(name string, key []byte, metadata map[string]string) *EncryptionKeyInfo { + return &EncryptionKeyInfo{ + metadata: metadata, + name: name, + key: key, + } +} + +// Name get the name of the key +func (eci *EncryptionKeyInfo) Name() string { + return eci.name +} + +// Key get the key data +func (eci *EncryptionKeyInfo) Key() []byte { + return eci.key +} + +// Metadata get key metadata +func (eci *EncryptionKeyInfo) Metadata() map[string]string { + return eci.metadata +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/message_crypto.go b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/message_crypto.go new file mode 100644 index 00000000..4a17b71d --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/message_crypto.go @@ -0,0 +1,39 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package crypto + +// MessageCrypto implement this interface to encrypt and decrypt messages +type MessageCrypto interface { + + // AddPublicKeyCipher encrypt data using the public key(s) in the argument. + // If more than one key name is specified, data key is encrypted using each of those keys. + // If the public key is expired or changed, application is responsible to remove + // the old key and add the new key. + AddPublicKeyCipher(keyNames []string, keyReader KeyReader) error + + // RemoveKeyCipher remove the key from the list + RemoveKeyCipher(keyName string) bool + + // Encrypt the payload using the data key and update + // message metadata with the key and encrypted data key + Encrypt(encKeys []string, KeyReader KeyReader, msgMetadata MessageMetadataSupplier, payload []byte) ([]byte, error) + + // Decrypt the payload using the data key. + // Keys used to encrypt the data key can be retrieved from msgMetadata + Decrypt(msgMetadata MessageMetadataSupplier, payload []byte, KeyReader KeyReader) ([]byte, error) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/message_metadata.go b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/message_metadata.go new file mode 100644 index 00000000..717b0c0a --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/crypto/message_metadata.go @@ -0,0 +1,122 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package crypto + +import ( + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" +) + +// MessageMetadataSupplier wrapper implementation around message metadata +type MessageMetadataSupplier interface { + // EncryptionKeys read all the encryption keys from the MessageMetadata + EncryptionKeys() []EncryptionKeyInfo + + // UpsertEncryptionKey add new or update existing EncryptionKeys in to the MessageMetadata + UpsertEncryptionKey(EncryptionKeyInfo) + + // EncryptionParam read the ecryption parameter from the MessageMetadata + EncryptionParam() []byte + + // SetEncryptionParam set encryption parameter in to the MessageMetadata + SetEncryptionParam([]byte) +} + +type MessageMetadata struct { + messageMetadata *pb.MessageMetadata +} + +func NewMessageMetadataSupplier(messageMetadata *pb.MessageMetadata) MessageMetadataSupplier { + return &MessageMetadata{ + messageMetadata: messageMetadata, + } +} + +func (m *MessageMetadata) EncryptionKeys() []EncryptionKeyInfo { + if m.messageMetadata != nil { + encInfo := []EncryptionKeyInfo{} + for _, k := range m.messageMetadata.EncryptionKeys { + key := NewEncryptionKeyInfo(k.GetKey(), k.GetValue(), getKeyMetaMap(k.GetMetadata())) + encInfo = append(encInfo, *key) + } + return encInfo + } + return nil +} + +func (m *MessageMetadata) UpsertEncryptionKey(keyInfo EncryptionKeyInfo) { + if m.messageMetadata != nil { + idx := m.encryptionKeyPresent(keyInfo) + newKey := &pb.EncryptionKeys{ + Key: &keyInfo.name, + Value: keyInfo.Key(), + Metadata: getKeyMeta(keyInfo.Metadata()), + } + + if idx >= 0 { + m.messageMetadata.EncryptionKeys[idx] = newKey + } else { + m.messageMetadata.EncryptionKeys = append(m.messageMetadata.EncryptionKeys, newKey) + } + } +} + +func (m *MessageMetadata) EncryptionParam() []byte { + if m.messageMetadata != nil { + return m.messageMetadata.EncryptionParam + } + return nil +} + +func (m *MessageMetadata) SetEncryptionParam(param []byte) { + if m.messageMetadata != nil { + m.messageMetadata.EncryptionParam = param + } +} + +func (m *MessageMetadata) encryptionKeyPresent(keyInfo EncryptionKeyInfo) int { + if len(m.messageMetadata.EncryptionKeys) > 0 { + for idx, k := range m.messageMetadata.EncryptionKeys { + if k.GetKey() == keyInfo.Name() { + return idx + } + } + } + return -1 +} + +func getKeyMeta(metaMap map[string]string) []*pb.KeyValue { + if len(metaMap) > 0 { + var meta []*pb.KeyValue + for k, v := range metaMap { + meta = append(meta, &pb.KeyValue{Key: &k, Value: &v}) + } + return meta + } + return nil +} + +func getKeyMetaMap(keyValues []*pb.KeyValue) map[string]string { + if keyValues != nil { + meta := map[string]string{} + for _, kv := range keyValues { + meta[kv.GetKey()] = kv.GetValue() + } + return meta + } + return nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/default_router.go b/vendor/github.com/apache/pulsar-client-go/pulsar/default_router.go new file mode 100644 index 00000000..6945ff19 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/default_router.go @@ -0,0 +1,111 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "math/rand" + "sync/atomic" + "time" +) + +type defaultRouter struct { + currentPartitionCursor uint32 + + lastBatchTimestamp int64 + msgCounter uint32 + cumulativeBatchSize uint32 +} + +// NewDefaultRouter set the message routing mode for the partitioned producer. +// Default routing mode is round-robin routing if no partition key is specified. +// If the batching is enabled, it honors the different thresholds for batching i.e. maximum batch size, +// maximum number of messages, maximum delay to publish a batch. When one of the threshold is reached the next partition +// is used. +func NewDefaultRouter( + hashFunc func(string) uint32, + maxBatchingMessages uint, + maxBatchingSize uint, + maxBatchingDelay time.Duration, + disableBatching bool) func(*ProducerMessage, uint32) int { + state := &defaultRouter{ + currentPartitionCursor: rand.Uint32(), + lastBatchTimestamp: time.Now().UnixNano(), + } + + readClockAfterNumMessages := uint32(maxBatchingMessages / 10) + return func(message *ProducerMessage, numPartitions uint32) int { + if numPartitions == 1 { + // When there are no partitions, don't even bother + return 0 + } + + if len(message.OrderingKey) != 0 { + // When an OrderingKey is specified, use the hash of that key + return int(hashFunc(message.OrderingKey) % numPartitions) + } + + if len(message.Key) != 0 { + // When a key is specified, use the hash of that key + return int(hashFunc(message.Key) % numPartitions) + } + + // If there's no key, we do round-robin across partition. If no batching go to next partition. + if disableBatching { + p := int(state.currentPartitionCursor % numPartitions) + atomic.AddUint32(&state.currentPartitionCursor, 1) + return p + } + + // If there's no key, we do round-robin across partition, sticking with a given + // partition for a certain amount of messages or volume buffered or the max delay to batch is reached so that + // we ensure having a decent amount of batching of the messages. + var now int64 + size := uint32(len(message.Payload)) + partitionCursor := atomic.LoadUint32(&state.currentPartitionCursor) + messageCount := atomic.AddUint32(&state.msgCounter, 1) + batchSize := atomic.AddUint32(&state.cumulativeBatchSize, size) + + // Note: use greater-than for the threshold check so that we don't route this message to a new partition + // before a batch is complete. + messageCountReached := messageCount > uint32(maxBatchingMessages) + sizeReached := batchSize > uint32(maxBatchingSize) + durationReached := false + if readClockAfterNumMessages == 0 || messageCount%readClockAfterNumMessages == 0 { + now = time.Now().UnixNano() + lastBatchTime := atomic.LoadInt64(&state.lastBatchTimestamp) + durationReached = now-lastBatchTime > maxBatchingDelay.Nanoseconds() + } + if messageCountReached || sizeReached || durationReached { + // Note: CAS to ensure that concurrent go-routines can only move the cursor forward by one so that + // partitions are not skipped. + newCursor := partitionCursor + 1 + if atomic.CompareAndSwapUint32(&state.currentPartitionCursor, partitionCursor, newCursor) { + atomic.StoreUint32(&state.msgCounter, 0) + atomic.StoreUint32(&state.cumulativeBatchSize, 0) + if now == 0 { + now = time.Now().UnixNano() + } + atomic.StoreInt64(&state.lastBatchTimestamp, now) + } + + return int(newCursor % numPartitions) + } + + return int(partitionCursor % numPartitions) + } +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/dlq_router.go b/vendor/github.com/apache/pulsar-client-go/pulsar/dlq_router.go new file mode 100644 index 00000000..6d300036 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/dlq_router.go @@ -0,0 +1,172 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" + "time" + + "github.com/apache/pulsar-client-go/pulsar/internal" + "github.com/apache/pulsar-client-go/pulsar/log" +) + +type dlqRouter struct { + client Client + producer Producer + policy *DLQPolicy + messageCh chan ConsumerMessage + closeCh chan interface{} + log log.Logger +} + +func newDlqRouter(client Client, policy *DLQPolicy, logger log.Logger) (*dlqRouter, error) { + r := &dlqRouter{ + client: client, + policy: policy, + log: logger, + } + + if policy != nil { + if policy.MaxDeliveries <= 0 { + return nil, newError(InvalidConfiguration, "DLQPolicy.MaxDeliveries needs to be > 0") + } + + if policy.DeadLetterTopic == "" { + return nil, newError(InvalidConfiguration, "DLQPolicy.Topic needs to be set to a valid topic name") + } + + r.messageCh = make(chan ConsumerMessage) + r.closeCh = make(chan interface{}, 1) + r.log = logger.SubLogger(log.Fields{"dlq-topic": policy.DeadLetterTopic}) + go r.run() + } + return r, nil +} + +func (r *dlqRouter) shouldSendToDlq(cm *ConsumerMessage) bool { + if r.policy == nil { + return false + } + + msg := cm.Message.(*message) + r.log.WithField("count", msg.redeliveryCount). + WithField("max", r.policy.MaxDeliveries). + WithField("msgId", msg.msgID). + Debug("Should route to DLQ?") + + // We use >= here because we're comparing the number of re-deliveries with + // the number of deliveries. So: + // * the user specifies that wants to process a message up to 10 times. + // * the first time, the redeliveryCount == 0, then 1 and so on + // * when we receive the message and redeliveryCount == 10, it means + // that the application has already got (and Nack()) the message 10 + // times, so this time we should just go to DLQ. + + return msg.redeliveryCount >= r.policy.MaxDeliveries +} + +func (r *dlqRouter) Chan() chan ConsumerMessage { + return r.messageCh +} + +func (r *dlqRouter) run() { + for { + select { + case cm := <-r.messageCh: + r.log.WithField("msgID", cm.ID()).Debug("Got message for DLQ") + producer := r.getProducer(cm.Consumer.(*consumer).options.Schema) + msg := cm.Message.(*message) + msgID := msg.ID() + + // properties associated with original message + properties := msg.Properties() + + // include orinal message id in string format in properties + properties[PropertyOriginMessageID] = msgID.String() + + // include original topic name of the message in properties + properties[SysPropertyRealTopic] = msg.Topic() + + producer.SendAsync(context.Background(), &ProducerMessage{ + Payload: msg.Payload(), + Key: msg.Key(), + OrderingKey: msg.OrderingKey(), + Properties: properties, + EventTime: msg.EventTime(), + ReplicationClusters: msg.replicationClusters, + }, func(messageID MessageID, producerMessage *ProducerMessage, err error) { + if err == nil { + r.log.WithField("msgID", msgID).Debug("Succeed to send message to DLQ") + // The Producer ack might be coming from the connection go-routine that + // is also used by the consumer. In that case we would get a dead-lock + // if we'd try to ack. + go cm.Consumer.AckID(msgID) + } else { + r.log.WithError(err).WithField("msgID", msgID).Debug("Failed to send message to DLQ") + go cm.Consumer.Nack(cm) + } + }) + + case <-r.closeCh: + if r.producer != nil { + r.producer.Close() + } + r.log.Debug("Closed DLQ router") + return + } + } +} + +func (r *dlqRouter) close() { + // Attempt to write on the close channel, without blocking + select { + case r.closeCh <- nil: + default: + } +} + +func (r *dlqRouter) getProducer(schema Schema) Producer { + if r.producer != nil { + // Producer was already initialized + return r.producer + } + + // Retry to create producer indefinitely + backoff := &internal.DefaultBackoff{} + for { + opt := r.policy.ProducerOptions + opt.Topic = r.policy.DeadLetterTopic + opt.Schema = schema + + // the origin code sets to LZ4 compression with no options + // so the new design allows compression type to be overwritten but still set lz4 by default + if r.policy.ProducerOptions.CompressionType == NoCompression { + opt.CompressionType = LZ4 + } + producer, err := r.client.CreateProducer(opt) + + if err != nil { + r.log.WithError(err).Error("Failed to create DLQ producer") + time.Sleep(backoff.Next()) + continue + } else { + r.producer = producer + return producer + } + } +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/encryption.go b/vendor/github.com/apache/pulsar-client-go/pulsar/encryption.go new file mode 100644 index 00000000..3ab25278 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/encryption.go @@ -0,0 +1,48 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import "github.com/apache/pulsar-client-go/pulsar/crypto" + +// ProducerEncryptionInfo encryption related fields required by the producer +type ProducerEncryptionInfo struct { + // KeyReader read RSA public/private key pairs + KeyReader crypto.KeyReader + + // MessageCrypto used to encrypt and decrypt the data and session keys + MessageCrypto crypto.MessageCrypto + + // Keys list of encryption key names to encrypt session key + Keys []string + + // ProducerCryptoFailureAction action to be taken on failure of message encryption + // default is ProducerCryptoFailureActionFail + ProducerCryptoFailureAction int +} + +// MessageDecryptionInfo encryption related fields required by the consumer to decrypt the message +type MessageDecryptionInfo struct { + // KeyReader read RSA public/private key pairs + KeyReader crypto.KeyReader + + // MessageCrypto used to encrypt and decrypt the data and session keys + MessageCrypto crypto.MessageCrypto + + // ConsumerCryptoFailureAction action to be taken on failure of message decryption + ConsumerCryptoFailureAction int +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/error.go b/vendor/github.com/apache/pulsar-client-go/pulsar/error.go new file mode 100644 index 00000000..73a0b606 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/error.go @@ -0,0 +1,241 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "fmt" + + proto "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" +) + +// Result used to represent pulsar processing is an alias of type int. +type Result int + +const ( + // Ok means no errors + Ok Result = iota + // UnknownError means unknown error happened on broker + UnknownError + // InvalidConfiguration means invalid configuration + InvalidConfiguration + // TimeoutError means operation timed out + TimeoutError + //LookupError means broker lookup failed + LookupError + // ConnectError means failed to connect to broker + ConnectError + // ReadError means failed to read from socket + ReadError + // AuthenticationError means authentication failed on broker + AuthenticationError + // AuthorizationError client is not authorized to create producer/consumer + AuthorizationError + // ErrorGettingAuthenticationData client cannot find authorization data + ErrorGettingAuthenticationData + // BrokerMetadataError broker failed in updating metadata + BrokerMetadataError + // BrokerPersistenceError broker failed to persist entry + BrokerPersistenceError + // ChecksumError corrupt message checksum failure + ChecksumError + // ConsumerBusy means Exclusive consumer is already connected + ConsumerBusy + // NotConnectedError producer/consumer is not currently connected to broker + NotConnectedError + // AlreadyClosedError producer/consumer is already closed and not accepting any operation + AlreadyClosedError + // InvalidMessage error in publishing an already used message + InvalidMessage + // ConsumerNotInitialized consumer is not initialized + ConsumerNotInitialized + // ProducerNotInitialized producer is not initialized + ProducerNotInitialized + // TooManyLookupRequestException too many concurrent LookupRequest + TooManyLookupRequestException + // InvalidTopicName means invalid topic name + InvalidTopicName + // InvalidURL means Client Initialized with Invalid Broker Url (VIP Url passed to Client Constructor) + InvalidURL + // ServiceUnitNotReady unloaded between client did lookup and producer/consumer got created + ServiceUnitNotReady + // OperationNotSupported operation not supported + OperationNotSupported + // ProducerBlockedQuotaExceededError producer is blocked + ProducerBlockedQuotaExceededError + // ProducerBlockedQuotaExceededException producer is getting exception + ProducerBlockedQuotaExceededException + // ProducerQueueIsFull producer queue is full + ProducerQueueIsFull + // MessageTooBig trying to send a messages exceeding the max size + MessageTooBig + // TopicNotFound topic not found + TopicNotFound + // SubscriptionNotFound subscription not found + SubscriptionNotFound + // ConsumerNotFound consumer not found + ConsumerNotFound + // UnsupportedVersionError when an older client/version doesn't support a required feature + UnsupportedVersionError + // TopicTerminated topic was already terminated + TopicTerminated + // CryptoError error when crypto operation fails + CryptoError + // ConsumerClosed means consumer already been closed + ConsumerClosed + // InvalidBatchBuilderType invalid batch builder type + InvalidBatchBuilderType + // AddToBatchFailed failed to add sendRequest to batchBuilder + AddToBatchFailed + // SeekFailed seek failed + SeekFailed + // ProducerClosed means producer already been closed + ProducerClosed + // SchemaFailure means the payload could not be encoded using the Schema + SchemaFailure + // InvalidStatus means the component status is not as expected. + InvalidStatus + // TransactionNoFoundError The transaction is not exist in the transaction coordinator, It may be an error txn + // or already ended. + TransactionNoFoundError + // ClientMemoryBufferIsFull client limit buffer is full + ClientMemoryBufferIsFull +) + +// Error implement error interface, composed of two parts: msg and result. +type Error struct { + msg string + result Result +} + +// Result get error's original result. +func (e *Error) Result() Result { + return e.result +} + +func (e *Error) Error() string { + return e.msg +} + +func newError(result Result, msg string) error { + return &Error{ + msg: fmt.Sprintf("%s: %s", msg, getResultStr(result)), + result: result, + } +} + +func getResultStr(r Result) string { + switch r { + case Ok: + return "OK" + case UnknownError: + return "UnknownError" + case InvalidConfiguration: + return "InvalidConfiguration" + case TimeoutError: + return "TimeoutError" + case LookupError: + return "LookupError" + case ConnectError: + return "ConnectError" + case ReadError: + return "ReadError" + case AuthenticationError: + return "AuthenticationError" + case AuthorizationError: + return "AuthorizationError" + case ErrorGettingAuthenticationData: + return "ErrorGettingAuthenticationData" + case BrokerMetadataError: + return "BrokerMetadataError" + case BrokerPersistenceError: + return "BrokerPersistenceError" + case ChecksumError: + return "ChecksumError" + case ConsumerBusy: + return "ConsumerBusy" + case NotConnectedError: + return "NotConnectedError" + case AlreadyClosedError: + return "AlreadyClosedError" + case InvalidMessage: + return "InvalidMessage" + case ConsumerNotInitialized: + return "ConsumerNotInitialized" + case ProducerNotInitialized: + return "ProducerNotInitialized" + case TooManyLookupRequestException: + return "TooManyLookupRequestException" + case InvalidTopicName: + return "InvalidTopicName" + case InvalidURL: + return "InvalidURL" + case ServiceUnitNotReady: + return "ServiceUnitNotReady" + case OperationNotSupported: + return "OperationNotSupported" + case ProducerBlockedQuotaExceededError: + return "ProducerBlockedQuotaExceededError" + case ProducerBlockedQuotaExceededException: + return "ProducerBlockedQuotaExceededException" + case ProducerQueueIsFull: + return "ProducerQueueIsFull" + case MessageTooBig: + return "MessageTooBig" + case TopicNotFound: + return "TopicNotFound" + case SubscriptionNotFound: + return "SubscriptionNotFound" + case ConsumerNotFound: + return "ConsumerNotFound" + case UnsupportedVersionError: + return "UnsupportedVersionError" + case TopicTerminated: + return "TopicTerminated" + case CryptoError: + return "CryptoError" + case ConsumerClosed: + return "ConsumerClosed" + case InvalidBatchBuilderType: + return "InvalidBatchBuilderType" + case AddToBatchFailed: + return "AddToBatchFailed" + case SeekFailed: + return "SeekFailed" + case ProducerClosed: + return "ProducerClosed" + case SchemaFailure: + return "SchemaFailure" + case ClientMemoryBufferIsFull: + return "ClientMemoryBufferIsFull" + case TransactionNoFoundError: + return "TransactionNoFoundError" + default: + return fmt.Sprintf("Result(%d)", r) + } +} + +func getErrorFromServerError(serverError *proto.ServerError) error { + switch *serverError { + case proto.ServerError_TransactionNotFound: + return newError(TransactionNoFoundError, serverError.String()) + case proto.ServerError_InvalidTxnStatus: + return newError(InvalidStatus, serverError.String()) + default: + return newError(UnknownError, serverError.String()) + } +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/helper.go b/vendor/github.com/apache/pulsar-client-go/pulsar/helper.go new file mode 100644 index 00000000..5c68731f --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/helper.go @@ -0,0 +1,79 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "fmt" + + pkgerrors "github.com/pkg/errors" + + "google.golang.org/protobuf/proto" + + "github.com/apache/pulsar-client-go/pulsar/internal" + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" +) + +// NewUnexpectedErrMsg instantiates an ErrUnexpectedMsg error. +// Optionally provide a list of IDs associated with the message +// for additional context in the error message. +func newUnexpectedErrMsg(msgType pb.BaseCommand_Type, ids ...interface{}) *unexpectedErrMsg { + return &unexpectedErrMsg{ + msgType: msgType, + ids: ids, + } +} + +// UnexpectedErrMsg is returned when an unexpected message is received. +type unexpectedErrMsg struct { + msgType pb.BaseCommand_Type + ids []interface{} +} + +// Error satisfies the error interface. +func (e *unexpectedErrMsg) Error() string { + msg := fmt.Sprintf("received unexpected message of type %q", e.msgType.String()) + for _, id := range e.ids { + msg += fmt.Sprintf(" consumerID=%v", id) + } + return msg +} + +func validateTopicNames(topics ...string) ([]*internal.TopicName, error) { + tns := make([]*internal.TopicName, len(topics)) + for i, t := range topics { + tn, err := internal.ParseTopicName(t) + if err != nil { + return nil, pkgerrors.Wrapf(err, "invalid topic name: %s", t) + } + tns[i] = tn + } + return tns, nil +} + +func toKeyValues(metadata map[string]string) []*pb.KeyValue { + kvs := make([]*pb.KeyValue, 0, len(metadata)) + for k, v := range metadata { + kv := &pb.KeyValue{ + Key: proto.String(k), + Value: proto.String(v), + } + kvs = append(kvs, kv) + } + + return kvs +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/impl_message.go b/vendor/github.com/apache/pulsar-client-go/pulsar/impl_message.go new file mode 100644 index 00000000..89a709f1 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/impl_message.go @@ -0,0 +1,493 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "errors" + "fmt" + "math" + "sync" + "sync/atomic" + "time" + + "google.golang.org/protobuf/proto" + + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "github.com/bits-and-blooms/bitset" +) + +type messageID struct { + ledgerID int64 + entryID int64 + batchIdx int32 + partitionIdx int32 + batchSize int32 +} + +var latestMessageID = &messageID{ + ledgerID: math.MaxInt64, + entryID: math.MaxInt64, + batchIdx: -1, + partitionIdx: -1, + batchSize: 0, +} + +var earliestMessageID = &messageID{ + ledgerID: -1, + entryID: -1, + batchIdx: -1, + partitionIdx: -1, + batchSize: 0, +} + +type trackingMessageID struct { + *messageID + + tracker *ackTracker + consumer acker + receivedTime time.Time +} + +func (id *trackingMessageID) Ack() error { + if id.consumer == nil { + return errors.New("consumer is nil in trackingMessageID") + } + if id.ack() { + return id.consumer.AckID(id) + } + + return nil +} + +func (id *trackingMessageID) AckWithResponse() error { + if id.consumer == nil { + return errors.New("consumer is nil in trackingMessageID") + } + if id.ack() { + return id.consumer.AckIDWithResponse(id) + } + + return nil +} + +func (id *trackingMessageID) Nack() { + if id.consumer == nil { + return + } + id.consumer.NackID(id) +} + +func (id *trackingMessageID) NackByMsg(msg Message) { + if id.consumer == nil { + return + } + id.consumer.NackMsg(msg) +} + +func (id *trackingMessageID) ack() bool { + if id.tracker != nil && id.batchIdx > -1 { + return id.tracker.ack(int(id.batchIdx)) + } + return true +} + +func (id *trackingMessageID) ackCumulative() bool { + if id.tracker != nil && id.batchIdx > -1 { + return id.tracker.ackCumulative(int(id.batchIdx)) + } + return true +} + +func (id *trackingMessageID) prev() *trackingMessageID { + return &trackingMessageID{ + messageID: &messageID{ + ledgerID: id.ledgerID, + entryID: id.entryID - 1, + partitionIdx: id.partitionIdx, + }, + tracker: id.tracker, + consumer: id.consumer, + } +} + +func (id *messageID) isEntryIDValid() bool { + return id.entryID >= 0 +} + +func (id *messageID) greater(other *messageID) bool { + if id.ledgerID != other.ledgerID { + return id.ledgerID > other.ledgerID + } + + if id.entryID != other.entryID { + return id.entryID > other.entryID + } + + return id.batchIdx > other.batchIdx +} + +func (id *messageID) equal(other *messageID) bool { + return id.ledgerID == other.ledgerID && + id.entryID == other.entryID && + id.batchIdx == other.batchIdx +} + +func (id *messageID) greaterEqual(other *messageID) bool { + return id.equal(other) || id.greater(other) +} + +func (id *messageID) Serialize() []byte { + msgID := &pb.MessageIdData{ + LedgerId: proto.Uint64(uint64(id.ledgerID)), + EntryId: proto.Uint64(uint64(id.entryID)), + BatchIndex: proto.Int32(id.batchIdx), + Partition: proto.Int32(id.partitionIdx), + BatchSize: proto.Int32(id.batchSize), + } + data, _ := proto.Marshal(msgID) + return data +} + +func (id *messageID) LedgerID() int64 { + return id.ledgerID +} + +func (id *messageID) EntryID() int64 { + return id.entryID +} + +func (id *messageID) BatchIdx() int32 { + return id.batchIdx +} + +func (id *messageID) PartitionIdx() int32 { + return id.partitionIdx +} + +func (id *messageID) BatchSize() int32 { + return id.batchSize +} + +func (id *messageID) String() string { + return fmt.Sprintf("%d:%d:%d", id.ledgerID, id.entryID, id.partitionIdx) +} + +func deserializeMessageID(data []byte) (MessageID, error) { + msgID := &pb.MessageIdData{} + err := proto.Unmarshal(data, msgID) + if err != nil { + return nil, err + } + id := newMessageID( + int64(msgID.GetLedgerId()), + int64(msgID.GetEntryId()), + msgID.GetBatchIndex(), + msgID.GetPartition(), + msgID.GetBatchSize(), + ) + return id, nil +} + +func newMessageID(ledgerID int64, entryID int64, batchIdx int32, partitionIdx int32, batchSize int32) MessageID { + return &messageID{ + ledgerID: ledgerID, + entryID: entryID, + batchIdx: batchIdx, + partitionIdx: partitionIdx, + batchSize: batchSize, + } +} + +func fromMessageID(msgID MessageID) *messageID { + return &messageID{ + ledgerID: msgID.LedgerID(), + entryID: msgID.EntryID(), + batchIdx: msgID.BatchIdx(), + partitionIdx: msgID.PartitionIdx(), + batchSize: msgID.BatchSize(), + } +} + +func newTrackingMessageID(ledgerID int64, entryID int64, batchIdx int32, partitionIdx int32, batchSize int32, + tracker *ackTracker) *trackingMessageID { + return &trackingMessageID{ + messageID: &messageID{ + ledgerID: ledgerID, + entryID: entryID, + batchIdx: batchIdx, + partitionIdx: partitionIdx, + batchSize: batchSize, + }, + tracker: tracker, + receivedTime: time.Now(), + } +} + +// checkMessageIDType checks if the MessageID is user-defined +func checkMessageIDType(msgID MessageID) (valid bool) { + switch msgID.(type) { + case *trackingMessageID: + return true + case *chunkMessageID: + return true + case *messageID: + return true + default: + return false + } +} + +func toTrackingMessageID(msgID MessageID) (trackingMsgID *trackingMessageID) { + if mid, ok := msgID.(*trackingMessageID); ok { + return mid + } + return &trackingMessageID{ + messageID: fromMessageID(msgID), + } +} + +func timeFromUnixTimestampMillis(timestamp uint64) time.Time { + ts := int64(timestamp) * int64(time.Millisecond) + seconds := ts / int64(time.Second) + nanos := ts - (seconds * int64(time.Second)) + return time.Unix(seconds, nanos) +} + +// EncryptionContext +// It will be used to decrypt message outside of this client +type EncryptionContext struct { + Keys map[string]EncryptionKey + Param []byte + Algorithm string + CompressionType CompressionType + UncompressedSize int + BatchSize int +} + +// EncryptionKey +// Encryption key used to encrypt the message payload +type EncryptionKey struct { + KeyValue []byte + Metadata map[string]string +} + +type message struct { + publishTime time.Time + eventTime time.Time + key string + orderingKey string + producerName string + payLoad []byte + msgID MessageID + properties map[string]string + topic string + replicationClusters []string + replicatedFrom string + redeliveryCount uint32 + schema Schema + schemaVersion []byte + schemaInfoCache *schemaInfoCache + encryptionContext *EncryptionContext + index *uint64 + brokerPublishTime *time.Time +} + +func (msg *message) Topic() string { + return msg.topic +} + +func (msg *message) Properties() map[string]string { + return msg.properties +} + +func (msg *message) Payload() []byte { + return msg.payLoad +} + +func (msg *message) ID() MessageID { + return msg.msgID +} + +func (msg *message) PublishTime() time.Time { + return msg.publishTime +} + +func (msg *message) EventTime() time.Time { + return msg.eventTime +} + +func (msg *message) Key() string { + return msg.key +} + +func (msg *message) OrderingKey() string { + return msg.orderingKey +} + +func (msg *message) RedeliveryCount() uint32 { + return msg.redeliveryCount +} + +func (msg *message) IsReplicated() bool { + return msg.replicatedFrom != "" +} + +func (msg *message) GetReplicatedFrom() string { + return msg.replicatedFrom +} + +func (msg *message) GetSchemaValue(v interface{}) error { + if msg.schemaVersion != nil { + schema, err := msg.schemaInfoCache.Get(msg.schemaVersion) + if err != nil { + return err + } + return schema.Decode(msg.payLoad, v) + } + return msg.schema.Decode(msg.payLoad, v) +} + +func (msg *message) SchemaVersion() []byte { + return msg.schemaVersion +} + +func (msg *message) ProducerName() string { + return msg.producerName +} + +func (msg *message) GetEncryptionContext() *EncryptionContext { + return msg.encryptionContext +} + +func (msg *message) Index() *uint64 { + return msg.index +} + +func (msg *message) BrokerPublishTime() *time.Time { + return msg.brokerPublishTime +} + +func (msg *message) size() int { + return len(msg.payLoad) +} + +func newAckTracker(size uint) *ackTracker { + batchIDs := bitset.New(size) + for i := uint(0); i < size; i++ { + batchIDs.Set(i) + } + return &ackTracker{ + size: size, + batchIDs: batchIDs, + } +} + +type ackTracker struct { + sync.Mutex + size uint + batchIDs *bitset.BitSet + prevBatchAcked uint32 +} + +func (t *ackTracker) ack(batchID int) bool { + if batchID < 0 { + return true + } + t.Lock() + defer t.Unlock() + t.batchIDs.Clear(uint(batchID)) + return t.batchIDs.None() +} + +func (t *ackTracker) ackCumulative(batchID int) bool { + if batchID < 0 { + return true + } + t.Lock() + defer t.Unlock() + for i := 0; i <= batchID; i++ { + t.batchIDs.Clear(uint(i)) + } + return t.batchIDs.None() +} + +func (t *ackTracker) hasPrevBatchAcked() bool { + return atomic.LoadUint32(&t.prevBatchAcked) == 1 +} + +func (t *ackTracker) setPrevBatchAcked() { + atomic.StoreUint32(&t.prevBatchAcked, 1) +} + +func (t *ackTracker) completed() bool { + t.Lock() + defer t.Unlock() + return t.batchIDs.None() +} + +func (t *ackTracker) toAckSet() []int64 { + t.Lock() + defer t.Unlock() + if t.batchIDs.None() { + return nil + } + bytes := t.batchIDs.Bytes() + ackSet := make([]int64, len(bytes)) + for i := 0; i < len(bytes); i++ { + ackSet[i] = int64(bytes[i]) + } + return ackSet +} + +type chunkMessageID struct { + *messageID + + firstChunkID *messageID + receivedTime time.Time + + consumer acker +} + +func newChunkMessageID(firstChunkID *messageID, lastChunkID *messageID) *chunkMessageID { + return &chunkMessageID{ + messageID: lastChunkID, + firstChunkID: firstChunkID, + receivedTime: time.Now(), + } +} + +func (id chunkMessageID) String() string { + return fmt.Sprintf("%s;%s", id.firstChunkID.String(), id.messageID.String()) +} + +func (id chunkMessageID) Serialize() []byte { + msgID := &pb.MessageIdData{ + LedgerId: proto.Uint64(uint64(id.ledgerID)), + EntryId: proto.Uint64(uint64(id.entryID)), + BatchIndex: proto.Int32(id.batchIdx), + Partition: proto.Int32(id.partitionIdx), + FirstChunkMessageId: &pb.MessageIdData{ + LedgerId: proto.Uint64(uint64(id.firstChunkID.ledgerID)), + EntryId: proto.Uint64(uint64(id.firstChunkID.entryID)), + BatchIndex: proto.Int32(id.firstChunkID.batchIdx), + Partition: proto.Int32(id.firstChunkID.partitionIdx), + }, + } + data, _ := proto.Marshal(msgID) + return data +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/backoff.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/backoff.go new file mode 100644 index 00000000..3284fb7e --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/backoff.go @@ -0,0 +1,63 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "math/rand" + "time" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// BackoffPolicy parameterize the following options in the reconnection logic to +// allow users to customize the reconnection logic (minBackoff, maxBackoff and jitterPercentage) +type BackoffPolicy interface { + Next() time.Duration +} + +// DefaultBackoff computes the delay before retrying an action. +// It uses an exponential backoff with jitter. The jitter represents up to 20 percents of the delay. +type DefaultBackoff struct { + backoff time.Duration +} + +const maxBackoff = 60 * time.Second + +// Next returns the delay to wait before next retry +func (b *DefaultBackoff) Next() time.Duration { + minBackoff := 100 * time.Millisecond + jitterPercentage := 0.2 + + // Double the delay each time + b.backoff += b.backoff + if b.backoff.Nanoseconds() < minBackoff.Nanoseconds() { + b.backoff = minBackoff + } else if b.backoff.Nanoseconds() > maxBackoff.Nanoseconds() { + b.backoff = maxBackoff + } + jitter := rand.Float64() * float64(b.backoff) * jitterPercentage + + return b.backoff + time.Duration(jitter) +} + +// IsMaxBackoffReached evaluates if the max number of retries is reached +func (b *DefaultBackoff) IsMaxBackoffReached() bool { + return b.backoff >= maxBackoff +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/batch_builder.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/batch_builder.go new file mode 100644 index 00000000..649aba48 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/batch_builder.go @@ -0,0 +1,310 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "bytes" + "time" + + "google.golang.org/protobuf/proto" + + "github.com/apache/pulsar-client-go/pulsar/internal/compression" + "github.com/apache/pulsar-client-go/pulsar/internal/crypto" + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "github.com/apache/pulsar-client-go/pulsar/log" +) + +type BuffersPool interface { + GetBuffer() Buffer +} + +// BatcherBuilderProvider defines func which returns the BatchBuilder. +type BatcherBuilderProvider func( + maxMessages uint, maxBatchSize uint, maxMessageSize uint32, producerName string, producerID uint64, + compressionType pb.CompressionType, level compression.Level, + bufferPool BuffersPool, logger log.Logger, encryptor crypto.Encryptor, +) (BatchBuilder, error) + +// BatchBuilder is a interface of batch builders +type BatchBuilder interface { + // IsFull check if the size in the current batch exceeds the maximum size allowed by the batch + IsFull() bool + + // Add will add single message to batch. + Add( + metadata *pb.SingleMessageMetadata, sequenceIDGenerator *uint64, + payload []byte, + callback interface{}, replicateTo []string, deliverAt time.Time, + schemaVersion []byte, multiSchemaEnabled bool, + ) bool + + // Flush all the messages buffered in the client and wait until all messages have been successfully persisted. + Flush() (batchData Buffer, sequenceID uint64, callbacks []interface{}, err error) + + // Flush all the messages buffered in multiple batches and wait until all + // messages have been successfully persisted. + FlushBatches() ( + batchData []Buffer, sequenceID []uint64, callbacks [][]interface{}, errors []error, + ) + + // Return the batch container batch message in multiple batches. + IsMultiBatches() bool + + reset() + Close() error +} + +// batchContainer wraps the objects needed to a batch. +// batchContainer implement BatchBuilder as a single batch container. +type batchContainer struct { + buffer Buffer + + // Current number of messages in the batch + numMessages uint + + // Max number of message allowed in the batch + maxMessages uint + + // The largest size for a batch sent from this particular producer. + // This is used as a baseline to allocate a new buffer that can hold the entire batch + // without needing costly re-allocations. + maxBatchSize uint + + maxMessageSize uint32 + + producerName string + producerID uint64 + + cmdSend *pb.BaseCommand + msgMetadata *pb.MessageMetadata + callbacks []interface{} + + compressionProvider compression.Provider + buffersPool BuffersPool + + log log.Logger + + encryptor crypto.Encryptor +} + +// newBatchContainer init a batchContainer +func newBatchContainer( + maxMessages uint, maxBatchSize uint, maxMessageSize uint32, producerName string, producerID uint64, + compressionType pb.CompressionType, level compression.Level, + bufferPool BuffersPool, logger log.Logger, encryptor crypto.Encryptor, +) batchContainer { + + bc := batchContainer{ + buffer: NewBuffer(4096), + numMessages: 0, + maxMessages: maxMessages, + maxBatchSize: maxBatchSize, + maxMessageSize: maxMessageSize, + producerName: producerName, + producerID: producerID, + cmdSend: baseCommand( + pb.BaseCommand_SEND, + &pb.CommandSend{ + ProducerId: &producerID, + }, + ), + msgMetadata: &pb.MessageMetadata{ + ProducerName: &producerName, + }, + callbacks: []interface{}{}, + compressionProvider: GetCompressionProvider(compressionType, level), + buffersPool: bufferPool, + log: logger, + encryptor: encryptor, + } + + if compressionType != pb.CompressionType_NONE { + bc.msgMetadata.Compression = &compressionType + } + + return bc +} + +// NewBatchBuilder init batch builder and return BatchBuilder pointer. Build a new batch message container. +func NewBatchBuilder( + maxMessages uint, maxBatchSize uint, maxMessageSize uint32, producerName string, producerID uint64, + compressionType pb.CompressionType, level compression.Level, + bufferPool BuffersPool, logger log.Logger, encryptor crypto.Encryptor, +) (BatchBuilder, error) { + + bc := newBatchContainer( + maxMessages, maxBatchSize, maxMessageSize, producerName, producerID, compressionType, + level, bufferPool, logger, encryptor, + ) + + return &bc, nil +} + +// IsFull checks if the size in the current batch meets or exceeds the maximum size allowed by the batch +func (bc *batchContainer) IsFull() bool { + return bc.numMessages >= bc.maxMessages || bc.buffer.ReadableBytes() >= uint32(bc.maxBatchSize) +} + +// hasSpace should return true if and only if the batch container can accommodate another message of length payload. +func (bc *batchContainer) hasSpace(payload []byte) bool { + if bc.numMessages == 0 { + // allow to add at least one message when batching is disabled + return true + } + msgSize := uint32(len(payload)) + expectedSize := bc.buffer.ReadableBytes() + msgSize + return bc.numMessages+1 <= bc.maxMessages && + expectedSize <= uint32(bc.maxBatchSize) && expectedSize <= bc.maxMessageSize +} + +func (bc *batchContainer) hasSameSchema(schemaVersion []byte) bool { + if bc.numMessages == 0 { + return true + } + return bytes.Equal(bc.msgMetadata.SchemaVersion, schemaVersion) +} + +// Add will add single message to batch. +func (bc *batchContainer) Add( + metadata *pb.SingleMessageMetadata, sequenceIDGenerator *uint64, + payload []byte, + callback interface{}, replicateTo []string, deliverAt time.Time, + schemaVersion []byte, multiSchemaEnabled bool, +) bool { + + if replicateTo != nil && bc.numMessages != 0 { + // If the current batch is not empty and we're trying to set the replication clusters, + // then we need to force the current batch to flush and send the message individually + return false + } else if bc.msgMetadata.ReplicateTo != nil { + // There's already a message with cluster replication list. need to flush before next + // message can be sent + return false + } else if !bc.hasSpace(payload) { + // The current batch is full. Producer has to call Flush() to + return false + } else if multiSchemaEnabled && !bc.hasSameSchema(schemaVersion) { + // The current batch has a different schema. Producer has to call Flush() to + return false + } + + if bc.numMessages == 0 { + var sequenceID uint64 + if metadata.SequenceId != nil { + sequenceID = *metadata.SequenceId + } else { + sequenceID = GetAndAdd(sequenceIDGenerator, 1) + } + bc.msgMetadata.SequenceId = proto.Uint64(sequenceID) + bc.msgMetadata.PublishTime = proto.Uint64(TimestampMillis(time.Now())) + bc.msgMetadata.ProducerName = &bc.producerName + bc.msgMetadata.ReplicateTo = replicateTo + bc.msgMetadata.PartitionKey = metadata.PartitionKey + bc.msgMetadata.SchemaVersion = schemaVersion + bc.msgMetadata.Properties = metadata.Properties + + if deliverAt.UnixNano() > 0 { + bc.msgMetadata.DeliverAtTime = proto.Int64(int64(TimestampMillis(deliverAt))) + } + + bc.cmdSend.Send.SequenceId = proto.Uint64(sequenceID) + } + addSingleMessageToBatch(bc.buffer, metadata, payload) + + bc.numMessages++ + bc.callbacks = append(bc.callbacks, callback) + return true +} + +func (bc *batchContainer) reset() { + bc.numMessages = 0 + bc.buffer.Clear() + bc.callbacks = []interface{}{} + bc.msgMetadata.ReplicateTo = nil + bc.msgMetadata.DeliverAtTime = nil + bc.msgMetadata.SchemaVersion = nil + bc.msgMetadata.Properties = nil +} + +// Flush all the messages buffered in the client and wait until all messages have been successfully persisted. +func (bc *batchContainer) Flush() ( + batchData Buffer, sequenceID uint64, callbacks []interface{}, err error, +) { + if bc.numMessages == 0 { + // No-Op for empty batch + return nil, 0, nil, nil + } + + bc.log.Debug("BatchBuilder flush: messages: ", bc.numMessages) + + bc.msgMetadata.NumMessagesInBatch = proto.Int32(int32(bc.numMessages)) + bc.cmdSend.Send.NumMessages = proto.Int32(int32(bc.numMessages)) + + uncompressedSize := bc.buffer.ReadableBytes() + bc.msgMetadata.UncompressedSize = &uncompressedSize + + buffer := bc.buffersPool.GetBuffer() + if buffer == nil { + buffer = NewBuffer(int(uncompressedSize * 3 / 2)) + } + + if err = serializeMessage( + buffer, bc.cmdSend, bc.msgMetadata, bc.buffer, bc.compressionProvider, + bc.encryptor, bc.maxMessageSize, true, + ); err == nil { // no error in serializing Batch + sequenceID = bc.cmdSend.Send.GetSequenceId() + } + + callbacks = bc.callbacks + bc.reset() + return buffer, sequenceID, callbacks, err +} + +// FlushBatches only for multiple batches container +func (bc *batchContainer) FlushBatches() ( + batchData []Buffer, sequenceID []uint64, callbacks [][]interface{}, errors []error, +) { + panic("single batch container not support FlushBatches(), please use Flush() instead") +} + +// batchContainer as a single batch container +func (bc *batchContainer) IsMultiBatches() bool { + return false +} + +func (bc *batchContainer) Close() error { + return bc.compressionProvider.Close() +} + +func GetCompressionProvider( + compressionType pb.CompressionType, + level compression.Level, +) compression.Provider { + switch compressionType { + case pb.CompressionType_NONE: + return compression.NewNoopProvider() + case pb.CompressionType_LZ4: + return compression.NewLz4Provider() + case pb.CompressionType_ZLIB: + return compression.NewZLibProvider() + case pb.CompressionType_ZSTD: + return compression.NewZStdProvider(level) + default: + panic("unsupported compression type") + } +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/blocking_queue.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/blocking_queue.go new file mode 100644 index 00000000..b44ec166 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/blocking_queue.go @@ -0,0 +1,194 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "sync" +) + +// BlockingQueue is a interface of block queue +type BlockingQueue interface { + // Put enqueue one item, block if the queue is full + Put(item interface{}) + + // Take dequeue one item, block until it's available + Take() interface{} + + // Poll dequeue one item, return nil if queue is empty + Poll() interface{} + + // CompareAndPoll compare the first item and poll it if meet the conditions + CompareAndPoll(compare func(item interface{}) bool) interface{} + + // Peek return the first item without dequeing, return nil if queue is empty + Peek() interface{} + + // PeekLast return last item in queue without dequeing, return nil if queue is empty + PeekLast() interface{} + + // Size return the current size of the queue + Size() int + + // ReadableSlice returns a new view of the readable items in the queue + ReadableSlice() []interface{} +} + +type blockingQueue struct { + items []interface{} + headIdx int + tailIdx int + size int + maxSize int + + mutex sync.Mutex + isNotEmpty *sync.Cond + isNotFull *sync.Cond +} + +// NewBlockingQueue init block queue and returns a BlockingQueue +func NewBlockingQueue(maxSize int) BlockingQueue { + bq := &blockingQueue{ + items: make([]interface{}, maxSize), + headIdx: 0, + tailIdx: 0, + size: 0, + maxSize: maxSize, + } + + bq.isNotEmpty = sync.NewCond(&bq.mutex) + bq.isNotFull = sync.NewCond(&bq.mutex) + return bq +} + +func (bq *blockingQueue) Put(item interface{}) { + bq.mutex.Lock() + defer bq.mutex.Unlock() + + for bq.size == bq.maxSize { + bq.isNotFull.Wait() + } + + wasEmpty := bq.size == 0 + + bq.items[bq.tailIdx] = item + bq.size++ + bq.tailIdx++ + if bq.tailIdx >= bq.maxSize { + bq.tailIdx = 0 + } + + if wasEmpty { + // Wake up eventual reader waiting for next item + bq.isNotEmpty.Signal() + } +} + +func (bq *blockingQueue) Take() interface{} { + bq.mutex.Lock() + defer bq.mutex.Unlock() + + for bq.size == 0 { + bq.isNotEmpty.Wait() + } + + return bq.dequeue() +} + +func (bq *blockingQueue) Poll() interface{} { + bq.mutex.Lock() + defer bq.mutex.Unlock() + + if bq.size == 0 { + return nil + } + + return bq.dequeue() +} + +func (bq *blockingQueue) CompareAndPoll(compare func(interface{}) bool) interface{} { + bq.mutex.Lock() + defer bq.mutex.Unlock() + + if bq.size == 0 { + return nil + } + + if compare(bq.items[bq.headIdx]) { + return bq.dequeue() + } + return nil +} + +func (bq *blockingQueue) Peek() interface{} { + bq.mutex.Lock() + defer bq.mutex.Unlock() + + if bq.size == 0 { + return nil + } + return bq.items[bq.headIdx] +} + +func (bq *blockingQueue) PeekLast() interface{} { + bq.mutex.Lock() + defer bq.mutex.Unlock() + + if bq.size == 0 { + return nil + } + idx := (bq.headIdx + bq.size - 1) % bq.maxSize + return bq.items[idx] +} + +func (bq *blockingQueue) dequeue() interface{} { + item := bq.items[bq.headIdx] + bq.items[bq.headIdx] = nil + + bq.headIdx++ + if bq.headIdx == len(bq.items) { + bq.headIdx = 0 + } + + bq.size-- + bq.isNotFull.Signal() + return item +} + +func (bq *blockingQueue) Size() int { + bq.mutex.Lock() + defer bq.mutex.Unlock() + + return bq.size +} + +func (bq *blockingQueue) ReadableSlice() []interface{} { + bq.mutex.Lock() + defer bq.mutex.Unlock() + + res := make([]interface{}, bq.size) + readIdx := bq.headIdx + for i := 0; i < bq.size; i++ { + res[i] = bq.items[readIdx] + readIdx++ + if readIdx == bq.maxSize { + readIdx = 0 + } + } + + return res +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/buffer.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/buffer.go new file mode 100644 index 00000000..b3e23fbe --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/buffer.go @@ -0,0 +1,219 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "encoding/binary" + + log "github.com/sirupsen/logrus" +) + +// Buffer is a variable-sized buffer of bytes with Read and Write methods. +// The zero value for Buffer is an empty buffer ready to use. +type Buffer interface { + ReadableBytes() uint32 + + WritableBytes() uint32 + + // Capacity returns the capacity of the buffer's underlying byte slice, + // that is, the total space allocated for the buffer's data. + Capacity() uint32 + + IsWritable() bool + + Read(size uint32) []byte + + Skip(size uint32) + + Get(readerIndex uint32, size uint32) []byte + + ReadableSlice() []byte + + WritableSlice() []byte + + // WrittenBytes advance the writer index when data was written in a slice + WrittenBytes(size uint32) + + // MoveToFront copy the available portion of data at the beginning of the buffer + MoveToFront() + + ReadUint16() uint16 + ReadUint32() uint32 + + WriteUint16(n uint16) + WriteUint32(n uint32) + + WriterIndex() uint32 + ReaderIndex() uint32 + + Write(s []byte) + + Put(writerIdx uint32, s []byte) + PutUint32(n uint32, writerIdx uint32) + + Resize(newSize uint32) + ResizeIfNeeded(spaceNeeded uint32) + + // Clear will clear the current buffer data. + Clear() +} + +type buffer struct { + data []byte + + readerIdx uint32 + writerIdx uint32 +} + +// NewBuffer creates and initializes a new Buffer using buf as its initial contents. +func NewBuffer(size int) Buffer { + return &buffer{ + data: make([]byte, size), + readerIdx: 0, + writerIdx: 0, + } +} + +func NewBufferWrapper(buf []byte) Buffer { + return &buffer{ + data: buf, + readerIdx: 0, + writerIdx: uint32(len(buf)), + } +} + +func (b *buffer) ReadableBytes() uint32 { + return b.writerIdx - b.readerIdx +} + +func (b *buffer) WritableBytes() uint32 { + return uint32(cap(b.data)) - b.writerIdx +} + +func (b *buffer) Capacity() uint32 { + return uint32(cap(b.data)) +} + +func (b *buffer) IsWritable() bool { + return b.WritableBytes() > 0 +} + +func (b *buffer) Read(size uint32) []byte { + // Check []byte slice size, avoid slice bounds out of range + if b.readerIdx+size > uint32(len(b.data)) { + log.Errorf("The input size [%d] > byte slice of data size [%d]", b.readerIdx+size, len(b.data)) + return nil + } + res := b.data[b.readerIdx : b.readerIdx+size] + b.readerIdx += size + return res +} + +func (b *buffer) Skip(size uint32) { + b.readerIdx += size +} + +func (b *buffer) Get(readerIdx uint32, size uint32) []byte { + return b.data[readerIdx : readerIdx+size] +} + +func (b *buffer) ReadableSlice() []byte { + return b.data[b.readerIdx:b.writerIdx] +} + +func (b *buffer) WritableSlice() []byte { + return b.data[b.writerIdx:] +} + +func (b *buffer) WrittenBytes(size uint32) { + b.writerIdx += size +} + +func (b *buffer) WriterIndex() uint32 { + return b.writerIdx +} + +func (b *buffer) ReaderIndex() uint32 { + return b.readerIdx +} + +func (b *buffer) MoveToFront() { + size := b.ReadableBytes() + copy(b.data, b.Read(size)) + b.readerIdx = 0 + b.writerIdx = size +} + +func (b *buffer) Resize(newSize uint32) { + newData := make([]byte, newSize) + size := b.ReadableBytes() + copy(newData, b.Read(size)) + b.data = newData + b.readerIdx = 0 + b.writerIdx = size +} + +func (b *buffer) ResizeIfNeeded(spaceNeeded uint32) { + if b.WritableBytes() < spaceNeeded { + capacityNeeded := uint32(cap(b.data)) + spaceNeeded + minCapacityIncrease := uint32(cap(b.data) * 3 / 2) + if capacityNeeded < minCapacityIncrease { + capacityNeeded = minCapacityIncrease + } + b.Resize(capacityNeeded) + } +} + +func (b *buffer) ReadUint32() uint32 { + return binary.BigEndian.Uint32(b.Read(4)) +} + +func (b *buffer) ReadUint16() uint16 { + return binary.BigEndian.Uint16(b.Read(2)) +} + +func (b *buffer) WriteUint32(n uint32) { + b.ResizeIfNeeded(4) + binary.BigEndian.PutUint32(b.WritableSlice(), n) + b.writerIdx += 4 +} + +func (b *buffer) PutUint32(n uint32, idx uint32) { + binary.BigEndian.PutUint32(b.data[idx:], n) +} + +func (b *buffer) WriteUint16(n uint16) { + b.ResizeIfNeeded(2) + binary.BigEndian.PutUint16(b.WritableSlice(), n) + b.writerIdx += 2 +} + +func (b *buffer) Write(s []byte) { + b.ResizeIfNeeded(uint32(len(s))) + copy(b.WritableSlice(), s) + b.writerIdx += uint32(len(s)) +} + +func (b *buffer) Put(writerIdx uint32, s []byte) { + copy(b.data[writerIdx:], s) +} + +func (b *buffer) Clear() { + b.readerIdx = 0 + b.writerIdx = 0 +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/channel_cond.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/channel_cond.go new file mode 100644 index 00000000..38301abe --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/channel_cond.go @@ -0,0 +1,76 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "context" + "sync" + "sync/atomic" + "unsafe" +) + +type chCond struct { + L sync.Locker + // The pointer to the channel, the channel pointed to may change, + // because we will use the channel's close mechanism to implement broadcast notifications. + notifyChPtr unsafe.Pointer +} + +func newCond(l sync.Locker) *chCond { + c := &chCond{L: l} + n := make(chan struct{}) + c.notifyChPtr = unsafe.Pointer(&n) + return c +} + +// wait for broadcast calls. Similar to regular sync.Cond +func (c *chCond) wait() { + n := c.notifyChan() + c.L.Unlock() + <-n + c.L.Lock() +} + +// waitWithContext Same as wait() call, but the end condition can also be controlled through the context. +func (c *chCond) waitWithContext(ctx context.Context) bool { + n := c.notifyChan() + c.L.Unlock() + defer c.L.Lock() + select { + case <-n: + return true + case <-ctx.Done(): + return false + default: + return true + } +} + +// broadcast wakes all goroutines waiting on c. +// It is not required for the caller to hold c.L during the call. +func (c *chCond) broadcast() { + n := make(chan struct{}) + ptrOld := atomic.SwapPointer(&c.notifyChPtr, unsafe.Pointer(&n)) + // close old channels to trigger broadcast. + close(*(*chan struct{})(ptrOld)) +} + +func (c *chCond) notifyChan() <-chan struct{} { + ptr := atomic.LoadPointer(&c.notifyChPtr) + return *((*chan struct{})(ptr)) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/checksum.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/checksum.go new file mode 100644 index 00000000..e7cf7874 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/checksum.go @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "hash" + "hash/crc32" +) + +// crc32cTable holds the precomputed crc32 hash table +// used by Pulsar (crc32c) +var crc32cTable = crc32.MakeTable(crc32.Castagnoli) + +type CheckSum struct { + hash hash.Hash +} + +// Crc32cCheckSum handles computing the checksum. +func Crc32cCheckSum(data []byte) uint32 { + return crc32.Checksum(data, crc32cTable) +} + +func (cs *CheckSum) Write(p []byte) (int, error) { + if cs.hash == nil { + cs.hash = crc32.New(crc32cTable) + } + return cs.hash.Write(p) +} + +func (cs *CheckSum) compute() []byte { + if cs.hash == nil { + return nil + } + return cs.hash.Sum(nil) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/client_handlers.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/client_handlers.go new file mode 100644 index 00000000..39b9bb78 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/client_handlers.go @@ -0,0 +1,63 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import "sync" + +// ClientHandlerMap is a simple concurrent-safe map for the client type +type ClientHandlers struct { + handlers map[Closable]bool + l *sync.RWMutex +} + +func NewClientHandlers() ClientHandlers { + return ClientHandlers{ + handlers: map[Closable]bool{}, + l: &sync.RWMutex{}, + } +} +func (h *ClientHandlers) Add(c Closable) { + h.l.Lock() + defer h.l.Unlock() + h.handlers[c] = true +} + +func (h *ClientHandlers) Del(c Closable) { + h.l.Lock() + defer h.l.Unlock() + delete(h.handlers, c) +} + +func (h *ClientHandlers) Val(c Closable) bool { + h.l.RLock() + defer h.l.RUnlock() + return h.handlers[c] +} + +func (h *ClientHandlers) Close() { + h.l.Lock() + handlers := make([]Closable, 0, len(h.handlers)) + for handler := range h.handlers { + handlers = append(handlers, handler) + } + h.l.Unlock() + + for _, handler := range handlers { + handler.Close() + } +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/closable.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/closable.go new file mode 100644 index 00000000..ac26e1ea --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/closable.go @@ -0,0 +1,22 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +type Closable interface { + Close() +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/commands.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/commands.go new file mode 100644 index 00000000..00e075be --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/commands.go @@ -0,0 +1,378 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "encoding/binary" + "errors" + "fmt" + + "google.golang.org/protobuf/proto" + + "github.com/apache/pulsar-client-go/pulsar/internal/compression" + "github.com/apache/pulsar-client-go/pulsar/internal/crypto" + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" +) + +const ( + // MaxMessageSize limit message size for transfer + MaxMessageSize = 5 * 1024 * 1024 + // MessageFramePadding is for metadata and other frame headers + MessageFramePadding = 10 * 1024 + // MaxFrameSize limit the maximum size that pulsar allows for messages to be sent. + MaxFrameSize = MaxMessageSize + MessageFramePadding + magicCrc32c uint16 = 0x0e01 + magicBrokerEntryMetadata uint16 = 0x0e02 +) + +// ErrCorruptedMessage is the error returned by ReadMessageData when it has detected corrupted data. +// The data is considered corrupted if it's missing a header, a checksum mismatch or there +// was an error when unmarshalling the message metadata. +var ErrCorruptedMessage = errors.New("corrupted message") + +// ErrEOM is the error returned by ReadMessage when no more input is available. +var ErrEOM = errors.New("EOF") + +var ErrConnectionClosed = errors.New("connection closed") + +var ErrExceedMaxMessageSize = errors.New("encryptedPayload exceeds MaxMessageSize") + +func NewMessageReader(headersAndPayload Buffer) *MessageReader { + return &MessageReader{ + buffer: headersAndPayload, + } +} + +func NewMessageReaderFromArray(headersAndPayload []byte) *MessageReader { + return NewMessageReader(NewBufferWrapper(headersAndPayload)) +} + +// MessageReader provides helper methods to parse +// the metadata and messages from the binary format +// Wire format for a messages +// +// Old format (single message) +// [MAGIC_NUMBER][CHECKSUM] [METADATA_SIZE][METADATA] [PAYLOAD] +// +// Batch format +// [MAGIC_NUMBER][CHECKSUM] [METADATA_SIZE][METADATA] [METADATA_SIZE][METADATA][PAYLOAD] +// [METADATA_SIZE][METADATA][PAYLOAD] +type MessageReader struct { + buffer Buffer + // true if we are parsing a batched message - set after parsing the message metadata + batched bool +} + +// ReadChecksum +func (r *MessageReader) readChecksum() (uint32, error) { + if r.buffer.ReadableBytes() < 6 { + return 0, errors.New("missing message header") + } + // reader magic number + magicNumber := r.buffer.ReadUint16() + if magicNumber != magicCrc32c { + return 0, ErrCorruptedMessage + } + checksum := r.buffer.ReadUint32() + return checksum, nil +} + +func (r *MessageReader) ReadMessageMetadata() (*pb.MessageMetadata, error) { + // Wire format + // [MAGIC_NUMBER][CHECKSUM] [METADATA_SIZE][METADATA] + + // read checksum + checksum, err := r.readChecksum() + if err != nil { + return nil, err + } + + // validate checksum + computedChecksum := Crc32cCheckSum(r.buffer.ReadableSlice()) + if checksum != computedChecksum { + return nil, fmt.Errorf("checksum mismatch received: 0x%x computed: 0x%x", checksum, computedChecksum) + } + + size := r.buffer.ReadUint32() + data := r.buffer.Read(size) + var meta pb.MessageMetadata + if err := proto.Unmarshal(data, &meta); err != nil { + return nil, ErrCorruptedMessage + } + + if meta.NumMessagesInBatch != nil { + r.batched = true + } + + return &meta, nil +} + +func (r *MessageReader) ReadBrokerMetadata() (*pb.BrokerEntryMetadata, error) { + magicNumber := binary.BigEndian.Uint16(r.buffer.Get(r.buffer.ReaderIndex(), 2)) + if magicNumber != magicBrokerEntryMetadata { + return nil, nil + } + r.buffer.Skip(2) + size := r.buffer.ReadUint32() + var brokerEntryMetadata pb.BrokerEntryMetadata + if err := proto.Unmarshal(r.buffer.Read(size), &brokerEntryMetadata); err != nil { + return nil, err + } + return &brokerEntryMetadata, nil +} + +func (r *MessageReader) ReadMessage() (*pb.SingleMessageMetadata, []byte, error) { + if r.buffer.ReadableBytes() == 0 && r.buffer.Capacity() > 0 { + return nil, nil, ErrEOM + } + if !r.batched { + return r.readMessage() + } + + return r.readSingleMessage() +} + +func (r *MessageReader) readMessage() (*pb.SingleMessageMetadata, []byte, error) { + // Wire format + // [PAYLOAD] + + return nil, r.buffer.Read(r.buffer.ReadableBytes()), nil +} + +func (r *MessageReader) readSingleMessage() (*pb.SingleMessageMetadata, []byte, error) { + // Wire format + // [METADATA_SIZE][METADATA][PAYLOAD] + + size := r.buffer.ReadUint32() + var meta pb.SingleMessageMetadata + if err := proto.Unmarshal(r.buffer.Read(size), &meta); err != nil { + return nil, nil, err + } + + return &meta, r.buffer.Read(uint32(meta.GetPayloadSize())), nil +} + +func (r *MessageReader) ResetBuffer(buffer Buffer) { + r.buffer = buffer +} + +func baseCommand(cmdType pb.BaseCommand_Type, msg proto.Message) *pb.BaseCommand { + cmd := &pb.BaseCommand{ + Type: &cmdType, + } + switch cmdType { + case pb.BaseCommand_CONNECT: + cmd.Connect = msg.(*pb.CommandConnect) + case pb.BaseCommand_LOOKUP: + cmd.LookupTopic = msg.(*pb.CommandLookupTopic) + case pb.BaseCommand_PARTITIONED_METADATA: + cmd.PartitionMetadata = msg.(*pb.CommandPartitionedTopicMetadata) + case pb.BaseCommand_PRODUCER: + cmd.Producer = msg.(*pb.CommandProducer) + case pb.BaseCommand_SUBSCRIBE: + cmd.Subscribe = msg.(*pb.CommandSubscribe) + case pb.BaseCommand_FLOW: + cmd.Flow = msg.(*pb.CommandFlow) + case pb.BaseCommand_PING: + cmd.Ping = msg.(*pb.CommandPing) + case pb.BaseCommand_PONG: + cmd.Pong = msg.(*pb.CommandPong) + case pb.BaseCommand_SEND: + cmd.Send = msg.(*pb.CommandSend) + case pb.BaseCommand_SEND_ERROR: + cmd.SendError = msg.(*pb.CommandSendError) + case pb.BaseCommand_CLOSE_PRODUCER: + cmd.CloseProducer = msg.(*pb.CommandCloseProducer) + case pb.BaseCommand_CLOSE_CONSUMER: + cmd.CloseConsumer = msg.(*pb.CommandCloseConsumer) + case pb.BaseCommand_ACK: + cmd.Ack = msg.(*pb.CommandAck) + case pb.BaseCommand_SEEK: + cmd.Seek = msg.(*pb.CommandSeek) + case pb.BaseCommand_UNSUBSCRIBE: + cmd.Unsubscribe = msg.(*pb.CommandUnsubscribe) + case pb.BaseCommand_REDELIVER_UNACKNOWLEDGED_MESSAGES: + cmd.RedeliverUnacknowledgedMessages = msg.(*pb.CommandRedeliverUnacknowledgedMessages) + case pb.BaseCommand_GET_TOPICS_OF_NAMESPACE: + cmd.GetTopicsOfNamespace = msg.(*pb.CommandGetTopicsOfNamespace) + case pb.BaseCommand_GET_LAST_MESSAGE_ID: + cmd.GetLastMessageId = msg.(*pb.CommandGetLastMessageId) + case pb.BaseCommand_AUTH_RESPONSE: + cmd.AuthResponse = msg.(*pb.CommandAuthResponse) + case pb.BaseCommand_GET_OR_CREATE_SCHEMA: + cmd.GetOrCreateSchema = msg.(*pb.CommandGetOrCreateSchema) + case pb.BaseCommand_GET_SCHEMA: + cmd.GetSchema = msg.(*pb.CommandGetSchema) + case pb.BaseCommand_TC_CLIENT_CONNECT_REQUEST: + cmd.TcClientConnectRequest = msg.(*pb.CommandTcClientConnectRequest) + case pb.BaseCommand_NEW_TXN: + cmd.NewTxn = msg.(*pb.CommandNewTxn) + case pb.BaseCommand_ADD_PARTITION_TO_TXN: + cmd.AddPartitionToTxn = msg.(*pb.CommandAddPartitionToTxn) + case pb.BaseCommand_ADD_SUBSCRIPTION_TO_TXN: + cmd.AddSubscriptionToTxn = msg.(*pb.CommandAddSubscriptionToTxn) + case pb.BaseCommand_END_TXN: + cmd.EndTxn = msg.(*pb.CommandEndTxn) + + default: + panic(fmt.Sprintf("Missing command type: %v", cmdType)) + } + + return cmd +} + +func addSingleMessageToBatch(wb Buffer, smm *pb.SingleMessageMetadata, payload []byte) { + metadataSize := uint32(proto.Size(smm)) + wb.WriteUint32(metadataSize) + + wb.ResizeIfNeeded(metadataSize) + err := MarshalToSizedBuffer(smm, wb.WritableSlice()[:metadataSize]) + if err != nil { + panic(fmt.Sprintf("Protobuf serialization error: %v", err)) + } + + wb.WrittenBytes(metadataSize) + wb.Write(payload) +} + +func serializeMessage(wb Buffer, + cmdSend *pb.BaseCommand, + msgMetadata *pb.MessageMetadata, + payload Buffer, + compressionProvider compression.Provider, + encryptor crypto.Encryptor, + maxMessageSize uint32, + doCompress bool) error { + // Wire format + // [TOTAL_SIZE] [CMD_SIZE][CMD] [MAGIC_NUMBER][CHECKSUM] [METADATA_SIZE][METADATA] [PAYLOAD] + + // compress the payload + var compressedPayload []byte + if doCompress { + compressedPayload = compressionProvider.Compress(nil, payload.ReadableSlice()) + } else { + compressedPayload = payload.ReadableSlice() + } + + // encrypt the compressed payload + encryptedPayload, err := encryptor.Encrypt(compressedPayload, msgMetadata) + if err != nil { + // error occurred while encrypting the payload, ProducerCryptoFailureAction is set to Fail + return fmt.Errorf("encryption of message failed, ProducerCryptoFailureAction is set to Fail. Error :%v", err) + } + + cmdSize := uint32(proto.Size(cmdSend)) + msgMetadataSize := uint32(proto.Size(msgMetadata)) + msgSize := len(encryptedPayload) + int(msgMetadataSize) + + // the maxMessageSize check of batching message is in here + if !(msgMetadata.GetTotalChunkMsgSize() != 0) && msgSize > int(maxMessageSize) { + return fmt.Errorf("%w, size: %d, MaxMessageSize: %d", + ErrExceedMaxMessageSize, msgSize, maxMessageSize) + } + + frameSizeIdx := wb.WriterIndex() + wb.WriteUint32(0) // Skip frame size until we now the size + frameStartIdx := wb.WriterIndex() + + // Write cmd + wb.WriteUint32(cmdSize) + wb.ResizeIfNeeded(cmdSize) + err = MarshalToSizedBuffer(cmdSend, wb.WritableSlice()[:cmdSize]) + if err != nil { + panic(fmt.Sprintf("Protobuf error when serializing cmdSend: %v", err)) + } + wb.WrittenBytes(cmdSize) + + // Create checksum placeholder + wb.WriteUint16(magicCrc32c) + checksumIdx := wb.WriterIndex() + wb.WriteUint32(0) // skip 4 bytes of checksum + + // Write metadata + metadataStartIdx := wb.WriterIndex() + wb.WriteUint32(msgMetadataSize) + wb.ResizeIfNeeded(msgMetadataSize) + err = MarshalToSizedBuffer(msgMetadata, wb.WritableSlice()[:msgMetadataSize]) + if err != nil { + panic(fmt.Sprintf("Protobuf error when serializing msgMetadata: %v", err)) + } + wb.WrittenBytes(msgMetadataSize) + + // add payload to the buffer + wb.Write(encryptedPayload) + + // Write checksum at created checksum-placeholder + frameEndIdx := wb.WriterIndex() + checksum := Crc32cCheckSum(wb.Get(metadataStartIdx, frameEndIdx-metadataStartIdx)) + + // Set Sizes and checksum in the fixed-size header + wb.PutUint32(frameEndIdx-frameStartIdx, frameSizeIdx) // External frame + wb.PutUint32(checksum, checksumIdx) + return nil +} + +func SingleSend(wb Buffer, + producerID, sequenceID uint64, + msgMetadata *pb.MessageMetadata, + compressedPayload Buffer, + encryptor crypto.Encryptor, + maxMassageSize uint32) error { + cmdSend := baseCommand( + pb.BaseCommand_SEND, + &pb.CommandSend{ + ProducerId: &producerID, + }, + ) + cmdSend.Send.SequenceId = &sequenceID + if msgMetadata.GetTotalChunkMsgSize() > 1 { + isChunk := true + cmdSend.Send.IsChunk = &isChunk + } + // payload has been compressed so compressionProvider can be nil + return serializeMessage(wb, cmdSend, msgMetadata, compressedPayload, + nil, encryptor, maxMassageSize, false) +} + +// ConvertFromStringMap convert a string map to a KeyValue []byte +func ConvertFromStringMap(m map[string]string) []*pb.KeyValue { + list := make([]*pb.KeyValue, len(m)) + + i := 0 + for k, v := range m { + list[i] = &pb.KeyValue{ + Key: proto.String(k), + Value: proto.String(v), + } + + i++ + } + + return list +} + +// ConvertToStringMap convert a KeyValue []byte to string map +func ConvertToStringMap(pbb []*pb.KeyValue) map[string]string { + m := make(map[string]string) + + for _, kv := range pbb { + m[*kv.Key] = *kv.Value + } + + return m +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/compression.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/compression.go new file mode 100644 index 00000000..a4504bf1 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/compression.go @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package compression + +import "io" + +type Level int + +const ( + Default Level = iota + Faster + Better +) + +// Provider is a interface of compression providers +type Provider interface { + // Return the max possible size for a compressed buffer given the uncompressed data size + CompressMaxSize(originalSize int) int + + // Compress a []byte, the param is a []byte with the uncompressed content. + // The reader/writer indexes will not be modified. The return is a []byte + // with the compressed content. + Compress(dst, src []byte) []byte + + // Decompress a []byte. The buffer needs to have been compressed with the matching Encoder. + // The src is compressed content. If dst is passed, the decompressed data will be written there + // The return were the result will be passed, if err is nil, the buffer was decompressed, no nil otherwise. + Decompress(dst, src []byte, originalSize int) ([]byte, error) + + // Returns a new instance of the same provider, with the same exact configuration + Clone() Provider + + // Close the compressor + io.Closer +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/lz4.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/lz4.go new file mode 100644 index 00000000..745ea831 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/lz4.go @@ -0,0 +1,105 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package compression + +import ( + "github.com/pierrec/lz4" +) + +const ( + minLz4DestinationBufferSize = 1024 * 1024 +) + +type lz4Provider struct { + hashTable []int +} + +// NewLz4Provider return a interface of Provider. +func NewLz4Provider() Provider { + const tableSize = 1 << 16 + + return &lz4Provider{ + hashTable: make([]int, tableSize), + } +} + +func (l *lz4Provider) CompressMaxSize(originalSize int) int { + s := lz4.CompressBlockBound(originalSize) + if s < minLz4DestinationBufferSize { + return minLz4DestinationBufferSize + } + + return s +} + +func (l *lz4Provider) Compress(dst, data []byte) []byte { + maxSize := lz4.CompressBlockBound(len(data)) + if cap(dst) >= maxSize { + dst = dst[0:maxSize] // Reuse dst buffer + } else { + dst = make([]byte, maxSize) + } + size, err := lz4.CompressBlock(data, dst, l.hashTable) + if err != nil { + panic("Failed to compress") + } + + if size == 0 { + // The data block was not compressed. Just repeat it with + // the block header flag to signal it's not compressed + headerSize := writeSize(len(data), dst) + copy(dst[headerSize:], data) + return dst[:len(data)+headerSize] + } + return dst[:size] +} + +// Write the encoded size for the uncompressed payload +func writeSize(size int, dst []byte) int { + if size < 0xF { + dst[0] |= byte(size << 4) + return 1 + } + dst[0] |= 0xF0 + l := size - 0xF + i := 1 + for ; l >= 0xFF; l -= 0xFF { + dst[i] = 0xFF + i++ + } + dst[i] = byte(l) + return i + 1 +} + +func (lz4Provider) Decompress(dst, src []byte, originalSize int) ([]byte, error) { + if cap(dst) >= originalSize { + dst = dst[0:originalSize] // Reuse dst buffer + } else { + dst = make([]byte, originalSize) + } + _, err := lz4.UncompressBlock(src, dst) + return dst, err +} + +func (lz4Provider) Close() error { + return nil +} + +func (lz4Provider) Clone() Provider { + return NewLz4Provider() +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/noop.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/noop.go new file mode 100644 index 00000000..78acb52d --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/noop.go @@ -0,0 +1,61 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package compression + +import ( + "bytes" +) + +type noopProvider struct{} + +// NewNoopProvider returns a Provider interface that does not compress the data +func NewNoopProvider() Provider { + return &noopProvider{} +} + +func (noopProvider) CompressMaxSize(originalSize int) int { + return originalSize +} + +func (noopProvider) Compress(dst, src []byte) []byte { + if dst == nil { + dst = make([]byte, len(src)) + } + + b := bytes.NewBuffer(dst[:0]) + b.Write(src) + return dst[:len(src)] +} + +func (noopProvider) Decompress(dst, src []byte, originalSize int) ([]byte, error) { + if dst == nil { + dst = make([]byte, len(src)) + } + + b := bytes.NewBuffer(dst[:0]) + b.Write(src) + return dst[:len(src)], nil +} + +func (noopProvider) Close() error { + return nil +} + +func (noopProvider) Clone() Provider { + return NewNoopProvider() +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/test_data_sample.txt b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/test_data_sample.txt new file mode 100644 index 00000000..89e3e478 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/test_data_sample.txt @@ -0,0 +1,1795 @@ +**The Project Gutenberg Etext of A Child's History of England** +#11 in our series by Charles Dickens + + +Copyright laws are changing all over the world, be sure to check +the copyright laws for your country before posting these files!! + +Please take a look at the important information in this header. +We encourage you to keep this file on your own disk, keeping an +electronic path open for the next readers. Do not remove this. + + +**Welcome To The World of Free Plain Vanilla Electronic Texts** + +**Etexts Readable By Both Humans and By Computers, Since 1971** + +*These Etexts Prepared By Hundreds of Volunteers and Donations* + +Information on contacting Project Gutenberg to get Etexts, and +further information is included below. We need your donations. + + +A Child's History of England + +by Charles Dickens + +October, 1996 [Etext #699] + + +**The Project Gutenberg Etext of A Child's History of England** +*****This file should be named achoe10.txt or achoe10.zip****** + +Corrected EDITIONS of our etexts get a new NUMBER, achoe11.txt. +VERSIONS based on separate sources get new LETTER, achoe10a.txt. + + +We are now trying to release all our books one month in advance +of the official release dates, for time for better editing. + +Please note: neither this list nor its contents are final till +midnight of the last day of the month of any such announcement. +The official release date of all Project Gutenberg Etexts is at +Midnight, Central Time, of the last day of the stated month. A +preliminary version may often be posted for suggestion, comment +and editing by those who wish to do so. To be sure you have an +up to date first edition [xxxxx10x.xxx] please check file sizes +in the first week of the next month. Since our ftp program has +a bug in it that scrambles the date [tried to fix and failed] a +look at the file size will have to do, but we will try to see a +new copy has at least one byte more or less. + + +Information about Project Gutenberg (one page) + +We produce about two million dollars for each hour we work. The +fifty hours is one conservative estimate for how long it we take +to get any etext selected, entered, proofread, edited, copyright +searched and analyzed, the copyright letters written, etc. This +projected audience is one hundred million readers. If our value +per text is nominally estimated at one dollar then we produce $2 +million dollars per hour this year as we release thirty-two text +files per month: or 400 more Etexts in 1996 for a total of 800. +If these reach just 10% of the computerized population, then the +total should reach 80 billion Etexts. + +The Goal of Project Gutenberg is to Give Away One Trillion Etext +Files by the December 31, 2001. [10,000 x 100,000,000=Trillion] +This is ten thousand titles each to one hundred million readers, +which is only 10% of the present number of computer users. 2001 +should have at least twice as many computer users as that, so it +will require us reaching less than 5% of the users in 2001. + + +We need your donations more than ever! + + +All donations should be made to "Project Gutenberg/BU": and are +tax deductible to the extent allowable by law. (BU = Benedictine +University). (Subscriptions to our paper newsletter go to BU.) + +For these and other matters, please mail to: + +Project Gutenberg +P. O. Box 2782 +Champaign, IL 61825 + +When all other email fails try our Executive Director: +Michael S. Hart + +We would prefer to send you this information by email +(Internet, Bitnet, Compuserve, ATTMAIL or MCImail). + +****** +If you have an FTP program (or emulator), please +FTP directly to the Project Gutenberg archives: +[Mac users, do NOT point and click. . .type] + +ftp uiarchive.cso.uiuc.edu +login: anonymous +password: your@login +cd etext/etext90 through /etext96 +or cd etext/articles [get suggest gut for more information] +dir [to see files] +get or mget [to get files. . .set bin for zip files] +GET INDEX?00.GUT +for a list of books +and +GET NEW GUT for general information +and +MGET GUT* for newsletters. + +**Information prepared by the Project Gutenberg legal advisor** +(Three Pages) + + +***START**THE SMALL PRINT!**FOR PUBLIC DOMAIN ETEXTS**START*** +Why is this "Small Print!" statement here? You know: lawyers. +They tell us you might sue us if there is something wrong with +your copy of this etext, even if you got it for free from +someone other than us, and even if what's wrong is not our +fault. So, among other things, this "Small Print!" statement +disclaims most of our liability to you. It also tells you how +you can distribute copies of this etext if you want to. + +*BEFORE!* YOU USE OR READ THIS ETEXT +By using or reading any part of this PROJECT GUTENBERG-tm +etext, you indicate that you understand, agree to and accept +this "Small Print!" statement. If you do not, you can receive +a refund of the money (if any) you paid for this etext by +sending a request within 30 days of receiving it to the person +you got it from. If you received this etext on a physical +medium (such as a disk), you must return it with your request. + +ABOUT PROJECT GUTENBERG-TM ETEXTS +This PROJECT GUTENBERG-tm etext, like most PROJECT GUTENBERG- +tm etexts, is a "public domain" work distributed by Professor +Michael S. Hart through the Project Gutenberg Association at +Benedictine University (the "Project"). Among other +things, this means that no one owns a United States copyright +on or for this work, so the Project (and you!) can copy and +distribute it in the United States without permission and +without paying copyright royalties. Special rules, set forth +below, apply if you wish to copy and distribute this etext +under the Project's "PROJECT GUTENBERG" trademark. + +To create these etexts, the Project expends considerable +efforts to identify, transcribe and proofread public domain +works. Despite these efforts, the Project's etexts and any +medium they may be on may contain "Defects". Among other +things, Defects may take the form of incomplete, inaccurate or +corrupt data, transcription errors, a copyright or other +intellectual property infringement, a defective or damaged +disk or other etext medium, a computer virus, or computer +codes that damage or cannot be read by your equipment. + +LIMITED WARRANTY; DISCLAIMER OF DAMAGES +But for the "Right of Replacement or Refund" described below, +[1] the Project (and any other party you may receive this +etext from as a PROJECT GUTENBERG-tm etext) disclaims all +liability to you for damages, costs and expenses, including +legal fees, and [2] YOU HAVE NO REMEDIES FOR NEGLIGENCE OR +UNDER STRICT LIABILITY, OR FOR BREACH OF WARRANTY OR CONTRACT, +INCLUDING BUT NOT LIMITED TO INDIRECT, CONSEQUENTIAL, PUNITIVE +OR INCIDENTAL DAMAGES, EVEN IF YOU GIVE NOTICE OF THE +POSSIBILITY OF SUCH DAMAGES. + +If you discover a Defect in this etext within 90 days of +receiving it, you can receive a refund of the money (if any) +you paid for it by sending an explanatory note within that +time to the person you received it from. If you received it +on a physical medium, you must return it with your note, and +such person may choose to alternatively give you a replacement +copy. If you received it electronically, such person may +choose to alternatively give you a second opportunity to +receive it electronically. + +THIS ETEXT IS OTHERWISE PROVIDED TO YOU "AS-IS". NO OTHER +WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, ARE MADE TO YOU AS +TO THE ETEXT OR ANY MEDIUM IT MAY BE ON, INCLUDING BUT NOT +LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A +PARTICULAR PURPOSE. + +Some states do not allow disclaimers of implied warranties or +the exclusion or limitation of consequential damages, so the +above disclaimers and exclusions may not apply to you, and you +may have other legal rights. + +INDEMNITY +You will indemnify and hold the Project, its directors, +officers, members and agents harmless from all liability, cost +and expense, including legal fees, that arise directly or +indirectly from any of the following that you do or cause: +[1] distribution of this etext, [2] alteration, modification, +or addition to the etext, or [3] any Defect. + +DISTRIBUTION UNDER "PROJECT GUTENBERG-tm" +You may distribute copies of this etext electronically, or by +disk, book or any other medium if you either delete this +"Small Print!" and all other references to Project Gutenberg, +or: + +[1] Only give exact copies of it. Among other things, this + requires that you do not remove, alter or modify the + etext or this "small print!" statement. You may however, + if you wish, distribute this etext in machine readable + binary, compressed, mark-up, or proprietary form, + including any form resulting from conversion by word pro- + cessing or hypertext software, but only so long as + *EITHER*: + + [*] The etext, when displayed, is clearly readable, and + does *not* contain characters other than those + intended by the author of the work, although tilde + (~), asterisk (*) and underline (_) characters may + be used to convey punctuation intended by the + author, and additional characters may be used to + indicate hypertext links; OR + + [*] The etext may be readily converted by the reader at + no expense into plain ASCII, EBCDIC or equivalent + form by the program that displays the etext (as is + the case, for instance, with most word processors); + OR + + [*] You provide, or agree to also provide on request at + no additional cost, fee or expense, a copy of the + etext in its original plain ASCII form (or in EBCDIC + or other equivalent proprietary form). + +[2] Honor the etext refund and replacement provisions of this + "Small Print!" statement. + +[3] Pay a trademark license fee to the Project of 20% of the + net profits you derive calculated using the method you + already use to calculate your applicable taxes. If you + don't derive profits, no royalty is due. Royalties are + payable to "Project Gutenberg Association / Benedictine + University" within the 60 days following each + date you prepare (or were legally required to prepare) + your annual (or equivalent periodic) tax return. + +WHAT IF YOU *WANT* TO SEND MONEY EVEN IF YOU DON'T HAVE TO? +The Project gratefully accepts contributions in money, time, +scanning machines, OCR software, public domain etexts, royalty +free copyright licenses, and every other sort of contribution +you can think of. Money should be paid to "Project Gutenberg +Association / Benedictine University". + +*END*THE SMALL PRINT! FOR PUBLIC DOMAIN ETEXTS*Ver.04.29.93*END* + + + + + +A Child's History of England by Charles Dickens +Scanned and Proofed by David Price, email ccx074@coventry.ac.uk + + + + + +A Child's History of England + + + + +CHAPTER I - ANCIENT ENGLAND AND THE ROMANS + + + +IF you look at a Map of the World, you will see, in the left-hand +upper corner of the Eastern Hemisphere, two Islands lying in the +sea. They are England and Scotland, and Ireland. England and +Scotland form the greater part of these Islands. Ireland is the +next in size. The little neighbouring islands, which are so small +upon the Map as to be mere dots, are chiefly little bits of +Scotland, - broken off, I dare say, in the course of a great length +of time, by the power of the restless water. + +In the old days, a long, long while ago, before Our Saviour was +born on earth and lay asleep in a manger, these Islands were in the +same place, and the stormy sea roared round them, just as it roars +now. But the sea was not alive, then, with great ships and brave +sailors, sailing to and from all parts of the world. It was very +lonely. The Islands lay solitary, in the great expanse of water. +The foaming waves dashed against their cliffs, and the bleak winds +blew over their forests; but the winds and waves brought no +adventurers to land upon the Islands, and the savage Islanders knew +nothing of the rest of the world, and the rest of the world knew +nothing of them. + +It is supposed that the Phoenicians, who were an ancient people, +famous for carrying on trade, came in ships to these Islands, and +found that they produced tin and lead; both very useful things, as +you know, and both produced to this very hour upon the sea-coast. +The most celebrated tin mines in Cornwall are, still, close to the +sea. One of them, which I have seen, is so close to it that it is +hollowed out underneath the ocean; and the miners say, that in +stormy weather, when they are at work down in that deep place, they +can hear the noise of the waves thundering above their heads. So, +the Phoenicians, coasting about the Islands, would come, without +much difficulty, to where the tin and lead were. + +The Phoenicians traded with the Islanders for these metals, and +gave the Islanders some other useful things in exchange. The +Islanders were, at first, poor savages, going almost naked, or only +dressed in the rough skins of beasts, and staining their bodies, as +other savages do, with coloured earths and the juices of plants. +But the Phoenicians, sailing over to the opposite coasts of France +and Belgium, and saying to the people there, 'We have been to those +white cliffs across the water, which you can see in fine weather, +and from that country, which is called BRITAIN, we bring this tin +and lead,' tempted some of the French and Belgians to come over +also. These people settled themselves on the south coast of +England, which is now called Kent; and, although they were a rough +people too, they taught the savage Britons some useful arts, and +improved that part of the Islands. It is probable that other +people came over from Spain to Ireland, and settled there. + +Thus, by little and little, strangers became mixed with the +Islanders, and the savage Britons grew into a wild, bold people; +almost savage, still, especially in the interior of the country +away from the sea where the foreign settlers seldom went; but +hardy, brave, and strong. + +The whole country was covered with forests, and swamps. The +greater part of it was very misty and cold. There were no roads, +no bridges, no streets, no houses that you would think deserving of +the name. A town was nothing but a collection of straw-covered +huts, hidden in a thick wood, with a ditch all round, and a low +wall, made of mud, or the trunks of trees placed one upon another. +The people planted little or no corn, but lived upon the flesh of +their flocks and cattle. They made no coins, but used metal rings +for money. They were clever in basket-work, as savage people often +are; and they could make a coarse kind of cloth, and some very bad +earthenware. But in building fortresses they were much more +clever. + +They made boats of basket-work, covered with the skins of animals, +but seldom, if ever, ventured far from the shore. They made +swords, of copper mixed with tin; but, these swords were of an +awkward shape, and so soft that a heavy blow would bend one. They +made light shields, short pointed daggers, and spears - which they +jerked back after they had thrown them at an enemy, by a long strip +of leather fastened to the stem. The butt-end was a rattle, to +frighten an enemy's horse. The ancient Britons, being divided into +as many as thirty or forty tribes, each commanded by its own little +king, were constantly fighting with one another, as savage people +usually do; and they always fought with these weapons. + +They were very fond of horses. The standard of Kent was the +picture of a white horse. They could break them in and manage them +wonderfully well. Indeed, the horses (of which they had an +abundance, though they were rather small) were so well taught in +those days, that they can scarcely be said to have improved since; +though the men are so much wiser. They understood, and obeyed, +every word of command; and would stand still by themselves, in all +the din and noise of battle, while their masters went to fight on +foot. The Britons could not have succeeded in their most +remarkable art, without the aid of these sensible and trusty +animals. The art I mean, is the construction and management of +war-chariots or cars, for which they have ever been celebrated in +history. Each of the best sort of these chariots, not quite breast +high in front, and open at the back, contained one man to drive, +and two or three others to fight - all standing up. The horses who +drew them were so well trained, that they would tear, at full +gallop, over the most stony ways, and even through the woods; +dashing down their masters' enemies beneath their hoofs, and +cutting them to pieces with the blades of swords, or scythes, which +were fastened to the wheels, and stretched out beyond the car on +each side, for that cruel purpose. In a moment, while at full +speed, the horses would stop, at the driver's command. The men +within would leap out, deal blows about them with their swords like +hail, leap on the horses, on the pole, spring back into the +chariots anyhow; and, as soon as they were safe, the horses tore +away again. + +The Britons had a strange and terrible religion, called the +Religion of the Druids. It seems to have been brought over, in +very early times indeed, from the opposite country of France, +anciently called Gaul, and to have mixed up the worship of the +Serpent, and of the Sun and Moon, with the worship of some of the +Heathen Gods and Goddesses. Most of its ceremonies were kept +secret by the priests, the Druids, who pretended to be enchanters, +and who carried magicians' wands, and wore, each of them, about his +neck, what he told the ignorant people was a Serpent's egg in a +golden case. But it is certain that the Druidical ceremonies +included the sacrifice of human victims, the torture of some +suspected criminals, and, on particular occasions, even the burning +alive, in immense wicker cages, of a number of men and animals +together. The Druid Priests had some kind of veneration for the +Oak, and for the mistletoe - the same plant that we hang up in +houses at Christmas Time now - when its white berries grew upon the +Oak. They met together in dark woods, which they called Sacred +Groves; and there they instructed, in their mysterious arts, young +men who came to them as pupils, and who sometimes stayed with them +as long as twenty years. + +These Druids built great Temples and altars, open to the sky, +fragments of some of which are yet remaining. Stonehenge, on +Salisbury Plain, in Wiltshire, is the most extraordinary of these. +Three curious stones, called Kits Coty House, on Bluebell Hill, +near Maidstone, in Kent, form another. We know, from examination +of the great blocks of which such buildings are made, that they +could not have been raised without the aid of some ingenious +machines, which are common now, but which the ancient Britons +certainly did not use in making their own uncomfortable houses. I +should not wonder if the Druids, and their pupils who stayed with +them twenty years, knowing more than the rest of the Britons, kept +the people out of sight while they made these buildings, and then +pretended that they built them by magic. Perhaps they had a hand +in the fortresses too; at all events, as they were very powerful, +and very much believed in, and as they made and executed the laws, +and paid no taxes, I don't wonder that they liked their trade. +And, as they persuaded the people the more Druids there were, the +better off the people would be, I don't wonder that there were a +good many of them. But it is pleasant to think that there are no +Druids, NOW, who go on in that way, and pretend to carry +Enchanters' Wands and Serpents' Eggs - and of course there is +nothing of the kind, anywhere. + +Such was the improved condition of the ancient Britons, fifty-five +years before the birth of Our Saviour, when the Romans, under their +great General, Julius Caesar, were masters of all the rest of the +known world. Julius Caesar had then just conquered Gaul; and +hearing, in Gaul, a good deal about the opposite Island with the +white cliffs, and about the bravery of the Britons who inhabited it +- some of whom had been fetched over to help the Gauls in the war +against him - he resolved, as he was so near, to come and conquer +Britain next. + +So, Julius Caesar came sailing over to this Island of ours, with +eighty vessels and twelve thousand men. And he came from the +French coast between Calais and Boulogne, 'because thence was the +shortest passage into Britain;' just for the same reason as our +steam-boats now take the same track, every day. He expected to +conquer Britain easily: but it was not such easy work as he +supposed - for the bold Britons fought most bravely; and, what with +not having his horse-soldiers with him (for they had been driven +back by a storm), and what with having some of his vessels dashed +to pieces by a high tide after they were drawn ashore, he ran great +risk of being totally defeated. However, for once that the bold +Britons beat him, he beat them twice; though not so soundly but +that he was very glad to accept their proposals of peace, and go +away. + +But, in the spring of the next year, he came back; this time, with +eight hundred vessels and thirty thousand men. The British tribes +chose, as their general-in-chief, a Briton, whom the Romans in +their Latin language called CASSIVELLAUNUS, but whose British name +is supposed to have been CASWALLON. A brave general he was, and +well he and his soldiers fought the Roman army! So well, that +whenever in that war the Roman soldiers saw a great cloud of dust, +and heard the rattle of the rapid British chariots, they trembled +in their hearts. Besides a number of smaller battles, there was a +battle fought near Canterbury, in Kent; there was a battle fought +near Chertsey, in Surrey; there was a battle fought near a marshy +little town in a wood, the capital of that part of Britain which +belonged to CASSIVELLAUNUS, and which was probably near what is now +Saint Albans, in Hertfordshire. However, brave CASSIVELLAUNUS had +the worst of it, on the whole; though he and his men always fought +like lions. As the other British chiefs were jealous of him, and +were always quarrelling with him, and with one another, he gave up, +and proposed peace. Julius Caesar was very glad to grant peace +easily, and to go away again with all his remaining ships and men. +He had expected to find pearls in Britain, and he may have found a +few for anything I know; but, at all events, he found delicious +oysters, and I am sure he found tough Britons - of whom, I dare +say, he made the same complaint as Napoleon Bonaparte the great +French General did, eighteen hundred years afterwards, when he said +they were such unreasonable fellows that they never knew when they +were beaten. They never DID know, I believe, and never will. + +Nearly a hundred years passed on, and all that time, there was +peace in Britain. The Britons improved their towns and mode of +life: became more civilised, travelled, and learnt a great deal +from the Gauls and Romans. At last, the Roman Emperor, Claudius, +sent AULUS PLAUTIUS, a skilful general, with a mighty force, to +subdue the Island, and shortly afterwards arrived himself. They +did little; and OSTORIUS SCAPULA, another general, came. Some of +the British Chiefs of Tribes submitted. Others resolved to fight +to the death. Of these brave men, the bravest was CARACTACUS, or +CARADOC, who gave battle to the Romans, with his army, among the +mountains of North Wales. 'This day,' said he to his soldiers, +'decides the fate of Britain! Your liberty, or your eternal +slavery, dates from this hour. Remember your brave ancestors, who +drove the great Caesar himself across the sea!' On hearing these +words, his men, with a great shout, rushed upon the Romans. But +the strong Roman swords and armour were too much for the weaker +British weapons in close conflict. The Britons lost the day. The +wife and daughter of the brave CARACTACUS were taken prisoners; his +brothers delivered themselves up; he himself was betrayed into the +hands of the Romans by his false and base stepmother: and they +carried him, and all his family, in triumph to Rome. + +But a great man will be great in misfortune, great in prison, great +in chains. His noble air, and dignified endurance of distress, so +touched the Roman people who thronged the streets to see him, that +he and his family were restored to freedom. No one knows whether +his great heart broke, and he died in Rome, or whether he ever +returned to his own dear country. English oaks have grown up from +acorns, and withered away, when they were hundreds of years old - +and other oaks have sprung up in their places, and died too, very +aged - since the rest of the history of the brave CARACTACUS was +forgotten. + +Still, the Britons WOULD NOT yield. They rose again and again, and +died by thousands, sword in hand. They rose, on every possible +occasion. SUETONIUS, another Roman general, came, and stormed the +Island of Anglesey (then called MONA), which was supposed to be +sacred, and he burnt the Druids in their own wicker cages, by their +own fires. But, even while he was in Britain, with his victorious +troops, the BRITONS rose. Because BOADICEA, a British queen, the +widow of the King of the Norfolk and Suffolk people, resisted the +plundering of her property by the Romans who were settled in +England, she was scourged, by order of CATUS a Roman officer; and +her two daughters were shamefully insulted in her presence, and her +husband's relations were made slaves. To avenge this injury, the +Britons rose, with all their might and rage. They drove CATUS into +Gaul; they laid the Roman possessions waste; they forced the Romans +out of London, then a poor little town, but a trading place; they +hanged, burnt, crucified, and slew by the sword, seventy thousand +Romans in a few days. SUETONIUS strengthened his army, and +advanced to give them battle. They strengthened their army, and +desperately attacked his, on the field where it was strongly +posted. Before the first charge of the Britons was made, BOADICEA, +in a war-chariot, with her fair hair streaming in the wind, and her +injured daughters lying at her feet, drove among the troops, and +cried to them for vengeance on their oppressors, the licentious +Romans. The Britons fought to the last; but they were vanquished +with great slaughter, and the unhappy queen took poison. + +Still, the spirit of the Britons was not broken. When SUETONIUS +left the country, they fell upon his troops, and retook the Island +of Anglesey. AGRICOLA came, fifteen or twenty years afterwards, +and retook it once more, and devoted seven years to subduing the +country, especially that part of it which is now called SCOTLAND; +but, its people, the Caledonians, resisted him at every inch of +ground. They fought the bloodiest battles with him; they killed +their very wives and children, to prevent his making prisoners of +them; they fell, fighting, in such great numbers that certain hills +in Scotland are yet supposed to be vast heaps of stones piled up +above their graves. HADRIAN came, thirty years afterwards, and +still they resisted him. SEVERUS came, nearly a hundred years +afterwards, and they worried his great army like dogs, and rejoiced +to see them die, by thousands, in the bogs and swamps. CARACALLA, +the son and successor of SEVERUS, did the most to conquer them, for +a time; but not by force of arms. He knew how little that would +do. He yielded up a quantity of land to the Caledonians, and gave +the Britons the same privileges as the Romans possessed. There was +peace, after this, for seventy years. + +Then new enemies arose. They were the Saxons, a fierce, sea-faring +people from the countries to the North of the Rhine, the great +river of Germany on the banks of which the best grapes grow to make +the German wine. They began to come, in pirate ships, to the sea- +coast of Gaul and Britain, and to plunder them. They were repulsed +by CARAUSIUS, a native either of Belgium or of Britain, who was +appointed by the Romans to the command, and under whom the Britons +first began to fight upon the sea. But, after this time, they +renewed their ravages. A few years more, and the Scots (which was +then the name for the people of Ireland), and the Picts, a northern +people, began to make frequent plundering incursions into the South +of Britain. All these attacks were repeated, at intervals, during +two hundred years, and through a long succession of Roman Emperors +and chiefs; during all which length of time, the Britons rose +against the Romans, over and over again. At last, in the days of +the Roman HONORIUS, when the Roman power all over the world was +fast declining, and when Rome wanted all her soldiers at home, the +Romans abandoned all hope of conquering Britain, and went away. +And still, at last, as at first, the Britons rose against them, in +their old brave manner; for, a very little while before, they had +turned away the Roman magistrates, and declared themselves an +independent people. + +Five hundred years had passed, since Julius Caesar's first invasion +of the Island, when the Romans departed from it for ever. In the +course of that time, although they had been the cause of terrible +fighting and bloodshed, they had done much to improve the condition +of the Britons. They had made great military roads; they had built +forts; they had taught them how to dress, and arm themselves, much +better than they had ever known how to do before; they had refined +the whole British way of living. AGRICOLA had built a great wall +of earth, more than seventy miles long, extending from Newcastle to +beyond Carlisle, for the purpose of keeping out the Picts and +Scots; HADRIAN had strengthened it; SEVERUS, finding it much in +want of repair, had built it afresh of stone. + +Above all, it was in the Roman time, and by means of Roman ships, +that the Christian Religion was first brought into Britain, and its +people first taught the great lesson that, to be good in the sight +of GOD, they must love their neighbours as themselves, and do unto +others as they would be done by. The Druids declared that it was +very wicked to believe in any such thing, and cursed all the people +who did believe it, very heartily. But, when the people found that +they were none the better for the blessings of the Druids, and none +the worse for the curses of the Druids, but, that the sun shone and +the rain fell without consulting the Druids at all, they just began +to think that the Druids were mere men, and that it signified very +little whether they cursed or blessed. After which, the pupils of +the Druids fell off greatly in numbers, and the Druids took to +other trades. + +Thus I have come to the end of the Roman time in England. It is +but little that is known of those five hundred years; but some +remains of them are still found. Often, when labourers are digging +up the ground, to make foundations for houses or churches, they +light on rusty money that once belonged to the Romans. Fragments +of plates from which they ate, of goblets from which they drank, +and of pavement on which they trod, are discovered among the earth +that is broken by the plough, or the dust that is crumbled by the +gardener's spade. Wells that the Romans sunk, still yield water; +roads that the Romans made, form part of our highways. In some old +battle-fields, British spear-heads and Roman armour have been +found, mingled together in decay, as they fell in the thick +pressure of the fight. Traces of Roman camps overgrown with grass, +and of mounds that are the burial-places of heaps of Britons, are +to be seen in almost all parts of the country. Across the bleak +moors of Northumberland, the wall of SEVERUS, overrun with moss and +weeds, still stretches, a strong ruin; and the shepherds and their +dogs lie sleeping on it in the summer weather. On Salisbury Plain, +Stonehenge yet stands: a monument of the earlier time when the +Roman name was unknown in Britain, and when the Druids, with their +best magic wands, could not have written it in the sands of the +wild sea-shore. + + + +CHAPTER II - ANCIENT ENGLAND UNDER THE EARLY SAXONS + + + +THE Romans had scarcely gone away from Britain, when the Britons +began to wish they had never left it. For, the Romans being gone, +and the Britons being much reduced in numbers by their long wars, +the Picts and Scots came pouring in, over the broken and unguarded +wall of SEVERUS, in swarms. They plundered the richest towns, and +killed the people; and came back so often for more booty and more +slaughter, that the unfortunate Britons lived a life of terror. As +if the Picts and Scots were not bad enough on land, the Saxons +attacked the islanders by sea; and, as if something more were still +wanting to make them miserable, they quarrelled bitterly among +themselves as to what prayers they ought to say, and how they ought +to say them. The priests, being very angry with one another on +these questions, cursed one another in the heartiest manner; and +(uncommonly like the old Druids) cursed all the people whom they +could not persuade. So, altogether, the Britons were very badly +off, you may believe. + +They were in such distress, in short, that they sent a letter to +Rome entreating help - which they called the Groans of the Britons; +and in which they said, 'The barbarians chase us into the sea, the +sea throws us back upon the barbarians, and we have only the hard +choice left us of perishing by the sword, or perishing by the +waves.' But, the Romans could not help them, even if they were so +inclined; for they had enough to do to defend themselves against +their own enemies, who were then very fierce and strong. At last, +the Britons, unable to bear their hard condition any longer, +resolved to make peace with the Saxons, and to invite the Saxons to +come into their country, and help them to keep out the Picts and +Scots. + +It was a British Prince named VORTIGERN who took this resolution, +and who made a treaty of friendship with HENGIST and HORSA, two +Saxon chiefs. Both of these names, in the old Saxon language, +signify Horse; for the Saxons, like many other nations in a rough +state, were fond of giving men the names of animals, as Horse, +Wolf, Bear, Hound. The Indians of North America, - a very inferior +people to the Saxons, though - do the same to this day. + +HENGIST and HORSA drove out the Picts and Scots; and VORTIGERN, +being grateful to them for that service, made no opposition to +their settling themselves in that part of England which is called +the Isle of Thanet, or to their inviting over more of their +countrymen to join them. But HENGIST had a beautiful daughter +named ROWENA; and when, at a feast, she filled a golden goblet to +the brim with wine, and gave it to VORTIGERN, saying in a sweet +voice, 'Dear King, thy health!' the King fell in love with her. My +opinion is, that the cunning HENGIST meant him to do so, in order +that the Saxons might have greater influence with him; and that the +fair ROWENA came to that feast, golden goblet and all, on purpose. + +At any rate, they were married; and, long afterwards, whenever the +King was angry with the Saxons, or jealous of their encroachments, +ROWENA would put her beautiful arms round his neck, and softly say, +'Dear King, they are my people! Be favourable to them, as you +loved that Saxon girl who gave you the golden goblet of wine at the +feast!' And, really, I don't see how the King could help himself. + +Ah! We must all die! In the course of years, VORTIGERN died - he +was dethroned, and put in prison, first, I am afraid; and ROWENA +died; and generations of Saxons and Britons died; and events that +happened during a long, long time, would have been quite forgotten +but for the tales and songs of the old Bards, who used to go about +from feast to feast, with their white beards, recounting the deeds +of their forefathers. Among the histories of which they sang and +talked, there was a famous one, concerning the bravery and virtues +of KING ARTHUR, supposed to have been a British Prince in those old +times. But, whether such a person really lived, or whether there +were several persons whose histories came to be confused together +under that one name, or whether all about him was invention, no one +knows. + +I will tell you, shortly, what is most interesting in the early +Saxon times, as they are described in these songs and stories of +the Bards. + +In, and long after, the days of VORTIGERN, fresh bodies of Saxons, +under various chiefs, came pouring into Britain. One body, +conquering the Britons in the East, and settling there, called +their kingdom Essex; another body settled in the West, and called +their kingdom Wessex; the Northfolk, or Norfolk people, established +themselves in one place; the Southfolk, or Suffolk people, +established themselves in another; and gradually seven kingdoms or +states arose in England, which were called the Saxon Heptarchy. +The poor Britons, falling back before these crowds of fighting men +whom they had innocently invited over as friends, retired into +Wales and the adjacent country; into Devonshire, and into Cornwall. +Those parts of England long remained unconquered. And in Cornwall +now - where the sea-coast is very gloomy, steep, and rugged - +where, in the dark winter-time, ships have often been wrecked close +to the land, and every soul on board has perished - where the winds +and waves howl drearily and split the solid rocks into arches and +caverns - there are very ancient ruins, which the people call the +ruins of KING ARTHUR'S Castle. + +Kent is the most famous of the seven Saxon kingdoms, because the +Christian religion was preached to the Saxons there (who domineered +over the Britons too much, to care for what THEY said about their +religion, or anything else) by AUGUSTINE, a monk from Rome. KING +ETHELBERT, of Kent, was soon converted; and the moment he said he +was a Christian, his courtiers all said THEY were Christians; after +which, ten thousand of his subjects said they were Christians too. +AUGUSTINE built a little church, close to this King's palace, on +the ground now occupied by the beautiful cathedral of Canterbury. +SEBERT, the King's nephew, built on a muddy marshy place near +London, where there had been a temple to Apollo, a church dedicated +to Saint Peter, which is now Westminster Abbey. And, in London +itself, on the foundation of a temple to Diana, he built another +little church which has risen up, since that old time, to be Saint +Paul's. + +After the death of ETHELBERT, EDWIN, King of Northumbria, who was +such a good king that it was said a woman or child might openly +carry a purse of gold, in his reign, without fear, allowed his +child to be baptised, and held a great council to consider whether +he and his people should all be Christians or not. It was decided +that they should be. COIFI, the chief priest of the old religion, +made a great speech on the occasion. In this discourse, he told +the people that he had found out the old gods to be impostors. 'I +am quite satisfied of it,' he said. 'Look at me! I have been +serving them all my life, and they have done nothing for me; +whereas, if they had been really powerful, they could not have +decently done less, in return for all I have done for them, than +make my fortune. As they have never made my fortune, I am quite +convinced they are impostors!' When this singular priest had +finished speaking, he hastily armed himself with sword and lance, +mounted a war-horse, rode at a furious gallop in sight of all the +people to the temple, and flung his lance against it as an insult. +From that time, the Christian religion spread itself among the +Saxons, and became their faith. + +The next very famous prince was EGBERT. He lived about a hundred +and fifty years afterwards, and claimed to have a better right to +the throne of Wessex than BEORTRIC, another Saxon prince who was at +the head of that kingdom, and who married EDBURGA, the daughter of +OFFA, king of another of the seven kingdoms. This QUEEN EDBURGA +was a handsome murderess, who poisoned people when they offended +her. One day, she mixed a cup of poison for a certain noble +belonging to the court; but her husband drank of it too, by +mistake, and died. Upon this, the people revolted, in great +crowds; and running to the palace, and thundering at the gates, +cried, 'Down with the wicked queen, who poisons men!' They drove +her out of the country, and abolished the title she had disgraced. +When years had passed away, some travellers came home from Italy, +and said that in the town of Pavia they had seen a ragged beggar- +woman, who had once been handsome, but was then shrivelled, bent, +and yellow, wandering about the streets, crying for bread; and that +this beggar-woman was the poisoning English queen. It was, indeed, +EDBURGA; and so she died, without a shelter for her wretched head. + +EGBERT, not considering himself safe in England, in consequence of +his having claimed the crown of Wessex (for he thought his rival +might take him prisoner and put him to death), sought refuge at the +court of CHARLEMAGNE, King of France. On the death of BEORTRIC, so +unhappily poisoned by mistake, EGBERT came back to Britain; +succeeded to the throne of Wessex; conquered some of the other +monarchs of the seven kingdoms; added their territories to his own; +and, for the first time, called the country over which he ruled, +ENGLAND. + +And now, new enemies arose, who, for a long time, troubled England +sorely. These were the Northmen, the people of Denmark and Norway, +whom the English called the Danes. They were a warlike people, +quite at home upon the sea; not Christians; very daring and cruel. +They came over in ships, and plundered and burned wheresoever they +landed. Once, they beat EGBERT in battle. Once, EGBERT beat them. +But, they cared no more for being beaten than the English +themselves. In the four following short reigns, of ETHELWULF, and +his sons, ETHELBALD, ETHELBERT, and ETHELRED, they came back, over +and over again, burning and plundering, and laying England waste. +In the last-mentioned reign, they seized EDMUND, King of East +England, and bound him to a tree. Then, they proposed to him that +he should change his religion; but he, being a good Christian, +steadily refused. Upon that, they beat him, made cowardly jests +upon him, all defenceless as he was, shot arrows at him, and, +finally, struck off his head. It is impossible to say whose head +they might have struck off next, but for the death of KING ETHELRED +from a wound he had received in fighting against them, and the +succession to his throne of the best and wisest king that ever +lived in England. + + + +CHAPTER III - ENGLAND UNDER THE GOOD SAXON, ALFRED + + + +ALFRED THE GREAT was a young man, three-and-twenty years of age, +when he became king. Twice in his childhood, he had been taken to +Rome, where the Saxon nobles were in the habit of going on journeys +which they supposed to be religious; and, once, he had stayed for +some time in Paris. Learning, however, was so little cared for, +then, that at twelve years old he had not been taught to read; +although, of the sons of KING ETHELWULF, he, the youngest, was the +favourite. But he had - as most men who grow up to be great and +good are generally found to have had - an excellent mother; and, +one day, this lady, whose name was OSBURGA, happened, as she was +sitting among her sons, to read a book of Saxon poetry. The art of +printing was not known until long and long after that period, and +the book, which was written, was what is called 'illuminated,' with +beautiful bright letters, richly painted. The brothers admiring it +very much, their mother said, 'I will give it to that one of you +four princes who first learns to read.' ALFRED sought out a tutor +that very day, applied himself to learn with great diligence, and +soon won the book. He was proud of it, all his life. + +This great king, in the first year of his reign, fought nine +battles with the Danes. He made some treaties with them too, by +which the false Danes swore they would quit the country. They +pretended to consider that they had taken a very solemn oath, in +swearing this upon the holy bracelets that they wore, and which +were always buried with them when they died; but they cared little +for it, for they thought nothing of breaking oaths and treaties +too, as soon as it suited their purpose, and coming back again to +fight, plunder, and burn, as usual. One fatal winter, in the +fourth year of KING ALFRED'S reign, they spread themselves in great +numbers over the whole of England; and so dispersed and routed the +King's soldiers that the King was left alone, and was obliged to +disguise himself as a common peasant, and to take refuge in the +cottage of one of his cowherds who did not know his face. + +Here, KING ALFRED, while the Danes sought him far and near, was +left alone one day, by the cowherd's wife, to watch some cakes +which she put to bake upon the hearth. But, being at work upon his +bow and arrows, with which he hoped to punish the false Danes when +a brighter time should come, and thinking deeply of his poor +unhappy subjects whom the Danes chased through the land, his noble +mind forgot the cakes, and they were burnt. 'What!' said the +cowherd's wife, who scolded him well when she came back, and little +thought she was scolding the King, 'you will be ready enough to eat +them by-and-by, and yet you cannot watch them, idle dog?' + +At length, the Devonshire men made head against a new host of Danes +who landed on their coast; killed their chief, and captured their +flag; on which was represented the likeness of a Raven - a very fit +bird for a thievish army like that, I think. The loss of their +standard troubled the Danes greatly, for they believed it to be +enchanted - woven by the three daughters of one father in a single +afternoon - and they had a story among themselves that when they +were victorious in battle, the Raven stretched his wings and seemed +to fly; and that when they were defeated, he would droop. He had +good reason to droop, now, if he could have done anything half so +sensible; for, KING ALFRED joined the Devonshire men; made a camp +with them on a piece of firm ground in the midst of a bog in +Somersetshire; and prepared for a great attempt for vengeance on +the Danes, and the deliverance of his oppressed people. + +But, first, as it was important to know how numerous those +pestilent Danes were, and how they were fortified, KING ALFRED, +being a good musician, disguised himself as a glee-man or minstrel, +and went, with his harp, to the Danish camp. He played and sang in +the very tent of GUTHRUM the Danish leader, and entertained the +Danes as they caroused. While he seemed to think of nothing but +his music, he was watchful of their tents, their arms, their +discipline, everything that he desired to know. And right soon did +this great king entertain them to a different tune; for, summoning +all his true followers to meet him at an appointed place, where +they received him with joyful shouts and tears, as the monarch whom +many of them had given up for lost or dead, he put himself at their +head, marched on the Danish camp, defeated the Danes with great +slaughter, and besieged them for fourteen days to prevent their +escape. But, being as merciful as he was good and brave, he then, +instead of killing them, proposed peace: on condition that they +should altogether depart from that Western part of England, and +settle in the East; and that GUTHRUM should become a Christian, in +remembrance of the Divine religion which now taught his conqueror, +the noble ALFRED, to forgive the enemy who had so often injured +him. This, GUTHRUM did. At his baptism, KING ALFRED was his +godfather. And GUTHRUM was an honourable chief who well deserved +that clemency; for, ever afterwards he was loyal and faithful to +the king. The Danes under him were faithful too. They plundered +and burned no more, but worked like honest men. They ploughed, and +sowed, and reaped, and led good honest English lives. And I hope +the children of those Danes played, many a time, with Saxon +children in the sunny fields; and that Danish young men fell in +love with Saxon girls, and married them; and that English +travellers, benighted at the doors of Danish cottages, often went +in for shelter until morning; and that Danes and Saxons sat by the +red fire, friends, talking of KING ALFRED THE GREAT. + +All the Danes were not like these under GUTHRUM; for, after some +years, more of them came over, in the old plundering and burning +way - among them a fierce pirate of the name of HASTINGS, who had +the boldness to sail up the Thames to Gravesend, with eighty ships. +For three years, there was a war with these Danes; and there was a +famine in the country, too, and a plague, both upon human creatures +and beasts. But KING ALFRED, whose mighty heart never failed him, +built large ships nevertheless, with which to pursue the pirates on +the sea; and he encouraged his soldiers, by his brave example, to +fight valiantly against them on the shore. At last, he drove them +all away; and then there was repose in England. + +As great and good in peace, as he was great and good in war, KING +ALFRED never rested from his labours to improve his people. He +loved to talk with clever men, and with travellers from foreign +countries, and to write down what they told him, for his people to +read. He had studied Latin after learning to read English, and now +another of his labours was, to translate Latin books into the +English-Saxon tongue, that his people might be interested, and +improved by their contents. He made just laws, that they might +live more happily and freely; he turned away all partial judges, +that no wrong might be done them; he was so careful of their +property, and punished robbers so severely, that it was a common +thing to say that under the great KING ALFRED, garlands of golden +chains and jewels might have hung across the streets, and no man +would have touched one. He founded schools; he patiently heard +causes himself in his Court of Justice; the great desires of his +heart were, to do right to all his subjects, and to leave England +better, wiser, happier in all ways, than he found it. His industry +in these efforts was quite astonishing. Every day he divided into +certain portions, and in each portion devoted himself to a certain +pursuit. That he might divide his time exactly, he had wax torches +or candles made, which were all of the same size, were notched +across at regular distances, and were always kept burning. Thus, +as the candles burnt down, he divided the day into notches, almost +as accurately as we now divide it into hours upon the clock. But +when the candles were first invented, it was found that the wind +and draughts of air, blowing into the palace through the doors and +windows, and through the chinks in the walls, caused them to gutter +and burn unequally. To prevent this, the King had them put into +cases formed of wood and white horn. And these were the first +lanthorns ever made in England. + +All this time, he was afflicted with a terrible unknown disease, +which caused him violent and frequent pain that nothing could +relieve. He bore it, as he had borne all the troubles of his life, +like a brave good man, until he was fifty-three years old; and +then, having reigned thirty years, he died. He died in the year +nine hundred and one; but, long ago as that is, his fame, and the +love and gratitude with which his subjects regarded him, are +freshly remembered to the present hour. + +In the next reign, which was the reign of EDWARD, surnamed THE +ELDER, who was chosen in council to succeed, a nephew of KING +ALFRED troubled the country by trying to obtain the throne. The +Danes in the East of England took part with this usurper (perhaps +because they had honoured his uncle so much, and honoured him for +his uncle's sake), and there was hard fighting; but, the King, with +the assistance of his sister, gained the day, and reigned in peace +for four and twenty years. He gradually extended his power over +the whole of England, and so the Seven Kingdoms were united into +one. + +When England thus became one kingdom, ruled over by one Saxon king, +the Saxons had been settled in the country more than four hundred +and fifty years. Great changes had taken place in its customs +during that time. The Saxons were still greedy eaters and great +drinkers, and their feasts were often of a noisy and drunken kind; +but many new comforts and even elegances had become known, and were +fast increasing. Hangings for the walls of rooms, where, in these +modern days, we paste up paper, are known to have been sometimes +made of silk, ornamented with birds and flowers in needlework. +Tables and chairs were curiously carved in different woods; were +sometimes decorated with gold or silver; sometimes even made of +those precious metals. Knives and spoons were used at table; +golden ornaments were worn - with silk and cloth, and golden +tissues and embroideries; dishes were made of gold and silver, +brass and bone. There were varieties of drinking-horns, bedsteads, +musical instruments. A harp was passed round, at a feast, like the +drinking-bowl, from guest to guest; and each one usually sang or +played when his turn came. The weapons of the Saxons were stoutly +made, and among them was a terrible iron hammer that gave deadly +blows, and was long remembered. The Saxons themselves were a +handsome people. The men were proud of their long fair hair, +parted on the forehead; their ample beards, their fresh +complexions, and clear eyes. The beauty of the Saxon women filled +all England with a new delight and grace. + +I have more to tell of the Saxons yet, but I stop to say this now, +because under the GREAT ALFRED, all the best points of the English- +Saxon character were first encouraged, and in him first shown. It +has been the greatest character among the nations of the earth. +Wherever the descendants of the Saxon race have gone, have sailed, +or otherwise made their way, even to the remotest regions of the +world, they have been patient, persevering, never to be broken in +spirit, never to be turned aside from enterprises on which they +have resolved. In Europe, Asia, Africa, America, the whole world +over; in the desert, in the forest, on the sea; scorched by a +burning sun, or frozen by ice that never melts; the Saxon blood +remains unchanged. Wheresoever that race goes, there, law, and +industry, and safety for life and property, and all the great +results of steady perseverance, are certain to arise. + +I pause to think with admiration, of the noble king who, in his +single person, possessed all the Saxon virtues. Whom misfortune +could not subdue, whom prosperity could not spoil, whose +perseverance nothing could shake. Who was hopeful in defeat, and +generous in success. Who loved justice, freedom, truth, and +knowledge. Who, in his care to instruct his people, probably did +more to preserve the beautiful old Saxon language, than I can +imagine. Without whom, the English tongue in which I tell this +story might have wanted half its meaning. As it is said that his +spirit still inspires some of our best English laws, so, let you +and I pray that it may animate our English hearts, at least to this +- to resolve, when we see any of our fellow-creatures left in +ignorance, that we will do our best, while life is in us, to have +them taught; and to tell those rulers whose duty it is to teach +them, and who neglect their duty, that they have profited very +little by all the years that have rolled away since the year nine +hundred and one, and that they are far behind the bright example of +KING ALFRED THE GREAT. + + + +CHAPTER IV - ENGLAND UNDER ATHELSTAN AND THE SIX BOY-KINGS + + + +ATHELSTAN, the son of Edward the Elder, succeeded that king. He +reigned only fifteen years; but he remembered the glory of his +grandfather, the great Alfred, and governed England well. He +reduced the turbulent people of Wales, and obliged them to pay him +a tribute in money, and in cattle, and to send him their best hawks +and hounds. He was victorious over the Cornish men, who were not +yet quite under the Saxon government. He restored such of the old +laws as were good, and had fallen into disuse; made some wise new +laws, and took care of the poor and weak. A strong alliance, made +against him by ANLAF a Danish prince, CONSTANTINE King of the +Scots, and the people of North Wales, he broke and defeated in one +great battle, long famous for the vast numbers slain in it. After +that, he had a quiet reign; the lords and ladies about him had +leisure to become polite and agreeable; and foreign princes were +glad (as they have sometimes been since) to come to England on +visits to the English court. + +When Athelstan died, at forty-seven years old, his brother EDMUND, +who was only eighteen, became king. He was the first of six boy- +kings, as you will presently know. + +They called him the Magnificent, because he showed a taste for +improvement and refinement. But he was beset by the Danes, and had +a short and troubled reign, which came to a troubled end. One +night, when he was feasting in his hall, and had eaten much and +drunk deep, he saw, among the company, a noted robber named LEOF, +who had been banished from England. Made very angry by the +boldness of this man, the King turned to his cup-bearer, and said, +'There is a robber sitting at the table yonder, who, for his +crimes, is an outlaw in the land - a hunted wolf, whose life any +man may take, at any time. Command that robber to depart!' 'I +will not depart!' said Leof. 'No?' cried the King. 'No, by the +Lord!' said Leof. Upon that the King rose from his seat, and, +making passionately at the robber, and seizing him by his long +hair, tried to throw him down. But the robber had a dagger +underneath his cloak, and, in the scuffle, stabbed the King to +death. That done, he set his back against the wall, and fought so +desperately, that although he was soon cut to pieces by the King's +armed men, and the wall and pavement were splashed with his blood, +yet it was not before he had killed and wounded many of them. You +may imagine what rough lives the kings of those times led, when one +of them could struggle, half drunk, with a public robber in his own +dining-hall, and be stabbed in presence of the company who ate and +drank with him. + +Then succeeded the boy-king EDRED, who was weak and sickly in body, +but of a strong mind. And his armies fought the Northmen, the +Danes, and Norwegians, or the Sea-Kings, as they were called, and +beat them for the time. And, in nine years, Edred died, and passed +away. + +Then came the boy-king EDWY, fifteen years of age; but the real +king, who had the real power, was a monk named DUNSTAN - a clever +priest, a little mad, and not a little proud and cruel. + +Dunstan was then Abbot of Glastonbury Abbey, whither the body of +King Edmund the Magnificent was carried, to be buried. While yet a +boy, he had got out of his bed one night (being then in a fever), +and walked about Glastonbury Church when it was under repair; and, +because he did not tumble off some scaffolds that were there, and +break his neck, it was reported that he had been shown over the +building by an angel. He had also made a harp that was said to +play of itself - which it very likely did, as AEolian Harps, which +are played by the wind, and are understood now, always do. For +these wonders he had been once denounced by his enemies, who were +jealous of his favour with the late King Athelstan, as a magician; +and he had been waylaid, bound hand and foot, and thrown into a +marsh. But he got out again, somehow, to cause a great deal of +trouble yet. + +The priests of those days were, generally, the only scholars. They +were learned in many things. Having to make their own convents and +monasteries on uncultivated grounds that were granted to them by +the Crown, it was necessary that they should be good farmers and +good gardeners, or their lands would have been too poor to support +them. For the decoration of the chapels where they prayed, and for +the comfort of the refectories where they ate and drank, it was +necessary that there should be good carpenters, good smiths, good +painters, among them. For their greater safety in sickness and +accident, living alone by themselves in solitary places, it was +necessary that they should study the virtues of plants and herbs, +and should know how to dress cuts, burns, scalds, and bruises, and +how to set broken limbs. Accordingly, they taught themselves, and +one another, a great variety of useful arts; and became skilful in +agriculture, medicine, surgery, and handicraft. And when they +wanted the aid of any little piece of machinery, which would be +simple enough now, but was marvellous then, to impose a trick upon +the poor peasants, they knew very well how to make it; and DID make +it many a time and often, I have no doubt. + +Dunstan, Abbot of Glastonbury Abbey, was one of the most sagacious +of these monks. He was an ingenious smith, and worked at a forge +in a little cell. This cell was made too short to admit of his +lying at full length when he went to sleep - as if THAT did any +good to anybody! - and he used to tell the most extraordinary lies +about demons and spirits, who, he said, came there to persecute +him. For instance, he related that one day when he was at work, +the devil looked in at the little window, and tried to tempt him to +lead a life of idle pleasure; whereupon, having his pincers in the +fire, red hot, he seized the devil by the nose, and put him to such +pain, that his bellowings were heard for miles and miles. Some +people are inclined to think this nonsense a part of Dunstan's +madness (for his head never quite recovered the fever), but I think +not. I observe that it induced the ignorant people to consider him +a holy man, and that it made him very powerful. Which was exactly +what he always wanted. + +On the day of the coronation of the handsome boy-king Edwy, it was +remarked by ODO, Archbishop of Canterbury (who was a Dane by +birth), that the King quietly left the coronation feast, while all +the company were there. Odo, much displeased, sent his friend +Dunstan to seek him. Dunstan finding him in the company of his +beautiful young wife ELGIVA, and her mother ETHELGIVA, a good and +virtuous lady, not only grossly abused them, but dragged the young +King back into the feasting-hall by force. Some, again, think +Dunstan did this because the young King's fair wife was his own +cousin, and the monks objected to people marrying their own +cousins; but I believe he did it, because he was an imperious, +audacious, ill-conditioned priest, who, having loved a young lady +himself before he became a sour monk, hated all love now, and +everything belonging to it. + +The young King was quite old enough to feel this insult. Dunstan +had been Treasurer in the last reign, and he soon charged Dunstan +with having taken some of the last king's money. The Glastonbury +Abbot fled to Belgium (very narrowly escaping some pursuers who +were sent to put out his eyes, as you will wish they had, when you +read what follows), and his abbey was given to priests who were +married; whom he always, both before and afterwards, opposed. But +he quickly conspired with his friend, Odo the Dane, to set up the +King's young brother, EDGAR, as his rival for the throne; and, not +content with this revenge, he caused the beautiful queen Elgiva, +though a lovely girl of only seventeen or eighteen, to be stolen +from one of the Royal Palaces, branded in the cheek with a red-hot +iron, and sold into slavery in Ireland. But the Irish people +pitied and befriended her; and they said, 'Let us restore the girl- +queen to the boy-king, and make the young lovers happy!' and they +cured her of her cruel wound, and sent her home as beautiful as +before. But the villain Dunstan, and that other villain, Odo, +caused her to be waylaid at Gloucester as she was joyfully hurrying +to join her husband, and to be hacked and hewn with swords, and to +be barbarously maimed and lamed, and left to die. When Edwy the +Fair (his people called him so, because he was so young and +handsome) heard of her dreadful fate, he died of a broken heart; +and so the pitiful story of the poor young wife and husband ends! +Ah! Better to be two cottagers in these better times, than king +and queen of England in those bad days, though never so fair! + +Then came the boy-king, EDGAR, called the Peaceful, fifteen years +old. Dunstan, being still the real king, drove all married priests +out of the monasteries and abbeys, and replaced them by solitary +monks like himself, of the rigid order called the Benedictines. He +made himself Archbishop of Canterbury, for his greater glory; and +exercised such power over the neighbouring British princes, and so +collected them about the King, that once, when the King held his +court at Chester, and went on the river Dee to visit the monastery +of St. John, the eight oars of his boat were pulled (as the people +used to delight in relating in stories and songs) by eight crowned +kings, and steered by the King of England. As Edgar was very +obedient to Dunstan and the monks, they took great pains to +represent him as the best of kings. But he was really profligate, +debauched, and vicious. He once forcibly carried off a young lady +from the convent at Wilton; and Dunstan, pretending to be very much +shocked, condemned him not to wear his crown upon his head for +seven years - no great punishment, I dare say, as it can hardly +have been a more comfortable ornament to wear, than a stewpan +without a handle. His marriage with his second wife, ELFRIDA, is +one of the worst events of his reign. Hearing of the beauty of +this lady, he despatched his favourite courtier, ATHELWOLD, to her +father's castle in Devonshire, to see if she were really as +charming as fame reported. Now, she was so exceedingly beautiful +that Athelwold fell in love with her himself, and married her; but +he told the King that she was only rich - not handsome. The King, +suspecting the truth when they came home, resolved to pay the +newly-married couple a visit; and, suddenly, told Athelwold to +prepare for his immediate coming. Athelwold, terrified, confessed +to his young wife what he had said and done, and implored her to +disguise her beauty by some ugly dress or silly manner, that he +might be safe from the King's anger. She promised that she would; +but she was a proud woman, who would far rather have been a queen +than the wife of a courtier. She dressed herself in her best +dress, and adorned herself with her richest jewels; and when the +King came, presently, he discovered the cheat. So, he caused his +false friend, Athelwold, to be murdered in a wood, and married his +widow, this bad Elfrida. Six or seven years afterwards, he died; +and was buried, as if he had been all that the monks said he was, +in the abbey of Glastonbury, which he - or Dunstan for him - had +much enriched. + +England, in one part of this reign, was so troubled by wolves, +which, driven out of the open country, hid themselves in the +mountains of Wales when they were not attacking travellers and +animals, that the tribute payable by the Welsh people was forgiven +them, on condition of their producing, every year, three hundred +wolves' heads. And the Welshmen were so sharp upon the wolves, to +save their money, that in four years there was not a wolf left. + +Then came the boy-king, EDWARD, called the Martyr, from the manner +of his death. Elfrida had a son, named ETHELRED, for whom she +claimed the throne; but Dunstan did not choose to favour him, and +he made Edward king. The boy was hunting, one day, down in +Dorsetshire, when he rode near to Corfe Castle, where Elfrida and +Ethelred lived. Wishing to see them kindly, he rode away from his +attendants and galloped to the castle gate, where he arrived at +twilight, and blew his hunting-horn. 'You are welcome, dear King,' +said Elfrida, coming out, with her brightest smiles. 'Pray you +dismount and enter.' 'Not so, dear madam,' said the King. 'My +company will miss me, and fear that I have met with some harm. +Please you to give me a cup of wine, that I may drink here, in the +saddle, to you and to my little brother, and so ride away with the +good speed I have made in riding here.' Elfrida, going in to bring +the wine, whispered an armed servant, one of her attendants, who +stole out of the darkening gateway, and crept round behind the +King's horse. As the King raised the cup to his lips, saying, +'Health!' to the wicked woman who was smiling on him, and to his +innocent brother whose hand she held in hers, and who was only ten +years old, this armed man made a spring and stabbed him in the +back. He dropped the cup and spurred his horse away; but, soon +fainting with loss of blood, dropped from the saddle, and, in his +fall, entangled one of his feet in the stirrup. The frightened +horse dashed on; trailing his rider's curls upon the ground; +dragging his smooth young face through ruts, and stones, and +briers, and fallen leaves, and mud; until the hunters, tracking the +animal's course by the King's blood, caught his bridle, and +released the disfigured body. + +Then came the sixth and last of the boy-kings, ETHELRED, whom +Elfrida, when he cried out at the sight of his murdered brother +riding away from the castle gate, unmercifully beat with a torch +which she snatched from one of the attendants. The people so +disliked this boy, on account of his cruel mother and the murder +she had done to promote him, that Dunstan would not have had him +for king, but would have made EDGITHA, the daughter of the dead +King Edgar, and of the lady whom he stole out of the convent at +Wilton, Queen of England, if she would have consented. But she +knew the stories of the youthful kings too well, and would not be +persuaded from the convent where she lived in peace; so, Dunstan +put Ethelred on the throne, having no one else to put there, and +gave him the nickname of THE UNREADY - knowing that he wanted +resolution and firmness. + +At first, Elfrida possessed great influence over the young King, +but, as he grew older and came of age, her influence declined. The +infamous woman, not having it in her power to do any more evil, +then retired from court, and, according, to the fashion of the +time, built churches and monasteries, to expiate her guilt. As if +a church, with a steeple reaching to the very stars, would have +been any sign of true repentance for the blood of the poor boy, +whose murdered form was trailed at his horse's heels! As if she +could have buried her wickedness beneath the senseless stones of +the whole world, piled up one upon another, for the monks to live +in! + +About the ninth or tenth year of this reign, Dunstan died. He was +growing old then, but was as stern and artful as ever. Two +circumstances that happened in connexion with him, in this reign of +Ethelred, made a great noise. Once, he was present at a meeting of +the Church, when the question was discussed whether priests should +have permission to marry; and, as he sat with his head hung down, +apparently thinking about it, a voice seemed to come out of a +crucifix in the room, and warn the meeting to be of his opinion. +This was some juggling of Dunstan's, and was probably his own voice +disguised. But he played off a worse juggle than that, soon +afterwards; for, another meeting being held on the same subject, +and he and his supporters being seated on one side of a great room, +and their opponents on the other, he rose and said, 'To Christ +himself, as judge, do I commit this cause!' Immediately on these +words being spoken, the floor where the opposite party sat gave +way, and some were killed and many wounded. You may be pretty sure +that it had been weakened under Dunstan's direction, and that it +fell at Dunstan's signal. HIS part of the floor did not go down. +No, no. He was too good a workman for that. + +When he died, the monks settled that he was a Saint, and called him +Saint Dunstan ever afterwards. They might just as well have +settled that he was a coach-horse, and could just as easily have +called him one. + +Ethelred the Unready was glad enough, I dare say, to be rid of this +holy saint; but, left to himself, he was a poor weak king, and his +reign was a reign of defeat and shame. The restless Danes, led by +SWEYN, a son of the King of Denmark who had quarrelled with his +father and had been banished from home, again came into England, +and, year after year, attacked and despoiled large towns. To coax +these sea-kings away, the weak Ethelred paid them money; but, the +more money he paid, the more money the Danes wanted. At first, he +gave them ten thousand pounds; on their next invasion, sixteen +thousand pounds; on their next invasion, four and twenty thousand +pounds: to pay which large sums, the unfortunate English people +were heavily taxed. But, as the Danes still came back and wanted +more, he thought it would be a good plan to marry into some +powerful foreign family that would help him with soldiers. So, in +the year one thousand and two, he courted and married Emma, the +sister of Richard Duke of Normandy; a lady who was called the +Flower of Normandy. + +And now, a terrible deed was done in England, the like of which was +never done on English ground before or since. On the thirteenth of +November, in pursuance of secret instructions sent by the King over +the whole country, the inhabitants of every town and city armed, +and murdered all the Danes who were their neighbours. + +Young and old, babies and soldiers, men and women, every Dane was +killed. No doubt there were among them many ferocious men who had +done the English great wrong, and whose pride and insolence, in +swaggering in the houses of the English and insulting their wives +and daughters, had become unbearable; but no doubt there were also +among them many peaceful Christian Danes who had married English +women and become like English men. They were all slain, even to +GUNHILDA, the sister of the King of Denmark, married to an English +lord; who was first obliged to see the murder of her husband and +her child, and then was killed herself. + +When the King of the sea-kings heard of this deed of blood, he +swore that he would have a great revenge. He raised an army, and a +mightier fleet of ships than ever yet had sailed to England; and in +all his army there was not a slave or an old man, but every soldier +was a free man, and the son of a free man, and in the prime of +life, and sworn to be revenged upon the English nation, for the +massacre of that dread thirteenth of November, when his countrymen +and countrywomen, and the little children whom they loved, were +killed with fire and sword. And so, the sea-kings came to England +in many great ships, each bearing the flag of its own commander. +Golden eagles, ravens, dragons, dolphins, beasts of prey, +threatened England from the prows of those ships, as they came +onward through the water; and were reflected in the shining shields +that hung upon their sides. The ship that bore the standard of the +King of the sea-kings was carved and painted like a mighty serpent; +and the King in his anger prayed that the Gods in whom he trusted +might all desert him, if his serpent did not strike its fangs into +England's heart. + +And indeed it did. For, the great army landing from the great +fleet, near Exeter, went forward, laying England waste, and +striking their lances in the earth as they advanced, or throwing +them into rivers, in token of their making all the island theirs. +In remembrance of the black November night when the Danes were +murdered, wheresoever the invaders came, they made the Saxons +prepare and spread for them great feasts; and when they had eaten +those feasts, and had drunk a curse to England with wild +rejoicings, they drew their swords, and killed their Saxon +entertainers, and marched on. For six long years they carried on +this war: burning the crops, farmhouses, barns, mills, granaries; +killing the labourers in the fields; preventing the seed from being +sown in the ground; causing famine and starvation; leaving only +heaps of ruin and smoking ashes, where they had found rich towns. +To crown this misery, English officers and men deserted, and even +the favourites of Ethelred the Unready, becoming traitors, seized +many of the English ships, turned pirates against their own +country, and aided by a storm occasioned the loss of nearly the +whole English navy. + +There was but one man of note, at this miserable pass, who was true +to his country and the feeble King. He was a priest, and a brave +one. For twenty days, the Archbishop of Canterbury defended that +city against its Danish besiegers; and when a traitor in the town +threw the gates open and admitted them, he said, in chains, 'I will +not buy my life with money that must be extorted from the suffering +people. Do with me what you please!' Again and again, he steadily +refused to purchase his release with gold wrung from the poor. + +At last, the Danes being tired of this, and being assembled at a +drunken merry-making, had him brought into the feasting-hall. + +'Now, bishop,' they said, 'we want gold!' + +He looked round on the crowd of angry faces; from the shaggy beards +close to him, to the shaggy beards against the walls, where men +were mounted on tables and forms to see him over the heads of +others: and he knew that his time was come. + +'I have no gold,' he said. + +'Get it, bishop!' they all thundered. + +'That, I have often told you I will not,' said he. + +They gathered closer round him, threatening, but he stood unmoved. +Then, one man struck him; then, another; then a cursing soldier +picked up from a heap in a corner of the hall, where fragments had +been rudely thrown at dinner, a great ox-bone, and cast it at his +face, from which the blood came spurting forth; then, others ran to +the same heap, and knocked him down with other bones, and bruised +and battered him; until one soldier whom he had baptised (willing, +as I hope for the sake of that soldier's soul, to shorten the +sufferings of the good man) struck him dead with his battle-axe. + +If Ethelred had had the heart to emulate the courage of this noble +archbishop, he might have done something yet. But he paid the +Danes forty-eight thousand pounds, instead, and gained so little by +the cowardly act, that Sweyn soon afterwards came over to subdue +all England. So broken was the attachment of the English people, +by this time, to their incapable King and their forlorn country +which could not protect them, that they welcomed Sweyn on all +sides, as a deliverer. London faithfully stood out, as long as the +King was within its walls; but, when he sneaked away, it also +welcomed the Dane. Then, all was over; and the King took refuge +abroad with the Duke of Normandy, who had already given shelter to +the King's wife, once the Flower of that country, and to her +children. + +Still, the English people, in spite of their sad sufferings, could +not quite forget the great King Alfred and the Saxon race. When +Sweyn died suddenly, in little more than a month after he had been +proclaimed King of England, they generously sent to Ethelred, to +say that they would have him for their King again, 'if he would +only govern them better than he had governed them before.' The +Unready, instead of coming himself, sent Edward, one of his sons, +to make promises for him. At last, he followed, and the English +declared him King. The Danes declared CANUTE, the son of Sweyn, +King. Thus, direful war began again, and lasted for three years, +when the Unready died. And I know of nothing better that he did, +in all his reign of eight and thirty years. + +Was Canute to be King now? Not over the Saxons, they said; they +must have EDMUND, one of the sons of the Unready, who was surnamed +IRONSIDE, because of his strength and stature. Edmund and Canute +thereupon fell to, and fought five battles - O unhappy England, +what a fighting-ground it was! - and then Ironside, who was a big +man, proposed to Canute, who was a little man, that they two should +fight it out in single combat. If Canute had been the big man, he +would probably have said yes, but, being the little man, he +decidedly said no. However, he declared that he was willing to +divide the kingdom - to take all that lay north of Watling Street, +as the old Roman military road from Dover to Chester was called, +and to give Ironside all that lay south of it. Most men being +weary of so much bloodshed, this was done. But Canute soon became +sole King of England; for Ironside died suddenly within two months. +Some think that he was killed, and killed by Canute's orders. No +one knows. + + + +CHAPTER V - ENGLAND UNDER CANUTE THE DANE + + + +CANUTE reigned eighteen years. He was a merciless King at first. +After he had clasped the hands of the Saxon chiefs, in token of the +sincerity with which he swore to be just and good to them in return +for their acknowledging him, he denounced and slew many of them, as +well as many relations of the late King. 'He who brings me the +head of one of my enemies,' he used to say, 'shall be dearer to me +than a brother.' And he was so severe in hunting down his enemies, +that he must have got together a pretty large family of these dear +brothers. He was strongly inclined to kill EDMUND and EDWARD, two +children, sons of poor Ironside; but, being afraid to do so in +England, he sent them over to the King of Sweden, with a request +that the King would be so good as 'dispose of them.' If the King +of Sweden had been like many, many other men of that day, he would +have had their innocent throats cut; but he was a kind man, and +brought them up tenderly. + +Normandy ran much in Canute's mind. In Normandy were the two +children of the late king - EDWARD and ALFRED by name; and their +uncle the Duke might one day claim the crown for them. But the +Duke showed so little inclination to do so now, that he proposed to +Canute to marry his sister, the widow of The Unready; who, being +but a showy flower, and caring for nothing so much as becoming a +queen again, left her children and was wedded to him. + +Successful and triumphant, assisted by the valour of the English in +his foreign wars, and with little strife to trouble him at home, +Canute had a prosperous reign, and made many improvements. He was +a poet and a musician. He grew sorry, as he grew older, for the +blood he had shed at first; and went to Rome in a Pilgrim's dress, +by way of washing it out. He gave a great deal of money to +foreigners on his journey; but he took it from the English before +he started. On the whole, however, he certainly became a far +better man when he had no opposition to contend with, and was as +great a King as England had known for some time. + +The old writers of history relate how that Canute was one day +disgusted with his courtiers for their flattery, and how he caused +his chair to be set on the sea-shore, and feigned to command the +tide as it came up not to wet the edge of his robe, for the land +was his; how the tide came up, of course, without regarding him; +and how he then turned to his flatterers, and rebuked them, saying, +what was the might of any earthly king, to the might of the +Creator, who could say unto the sea, 'Thus far shalt thou go, and +no farther!' We may learn from this, I think, that a little sense +will go a long way in a king; and that courtiers are not easily +cured of flattery, nor kings of a liking for it. If the courtiers +of Canute had not known, long before, that the King was fond of +flattery, they would have known better than to offer it in such +large doses. And if they had not known that he was vain of this +speech (anything but a wonderful speech it seems to me, if a good +child had made it), they would not have been at such great pains to +repeat it. I fancy I see them all on the sea-shore together; the +King's chair sinking in the sand; the King in a mighty good humour +with his own wisdom; and the courtiers pretending to be quite +stunned by it! + +It is not the sea alone that is bidden to go 'thus far, and no +farther.' The great command goes forth to all the kings upon the +earth, and went to Canute in the year one thousand and thirty-five, +and stretched him dead upon his bed. Beside it, stood his Norman +wife. Perhaps, as the King looked his last upon her, he, who had +so often thought distrustfully of Normandy, long ago, thought once +more of the two exiled Princes in their uncle's court, and of the +little favour they could feel for either Danes or Saxons, and of a +rising cloud in Normandy that slowly moved towards England. + + + +CHAPTER VI - ENGLAND UNDER HAROLD HAREFOOT, HARDICANUTE, AND EDWARD +THE CONFESSOR + + + +CANUTE left three sons, by name SWEYN, HAROLD, and HARDICANUTE; but +his Queen, Emma, once the Flower of Normandy, was the mother of +only Hardicanute. Canute had wished his dominions to be divided +between the three, and had wished Harold to have England; but the +Saxon people in the South of England, headed by a nobleman with +great possessions, called the powerful EARL GODWIN (who is said to +have been originally a poor cow-boy), opposed this, and desired to +have, instead, either Hardicanute, or one of the two exiled Princes +who were over in Normandy. It seemed so certain that there would +be more bloodshed to settle this dispute, that many people left +their homes, and took refuge in the woods and swamps. Happily, +however, it was agreed to refer the whole question to a great +meeting at Oxford, which decided that Harold should have all the +country north of the Thames, with London for his capital city, and +that Hardicanute should have all the south. The quarrel was so +arranged; and, as Hardicanute was in Denmark troubling himself very +little about anything but eating and getting drunk, his mother and +Earl Godwin governed the south for him. + +They had hardly begun to do so, and the trembling people who had +hidden themselves were scarcely at home again, when Edward, the +elder of the two exiled Princes, came over from Normandy with a few +followers, to claim the English Crown. His mother Emma, however, +who only cared for her last son Hardicanute, instead of assisting +him, as he expected, opposed him so strongly with all her influence +that he was very soon glad to get safely back. His brother Alfred +was not so fortunate. Believing in an affectionate letter, written +some time afterwards to him and his brother, in his mother's name +(but whether really with or without his mother's knowledge is now +uncertain), he allowed himself to be tempted over to England, with +a good force of soldiers, and landing on the Kentish coast, and +being met and welcomed by Earl Godwin, proceeded into Surrey, as +far as the town of Guildford. Here, he and his men halted in the +evening to rest, having still the Earl in their company; who had +ordered lodgings and good cheer for them. But, in the dead of the +night, when they were off their guard, being divided into small +parties sleeping soundly after a long march and a plentiful supper +in different houses, they were set upon by the King's troops, and +taken prisoners. Next morning they were drawn out in a line, to +the number of six hundred men, and were barbarously tortured and +killed; with the exception of every tenth man, who was sold into +slavery. As to the wretched Prince Alfred, he was stripped naked, +tied to a horse and sent away into the Isle of Ely, where his eyes +were torn out of his head, and where in a few days he miserably +died. I am not sure that the Earl had wilfully entrapped him, but +I suspect it strongly. + +Harold was now King all over England, though it is doubtful whether +the Archbishop of Canterbury (the greater part of the priests were +Saxons, and not friendly to the Danes) ever consented to crown him. +Crowned or uncrowned, with the Archbishop's leave or without it, he +was King for four years: after which short reign he died, and was +buried; having never done much in life but go a hunting. He was +such a fast runner at this, his favourite sport, that the people +called him Harold Harefoot. + +Hardicanute was then at Bruges, in Flanders, plotting, with his +mother (who had gone over there after the cruel murder of Prince +Alfred), for the invasion of England. The Danes and Saxons, +finding themselves without a King, and dreading new disputes, made +common cause, and joined in inviting him to occupy the Throne. He +consented, and soon troubled them enough; for he brought over +numbers of Danes, and taxed the people so insupportably to enrich +those greedy favourites that there were many insurrections, +especially one at Worcester, where the citizens rose and killed his +tax-collectors; in revenge for which he burned their city. He was +a brutal King, whose first public act was to order the dead body of +poor Harold Harefoot to be dug up, beheaded, and thrown into the +river. His end was worthy of such a beginning. He fell down +drunk, with a goblet of wine in his hand, at a wedding-feast at +Lambeth, given in honour of the marriage of his standard-bearer, a +Dane named TOWED THE PROUD. And he never spoke again. + +EDWARD, afterwards called by the monks THE CONFESSOR, succeeded; +and his first act was to oblige his mother Emma, who had favoured +him so little, to retire into the country; where she died some ten +years afterwards. He was the exiled prince whose brother Alfred +had been so foully killed. He had been invited over from Normandy +by Hardicanute, in the course of his short reign of two years, and +had been handsomely treated at court. His cause was now favoured +by the powerful Earl Godwin, and he was soon made King. This Earl +had been suspected by the people, ever since Prince Alfred's cruel +death; he had even been tried in the last reign for the Prince's +murder, but had been pronounced not guilty; chiefly, as it was +supposed, because of a present he had made to the swinish King, of +a gilded ship with a figure-head of solid gold, and a crew of +eighty splendidly armed men. It was his interest to help the new +King with his power, if the new King would help him against the +popular distrust and hatred. So they made a bargain. Edward the +Confessor got the Throne. The Earl got more power and more land, +and his daughter Editha was made queen; for it was a part of their +compact that the King should take her for his wife. + +But, although she was a gentle lady, in all things worthy to be +beloved - good, beautiful, sensible, and kind - the King from the +first neglected her. Her father and her six proud brothers, +resenting this cold treatment, harassed the King greatly by +exerting all their power to make him unpopular. Having lived so +long in Normandy, he preferred the Normans to the English. He made +a Norman Archbishop, and Norman Bishops; his great officers and +favourites were all Normans; he introduced the Norman fashions and +the Norman language; in imitation of the state custom of Normandy, +he attached a great seal to his state documents, instead of merely +marking them, as the Saxon Kings had done, with the sign of the +cross - just as poor people who have never been taught to write, +now make the same mark for their names. All this, the powerful +Earl Godwin and his six proud sons represented to the people as +disfavour shown towards the English; and thus they daily increased +their own power, and daily diminished the power of the King. + +They were greatly helped by an event that occurred when he had +reigned eight years. Eustace, Earl of Bologne, who had married the +King's sister, came to England on a visit. After staying at the +court some time, he set forth, with his numerous train of +attendants, to return home. They were to embark at Dover. +Entering that peaceful town in armour, they took possession of the +best houses, and noisily demanded to be lodged and entertained +without payment. One of the bold men of Dover, who would not +endure to have these domineering strangers jingling their heavy +swords and iron corselets up and down his house, eating his meat +and drinking his strong liquor, stood in his doorway and refused +admission to the first armed man who came there. The armed man +drew, and wounded him. The man of Dover struck the armed man dead. +Intelligence of what he had done, spreading through the streets to +where the Count Eustace and his men were standing by their horses, +bridle in hand, they passionately mounted, galloped to the house, +surrounded it, forced their way in (the doors and windows being +closed when they came up), and killed the man of Dover at his own +fireside. They then clattered through the streets, cutting down +and riding over men, women, and children. This did not last long, +you may believe. The men of Dover set upon them with great fury, +killed nineteen of the foreigners, wounded many more, and, +blockading the road to the port so that they should not embark, +beat them out of the town by the way they had come. Hereupon, +Count Eustace rides as hard as man can ride to Gloucester, where +Edward is, surrounded by Norman monks and Norman lords. 'Justice!' +cries the Count, 'upon the men of Dover, who have set upon and +slain my people!' The King sends immediately for the powerful Earl +Godwin, who happens to be near; reminds him that Dover is under his +government; and orders him to repair to Dover and do military +execution on the inhabitants. 'It does not become you,' says the +proud Earl in reply, 'to condemn without a hearing those whom you +have sworn to protect. I will not do it.' + +The King, therefore, summoned the Earl, on pain of banishment and +loss of his titles and property, to appear before the court to +answer this disobedience. The Earl refused to appear. He, his +eldest son Harold, and his second son Sweyn, hastily raised as many +fighting men as their utmost power could collect, and demanded to +have Count Eustace and his followers surrendered to the justice of +the country. The King, in his turn, refused to give them up, and +raised a strong force. After some treaty and delay, the troops of +the great Earl and his sons began to fall off. The Earl, with a +part of his family and abundance of treasure, sailed to Flanders; +Harold escaped to Ireland; and the power of the great family was +for that time gone in England. But, the people did not forget +them. + +Then, Edward the Confessor, with the true meanness of a mean +spirit, visited his dislike of the once powerful father and sons +upon the helpless daughter and sister, his unoffending wife, whom +all who saw her (her husband and his monks excepted) loved. He +seized rapaciously upon her fortune and her jewels, and allowing +her only one attendant, confined her in a gloomy convent, of which +a sister of his - no doubt an unpleasant lady after his own heart - +was abbess or jailer. + +Having got Earl Godwin and his six sons well out of his way, the +King favoured the Normans more than ever. He invited over WILLIAM, +DUKE OF NORMANDY, the son of that Duke who had received him and his +murdered brother long ago, and of a peasant girl, a tanner's +daughter, with whom that Duke had fallen in love for her beauty as +he saw her washing clothes in a brook. William, who was a great +warrior, with a passion for fine horses, dogs, and arms, accepted +the invitation; and the Normans in England, finding themselves more +numerous than ever when he arrived with his retinue, and held in +still greater honour at court than before, became more and more +haughty towards the people, and were more and more disliked by +them. + +The old Earl Godwin, though he was abroad, knew well how the people +felt; for, with part of the treasure he had carried away with him, +he kept spies and agents in his pay all over England. + +Accordingly, he thought the time was come for fitting out a great +expedition against the Norman-loving King. With it, he sailed to +the Isle of Wight, where he was joined by his son Harold, the most +gallant and brave of all his family. And so the father and son +came sailing up the Thames to Southwark; great numbers of the +people declaring for them, and shouting for the English Earl and +the English Harold, against the Norman favourites! + +The King was at first as blind and stubborn as kings usually have +been whensoever they have been in the hands of monks. But the +people rallied so thickly round the old Earl and his son, and the +old Earl was so steady in demanding without bloodshed the +restoration of himself and his family to their rights, that at last +the court took the alarm. The Norman Archbishop of Canterbury, and +the Norman Bishop of London, surrounded by their retainers, fought +their way out of London, and escaped from Essex to France in a +fishing-boat. The other Norman favourites dispersed in all +directions. The old Earl and his sons (except Sweyn, who had +committed crimes against the law) were restored to their +possessions and dignities. Editha, the virtuous and lovely Queen +of the insensible King, was triumphantly released from her prison, +the convent, and once more sat in her chair of state, arrayed in +the jewels of which, when she had no champion to support her +rights, her cold-blooded husband had deprived her. + +The old Earl Godwin did not long enjoy his restored fortune. He +fell down in a fit at the King's table, and died upon the third day +afterwards. Harold succeeded to his power, and to a far higher +place in the attachment of the people than his father had ever +held. By his valour he subdued the King's enemies in many bloody +fights. He was vigorous against rebels in Scotland - this was the +time when Macbeth slew Duncan, upon which event our English +Shakespeare, hundreds of years afterwards, wrote his great tragedy; +and he killed the restless Welsh King GRIFFITH, and brought his +head to England. + +What Harold was doing at sea, when he was driven on the French +coast by a tempest, is not at all certain; nor does it at all +matter. That his ship was forced by a storm on that shore, and +that he was taken prisoner, there is no doubt. In those barbarous +days, all shipwrecked strangers were taken prisoners, and obliged +to pay ransom. So, a certain Count Guy, who was the Lord of +Ponthieu where Harold's disaster happened, seized him, instead of +relieving him like a hospitable and Christian lord as he ought to +have done, and expected to make a very good thing of it. + +But Harold sent off immediately to Duke William of Normandy, +complaining of this treatment; and the Duke no sooner heard of it +than he ordered Harold to be escorted to the ancient town of Rouen, +where he then was, and where he received him as an honoured guest. +Now, some writers tell us that Edward the Confessor, who was by +this time old and had no children, had made a will, appointing Duke +William of Normandy his successor, and had informed the Duke of his +having done so. There is no doubt that he was anxious about his +successor; because he had even invited over, from abroad, EDWARD +THE OUTLAW, a son of Ironside, who had come to England with his +wife and three children, but whom the King had strangely refused to +see when he did come, and who had died in London suddenly (princes +were terribly liable to sudden death in those days), and had been +buried in St. Paul's Cathedral. The King might possibly have made +such a will; or, having always been fond of the Normans, he might +have encouraged Norman William to aspire to \ No newline at end of file diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/zlib.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/zlib.go new file mode 100644 index 00000000..76457c6b --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/zlib.go @@ -0,0 +1,81 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package compression + +import ( + "bytes" + "compress/zlib" + "io" +) + +type zlibProvider struct{} + +// NewZLibProvider returns a Provider interface +func NewZLibProvider() Provider { + return &zlibProvider{} +} + +func (zlibProvider) CompressMaxSize(originalSize int) int { + // Use formula from ZLib: https://github.com/madler/zlib/blob/cacf7f1d4e3d44d871b605da3b647f07d718623f/deflate.c#L659 + return originalSize + + ((originalSize + 7) >> 3) + ((originalSize + 63) >> 6) + 11 +} + +func (zlibProvider) Compress(dst, src []byte) []byte { + var b = bytes.NewBuffer(dst[:0]) + w := zlib.NewWriter(b) + + if _, err := w.Write(src); err != nil { + return nil + } + if err := w.Close(); err != nil { + return nil + } + + return b.Bytes() +} + +func (zlibProvider) Decompress(dst, src []byte, originalSize int) ([]byte, error) { + r, err := zlib.NewReader(bytes.NewReader(src)) + if err != nil { + return nil, err + } + + if cap(dst) >= originalSize { + dst = dst[0:originalSize] // Reuse dst buffer + } else { + dst = make([]byte, originalSize) + } + if _, err = io.ReadFull(r, dst); err != nil { + return nil, err + } + + if err = r.Close(); err != nil { + return nil, err + } + + return dst, nil +} + +func (zlibProvider) Clone() Provider { + return NewZLibProvider() +} + +func (zlibProvider) Close() error { + return nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/zstd.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/zstd.go new file mode 100644 index 00000000..5142e0f5 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/zstd.go @@ -0,0 +1,36 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +//go:build !cgo +// +build !cgo + +package compression + +import ( + "fmt" +) + +func NewZStdProvider(level Level) Provider { + return newPureGoZStdProvider(level) +} + +func newCGoZStdProvider(level Level) Provider { + // This is kept to avoid compile errors in benchmark code when cgo is disabled. + // The warning is only shown when running the benchmark with CGO disabled. + fmt.Println("WARNING: CGO is disabled, using pure Go implementation of ZStd. Use CGO_ENABLED=1 when running benchmark.") + return newPureGoZStdProvider(level) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/zstd_cgo.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/zstd_cgo.go new file mode 100644 index 00000000..25429e25 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/zstd_cgo.go @@ -0,0 +1,82 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +//go:build cgo +// +build cgo + +// If CGO is enabled, use ZSTD library that links with official +// C based zstd which provides better performance compared with +// respect to the native Go implementation of ZStd. + +package compression + +import ( + "github.com/DataDog/zstd" + log "github.com/sirupsen/logrus" +) + +type zstdCGoProvider struct { + ctx zstd.Ctx + level Level + zstdLevel int +} + +func newCGoZStdProvider(level Level) Provider { + z := &zstdCGoProvider{ + ctx: zstd.NewCtx(), + } + + switch level { + case Default: + z.zstdLevel = zstd.DefaultCompression + case Faster: + z.zstdLevel = zstd.BestSpeed + case Better: + z.zstdLevel = 9 + } + + return z +} + +func NewZStdProvider(level Level) Provider { + return newCGoZStdProvider(level) +} + +func (z *zstdCGoProvider) CompressMaxSize(originalSize int) int { + return zstd.CompressBound(originalSize) +} + +func (z *zstdCGoProvider) Compress(dst, src []byte) []byte { + out, err := z.ctx.CompressLevel(dst, src, z.zstdLevel) + if err != nil { + log.WithError(err).Fatal("Failed to compress") + } + + return out +} + +func (z *zstdCGoProvider) Decompress(dst, src []byte, originalSize int) ([]byte, error) { + return z.ctx.Decompress(dst, src) +} + +func (z *zstdCGoProvider) Close() error { + return nil +} + +func (z *zstdCGoProvider) Clone() Provider { + return newCGoZStdProvider(z.level) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/zstd_go.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/zstd_go.go new file mode 100644 index 00000000..ae850783 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/compression/zstd_go.go @@ -0,0 +1,72 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package compression + +import ( + "github.com/klauspost/compress/zstd" +) + +type zstdProvider struct { + compressionLevel Level + encoder *zstd.Encoder + decoder *zstd.Decoder +} + +func newPureGoZStdProvider(level Level) Provider { + var zstdLevel zstd.EncoderLevel + p := &zstdProvider{} + switch level { + case Default: + zstdLevel = zstd.SpeedDefault + case Faster: + zstdLevel = zstd.SpeedFastest + case Better: + zstdLevel = zstd.SpeedBetterCompression + } + p.encoder, _ = zstd.NewWriter(nil, zstd.WithEncoderLevel(zstdLevel)) + p.decoder, _ = zstd.NewReader(nil) + return p +} + +func (p *zstdProvider) CompressMaxSize(srcSize int) int { + // from zstd.h + // this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB + lowLimit := 128 << 10 // 128 kB + var margin int + if srcSize < lowLimit { + margin = (lowLimit - srcSize) >> 11 + } + return srcSize + (srcSize >> 8) + margin +} + +func (p *zstdProvider) Compress(dst, src []byte) []byte { + return p.encoder.EncodeAll(src, dst) +} + +func (p *zstdProvider) Decompress(dst, src []byte, originalSize int) ([]byte, error) { + return p.decoder.DecodeAll(src, dst) +} + +func (p *zstdProvider) Close() error { + p.decoder.Close() + return p.encoder.Close() +} + +func (p *zstdProvider) Clone() Provider { + return newPureGoZStdProvider(p.compressionLevel) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/connection.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/connection.go new file mode 100644 index 00000000..59aad167 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/connection.go @@ -0,0 +1,1125 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "crypto/tls" + "crypto/x509" + "errors" + "fmt" + "net" + "net/url" + "os" + "sync" + "sync/atomic" + "time" + + "github.com/apache/pulsar-client-go/pulsar/auth" + + "google.golang.org/protobuf/proto" + + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "github.com/apache/pulsar-client-go/pulsar/log" + + ua "go.uber.org/atomic" +) + +const ( + PulsarProtocolVersion = int32(pb.ProtocolVersion_v18) +) + +type TLSOptions struct { + KeyFile string + CertFile string + TrustCertsFilePath string + AllowInsecureConnection bool + ValidateHostname bool + ServerName string +} + +var ( + errConnectionClosed = errors.New("connection closed") + errUnableRegisterListener = errors.New("unable register listener when con closed") + errUnableAddConsumeHandler = errors.New("unable add consumer handler when con closed") +) + +// ConnectionListener is a user of a connection (eg. a producer or +// a consumer) that can register itself to get notified +// when the connection is closed. +type ConnectionListener interface { + // ReceivedSendReceipt receive and process the return value of the send command. + ReceivedSendReceipt(response *pb.CommandSendReceipt) + + // ConnectionClosed close the TCP connection. + ConnectionClosed() +} + +// Connection is a interface of client cnx. +type Connection interface { + SendRequest(requestID uint64, req *pb.BaseCommand, callback func(*pb.BaseCommand, error)) + SendRequestNoWait(req *pb.BaseCommand) error + WriteData(data Buffer) + RegisterListener(id uint64, listener ConnectionListener) error + UnregisterListener(id uint64) + AddConsumeHandler(id uint64, handler ConsumerHandler) error + DeleteConsumeHandler(id uint64) + ID() string + GetMaxMessageSize() int32 + Close() +} + +type ConsumerHandler interface { + MessageReceived(response *pb.CommandMessage, headersAndPayload Buffer) error + + ActiveConsumerChanged(isActive bool) + + // ConnectionClosed close the TCP connection. + ConnectionClosed() +} + +type connectionState int32 + +const ( + connectionInit = iota + connectionReady + connectionClosing + connectionClosed +) + +func (s connectionState) String() string { + switch s { + case connectionInit: + return "Initializing" + case connectionReady: + return "Ready" + case connectionClosing: + return "Closing" + case connectionClosed: + return "Closed" + default: + return "Unknown" + } +} + +type request struct { + id *uint64 + cmd *pb.BaseCommand + callback func(command *pb.BaseCommand, err error) +} + +type incomingCmd struct { + cmd *pb.BaseCommand + headersAndPayload Buffer +} + +type connection struct { + sync.Mutex + cond *sync.Cond + started int32 + state ua.Int32 + connectionTimeout time.Duration + closeOnce sync.Once + + logicalAddr *url.URL + physicalAddr *url.URL + cnx net.Conn + + writeBufferLock sync.Mutex + writeBuffer Buffer + reader *connectionReader + + lastDataReceivedLock sync.Mutex + lastDataReceivedTime time.Time + + log log.Logger + + incomingRequestsWG sync.WaitGroup + incomingRequestsCh chan *request + incomingCmdCh chan *incomingCmd + closeCh chan interface{} + writeRequestsCh chan Buffer + + pendingLock sync.Mutex + pendingReqs map[uint64]*request + + listenersLock sync.RWMutex + listeners map[uint64]ConnectionListener + + consumerHandlersLock sync.RWMutex + consumerHandlers map[uint64]ConsumerHandler + + tlsOptions *TLSOptions + auth auth.Provider + + maxMessageSize int32 + metrics *Metrics + + keepAliveInterval time.Duration + + lastActive time.Time +} + +// connectionOptions defines configurations for creating connection. +type connectionOptions struct { + logicalAddr *url.URL + physicalAddr *url.URL + tls *TLSOptions + connectionTimeout time.Duration + auth auth.Provider + logger log.Logger + metrics *Metrics + keepAliveInterval time.Duration +} + +func newConnection(opts connectionOptions) *connection { + cnx := &connection{ + connectionTimeout: opts.connectionTimeout, + keepAliveInterval: opts.keepAliveInterval, + logicalAddr: opts.logicalAddr, + physicalAddr: opts.physicalAddr, + writeBuffer: NewBuffer(4096), + log: opts.logger.SubLogger(log.Fields{"remote_addr": opts.physicalAddr}), + pendingReqs: make(map[uint64]*request), + lastDataReceivedTime: time.Now(), + tlsOptions: opts.tls, + auth: opts.auth, + + closeCh: make(chan interface{}), + incomingRequestsCh: make(chan *request, 10), + incomingCmdCh: make(chan *incomingCmd, 10), + + // This channel is used to pass data from producers to the connection + // go routine. It can become contended or blocking if we have multiple + // partition produces writing on a single connection. In general it's + // good to keep this above the number of partition producers assigned + // to a single connection. + writeRequestsCh: make(chan Buffer, 256), + listeners: make(map[uint64]ConnectionListener), + consumerHandlers: make(map[uint64]ConsumerHandler), + metrics: opts.metrics, + } + cnx.setState(connectionInit) + cnx.reader = newConnectionReader(cnx) + cnx.cond = sync.NewCond(cnx) + return cnx +} + +func (c *connection) start() { + if !atomic.CompareAndSwapInt32(&c.started, 0, 1) { + c.log.Warnf("connection has already started") + return + } + + // Each connection gets its own goroutine that will + go func() { + if c.connect() { + if c.doHandshake() { + c.metrics.ConnectionsOpened.Inc() + c.run() + } else { + c.metrics.ConnectionsHandshakeErrors.Inc() + c.Close() + } + } else { + c.metrics.ConnectionsEstablishmentErrors.Inc() + c.Close() + } + }() +} + +func (c *connection) connect() bool { + c.log.Info("Connecting to broker") + + var ( + err error + cnx net.Conn + tlsConfig *tls.Config + ) + + if c.tlsOptions == nil { + // Clear text connection + cnx, err = net.DialTimeout("tcp", c.physicalAddr.Host, c.connectionTimeout) + } else { + // TLS connection + tlsConfig, err = c.getTLSConfig() + if err != nil { + c.log.WithError(err).Warn("Failed to configure TLS ") + return false + } + + d := &net.Dialer{Timeout: c.connectionTimeout} + cnx, err = tls.DialWithDialer(d, "tcp", c.physicalAddr.Host, tlsConfig) + } + + if err != nil { + c.log.WithError(err).Warn("Failed to connect to broker.") + c.Close() + return false + } + + c.Lock() + c.cnx = cnx + c.log = c.log.SubLogger(log.Fields{"local_addr": c.cnx.LocalAddr()}) + c.log.Info("TCP connection established") + c.Unlock() + + return true +} + +func (c *connection) doHandshake() bool { + // Send 'Connect' command to initiate handshake + authData, err := c.auth.GetData() + if err != nil { + c.log.WithError(err).Warn("Failed to load auth credentials") + return false + } + + // During the initial handshake, the internal keep alive is not + // active yet, so we need to timeout write and read requests + c.cnx.SetDeadline(time.Now().Add(c.keepAliveInterval)) + cmdConnect := &pb.CommandConnect{ + ProtocolVersion: proto.Int32(PulsarProtocolVersion), + ClientVersion: proto.String(ClientVersionString), + AuthMethodName: proto.String(c.auth.Name()), + AuthData: authData, + FeatureFlags: &pb.FeatureFlags{ + SupportsAuthRefresh: proto.Bool(true), + SupportsBrokerEntryMetadata: proto.Bool(true), + }, + } + + if c.logicalAddr.Host != c.physicalAddr.Host { + cmdConnect.ProxyToBrokerUrl = proto.String(c.logicalAddr.Host) + } + c.writeCommand(baseCommand(pb.BaseCommand_CONNECT, cmdConnect)) + cmd, _, err := c.reader.readSingleCommand() + if err != nil { + c.log.WithError(err).Warn("Failed to perform initial handshake") + return false + } + + // Reset the deadline so that we don't use read timeouts + c.cnx.SetDeadline(time.Time{}) + + if cmd.Connected == nil { + c.log.Warnf("Failed to establish connection with broker: '%s'", + cmd.Error.GetMessage()) + return false + } + if cmd.Connected.MaxMessageSize != nil && *cmd.Connected.MaxMessageSize > 0 { + c.log.Debug("Got MaxMessageSize from handshake response:", *cmd.Connected.MaxMessageSize) + c.maxMessageSize = *cmd.Connected.MaxMessageSize + } else { + c.log.Debug("No MaxMessageSize from handshake response, use default: ", MaxMessageSize) + c.maxMessageSize = MaxMessageSize + } + c.log.Info("Connection is ready") + c.changeState(connectionReady) + return true +} + +func (c *connection) waitUntilReady() error { + // If we are going to call cond.Wait() at all, then we must call it _before_ we call cond.Broadcast(). + // The lock is held here to prevent changeState() from calling cond.Broadcast() in the time between + // the state check and call to cond.Wait(). + c.Lock() + defer c.Unlock() + + for c.getState() != connectionReady { + c.log.Debugf("Wait until connection is ready state=%s", c.getState().String()) + if c.getState() == connectionClosed { + return errors.New("connection error") + } + // wait for a new connection state change + c.cond.Wait() + } + + return nil +} + +func (c *connection) failLeftRequestsWhenClose() { + // wait for outstanding incoming requests to complete before draining + // and closing the channel + c.incomingRequestsWG.Wait() + + ch := c.incomingRequestsCh + go func() { + // send a nil message to drain instead of + // closing the channel and causing a potential panic + // + // if other requests come in after the nil message + // then the RPC client will time out + ch <- nil + }() + for req := range ch { + if nil == req { + break // we have drained the requests + } + c.internalSendRequest(req) + } +} + +func (c *connection) run() { + pingSendTicker := time.NewTicker(c.keepAliveInterval) + pingCheckTicker := time.NewTicker(c.keepAliveInterval) + + defer func() { + // stop tickers + pingSendTicker.Stop() + pingCheckTicker.Stop() + + // all the accesses to the pendingReqs should be happened in this run loop thread, + // including the final cleanup, to avoid the issue + // https://github.com/apache/pulsar-client-go/issues/239 + c.failPendingRequests(errConnectionClosed) + c.Close() + }() + + // All reads come from the reader goroutine + go c.reader.readFromConnection() + go c.runPingCheck(pingCheckTicker) + + c.log.Debugf("Connection run starting with request capacity=%d queued=%d", + cap(c.incomingRequestsCh), len(c.incomingRequestsCh)) + + go func() { + for { + select { + case <-c.closeCh: + c.failLeftRequestsWhenClose() + return + + case req := <-c.incomingRequestsCh: + if req == nil { + return // TODO: this never gonna be happen + } + c.internalSendRequest(req) + } + } + }() + + for { + select { + case <-c.closeCh: + return + + case cmd := <-c.incomingCmdCh: + c.internalReceivedCommand(cmd.cmd, cmd.headersAndPayload) + case data := <-c.writeRequestsCh: + if data == nil { + return + } + c.internalWriteData(data) + + case <-pingSendTicker.C: + c.sendPing() + } + } +} + +func (c *connection) runPingCheck(pingCheckTicker *time.Ticker) { + for { + select { + case <-c.closeCh: + return + case <-pingCheckTicker.C: + if c.lastDataReceived().Add(2 * c.keepAliveInterval).Before(time.Now()) { + // We have not received a response to the previous Ping request, the + // connection to broker is stale + c.log.Warn("Detected stale connection to broker") + c.Close() + return + } + } + } +} + +func (c *connection) WriteData(data Buffer) { + select { + case c.writeRequestsCh <- data: + // Channel is not full + return + + default: + // Channel full, fallback to probe if connection is closed + } + + for { + select { + case c.writeRequestsCh <- data: + // Successfully wrote on the channel + return + + case <-time.After(100 * time.Millisecond): + // The channel is either: + // 1. blocked, in which case we need to wait until we have space + // 2. the connection is already closed, then we need to bail out + c.log.Debug("Couldn't write on connection channel immediately") + state := c.getState() + if state != connectionReady { + c.log.Debug("Connection was already closed") + return + } + } + } + +} + +func (c *connection) internalWriteData(data Buffer) { + c.log.Debug("Write data: ", data.ReadableBytes()) + if _, err := c.cnx.Write(data.ReadableSlice()); err != nil { + c.log.WithError(err).Warn("Failed to write on connection") + c.Close() + } +} + +func (c *connection) writeCommand(cmd *pb.BaseCommand) { + // Wire format + // [FRAME_SIZE] [CMD_SIZE][CMD] + cmdSize := uint32(proto.Size(cmd)) + frameSize := cmdSize + 4 + + c.writeBufferLock.Lock() + defer c.writeBufferLock.Unlock() + + c.writeBuffer.Clear() + c.writeBuffer.WriteUint32(frameSize) + + c.writeBuffer.WriteUint32(cmdSize) + c.writeBuffer.ResizeIfNeeded(cmdSize) + err := MarshalToSizedBuffer(cmd, c.writeBuffer.WritableSlice()[:cmdSize]) + if err != nil { + c.log.WithError(err).Error("Protobuf serialization error") + panic("Protobuf serialization error") + } + + c.writeBuffer.WrittenBytes(cmdSize) + c.internalWriteData(c.writeBuffer) +} + +func (c *connection) receivedCommand(cmd *pb.BaseCommand, headersAndPayload Buffer) { + c.incomingCmdCh <- &incomingCmd{cmd, headersAndPayload} +} + +func (c *connection) internalReceivedCommand(cmd *pb.BaseCommand, headersAndPayload Buffer) { + c.log.Debugf("Received command: %s -- payload: %v", cmd, headersAndPayload) + c.setLastDataReceived(time.Now()) + + switch *cmd.Type { + case pb.BaseCommand_SUCCESS: + c.handleResponse(cmd.Success.GetRequestId(), cmd) + + case pb.BaseCommand_PRODUCER_SUCCESS: + if !cmd.ProducerSuccess.GetProducerReady() { + request, ok := c.findPendingRequest(cmd.ProducerSuccess.GetRequestId()) + if ok { + request.callback(cmd, nil) + } + } else { + c.handleResponse(cmd.ProducerSuccess.GetRequestId(), cmd) + } + case pb.BaseCommand_PARTITIONED_METADATA_RESPONSE: + c.checkServerError(cmd.PartitionMetadataResponse.Error) + c.handleResponse(cmd.PartitionMetadataResponse.GetRequestId(), cmd) + + case pb.BaseCommand_LOOKUP_RESPONSE: + lookupResult := cmd.LookupTopicResponse + c.checkServerError(lookupResult.Error) + c.handleResponse(lookupResult.GetRequestId(), cmd) + + case pb.BaseCommand_CONSUMER_STATS_RESPONSE: + c.handleResponse(cmd.ConsumerStatsResponse.GetRequestId(), cmd) + + case pb.BaseCommand_GET_LAST_MESSAGE_ID_RESPONSE: + c.handleResponse(cmd.GetLastMessageIdResponse.GetRequestId(), cmd) + + case pb.BaseCommand_GET_TOPICS_OF_NAMESPACE_RESPONSE: + c.handleResponse(cmd.GetTopicsOfNamespaceResponse.GetRequestId(), cmd) + + case pb.BaseCommand_GET_SCHEMA_RESPONSE: + c.handleResponse(cmd.GetSchemaResponse.GetRequestId(), cmd) + + case pb.BaseCommand_GET_OR_CREATE_SCHEMA_RESPONSE: + c.handleResponse(cmd.GetOrCreateSchemaResponse.GetRequestId(), cmd) + + case pb.BaseCommand_ERROR: + c.handleResponseError(cmd.GetError()) + + case pb.BaseCommand_SEND_ERROR: + c.handleSendError(cmd.GetSendError()) + + case pb.BaseCommand_CLOSE_PRODUCER: + c.handleCloseProducer(cmd.GetCloseProducer()) + + case pb.BaseCommand_CLOSE_CONSUMER: + c.handleCloseConsumer(cmd.GetCloseConsumer()) + + case pb.BaseCommand_AUTH_CHALLENGE: + c.handleAuthChallenge(cmd.GetAuthChallenge()) + + case pb.BaseCommand_SEND_RECEIPT: + c.handleSendReceipt(cmd.GetSendReceipt()) + + case pb.BaseCommand_MESSAGE: + c.handleMessage(cmd.GetMessage(), headersAndPayload) + + case pb.BaseCommand_ACK_RESPONSE: + c.handleAckResponse(cmd.GetAckResponse()) + + case pb.BaseCommand_PING: + c.handlePing() + case pb.BaseCommand_PONG: + c.handlePong() + case pb.BaseCommand_TC_CLIENT_CONNECT_RESPONSE: + c.handleResponse(cmd.TcClientConnectResponse.GetRequestId(), cmd) + case pb.BaseCommand_NEW_TXN_RESPONSE: + c.handleResponse(cmd.NewTxnResponse.GetRequestId(), cmd) + case pb.BaseCommand_ADD_PARTITION_TO_TXN_RESPONSE: + c.handleResponse(cmd.AddPartitionToTxnResponse.GetRequestId(), cmd) + case pb.BaseCommand_ADD_SUBSCRIPTION_TO_TXN_RESPONSE: + c.handleResponse(cmd.AddSubscriptionToTxnResponse.GetRequestId(), cmd) + case pb.BaseCommand_END_TXN_RESPONSE: + c.handleResponse(cmd.EndTxnResponse.GetRequestId(), cmd) + case pb.BaseCommand_ACTIVE_CONSUMER_CHANGE: + c.handleActiveConsumerChange(cmd.GetActiveConsumerChange()) + + default: + c.log.Errorf("Received invalid command type: %s", cmd.Type) + c.Close() + } +} + +func (c *connection) checkServerError(err *pb.ServerError) { + if err == nil { + return + } + + if *err == pb.ServerError_ServiceNotReady { + c.Close() + } +} + +func (c *connection) Write(data Buffer) { + c.writeRequestsCh <- data +} + +func (c *connection) SendRequest(requestID uint64, req *pb.BaseCommand, + callback func(command *pb.BaseCommand, err error)) { + c.incomingRequestsWG.Add(1) + defer c.incomingRequestsWG.Done() + + state := c.getState() + if state == connectionClosed || state == connectionClosing { + callback(req, ErrConnectionClosed) + + } else { + select { + case <-c.closeCh: + callback(req, ErrConnectionClosed) + + case c.incomingRequestsCh <- &request{ + id: &requestID, + cmd: req, + callback: callback, + }: + } + } +} + +func (c *connection) SendRequestNoWait(req *pb.BaseCommand) error { + c.incomingRequestsWG.Add(1) + defer c.incomingRequestsWG.Done() + + state := c.getState() + if state == connectionClosed || state == connectionClosing { + return ErrConnectionClosed + } + + select { + case <-c.closeCh: + return ErrConnectionClosed + + case c.incomingRequestsCh <- &request{ + id: nil, + cmd: req, + callback: nil, + }: + return nil + } +} + +func (c *connection) internalSendRequest(req *request) { + if c.closed() { + c.log.Warnf("internalSendRequest failed for connectionClosed") + if req.callback != nil { + req.callback(req.cmd, ErrConnectionClosed) + } + } else { + c.pendingLock.Lock() + if req.id != nil { + c.pendingReqs[*req.id] = req + } + c.pendingLock.Unlock() + c.writeCommand(req.cmd) + } +} + +func (c *connection) handleResponse(requestID uint64, response *pb.BaseCommand) { + request, ok := c.deletePendingRequest(requestID) + if !ok { + c.log.Warnf("Received unexpected response for request %d of type %s", requestID, response.Type) + return + } + + request.callback(response, nil) +} + +func (c *connection) handleResponseError(serverError *pb.CommandError) { + requestID := serverError.GetRequestId() + + request, ok := c.deletePendingRequest(requestID) + if !ok { + c.log.Warnf("Received unexpected error response for request %d of type %s", + requestID, serverError.GetError()) + return + } + + errMsg := fmt.Sprintf("server error: %s: %s", serverError.GetError(), serverError.GetMessage()) + request.callback(nil, errors.New(errMsg)) +} + +func (c *connection) handleAckResponse(ackResponse *pb.CommandAckResponse) { + requestID := ackResponse.GetRequestId() + consumerID := ackResponse.GetConsumerId() + + request, ok := c.deletePendingRequest(requestID) + if !ok { + c.log.Warnf("AckResponse has complete when receive response! requestId : %d, consumerId : %d", + requestID, consumerID) + return + } + + if ackResponse.GetMessage() == "" { + request.callback(nil, nil) + return + } + + errMsg := fmt.Sprintf("ack response error: %s: %s", ackResponse.GetError(), ackResponse.GetMessage()) + request.callback(nil, errors.New(errMsg)) +} + +func (c *connection) handleSendReceipt(response *pb.CommandSendReceipt) { + producerID := response.GetProducerId() + + c.listenersLock.RLock() + producer, ok := c.listeners[producerID] + c.listenersLock.RUnlock() + + if ok { + producer.ReceivedSendReceipt(response) + } else { + c.log. + WithField("producerID", producerID). + Warn("Got unexpected send receipt for messageID=%+v", response.MessageId) + } +} + +func (c *connection) handleMessage(response *pb.CommandMessage, payload Buffer) { + c.log.Debug("Got Message: ", response) + consumerID := response.GetConsumerId() + if consumer, ok := c.consumerHandler(consumerID); ok { + err := consumer.MessageReceived(response, payload) + if err != nil { + c.log. + WithError(err). + WithField("consumerID", consumerID). + Error("handle message Id: ", response.MessageId) + } + } else { + c.log.WithField("consumerID", consumerID).Warn("Got unexpected message: ", response.MessageId) + } +} + +func (c *connection) deletePendingRequest(requestID uint64) (*request, bool) { + c.pendingLock.Lock() + defer c.pendingLock.Unlock() + request, ok := c.pendingReqs[requestID] + if ok { + delete(c.pendingReqs, requestID) + } + return request, ok +} + +func (c *connection) findPendingRequest(requestID uint64) (*request, bool) { + c.pendingLock.Lock() + defer c.pendingLock.Unlock() + request, ok := c.pendingReqs[requestID] + return request, ok +} + +func (c *connection) failPendingRequests(err error) bool { + c.pendingLock.Lock() + defer c.pendingLock.Unlock() + for id, req := range c.pendingReqs { + req.callback(nil, err) + delete(c.pendingReqs, id) + } + return true +} + +func (c *connection) lastDataReceived() time.Time { + c.lastDataReceivedLock.Lock() + defer c.lastDataReceivedLock.Unlock() + t := c.lastDataReceivedTime + return t +} + +func (c *connection) setLastDataReceived(t time.Time) { + c.lastDataReceivedLock.Lock() + defer c.lastDataReceivedLock.Unlock() + c.lastDataReceivedTime = t +} + +func (c *connection) sendPing() { + c.log.Debug("Sending PING") + c.writeCommand(baseCommand(pb.BaseCommand_PING, &pb.CommandPing{})) +} + +func (c *connection) handlePong() { + c.log.Debug("Received PONG response") +} + +func (c *connection) handlePing() { + c.log.Debug("Responding to PING request") + c.writeCommand(baseCommand(pb.BaseCommand_PONG, &pb.CommandPong{})) +} + +func (c *connection) handleAuthChallenge(authChallenge *pb.CommandAuthChallenge) { + c.log.Debugf("Received auth challenge from broker: %s", authChallenge.GetChallenge().GetAuthMethodName()) + + // Get new credentials from the provider + authData, err := c.auth.GetData() + if err != nil { + c.log.WithError(err).Warn("Failed to load auth credentials") + c.Close() + return + } + + cmdAuthResponse := &pb.CommandAuthResponse{ + ProtocolVersion: proto.Int32(PulsarProtocolVersion), + ClientVersion: proto.String(ClientVersionString), + Response: &pb.AuthData{ + AuthMethodName: proto.String(c.auth.Name()), + AuthData: authData, + }, + } + + c.writeCommand(baseCommand(pb.BaseCommand_AUTH_RESPONSE, cmdAuthResponse)) +} + +func (c *connection) handleSendError(sendError *pb.CommandSendError) { + c.log.Warnf("Received send error from server: [%v] : [%s]", sendError.GetError(), sendError.GetMessage()) + + producerID := sendError.GetProducerId() + + switch sendError.GetError() { + case pb.ServerError_NotAllowedError: + _, ok := c.deletePendingProducers(producerID) + if !ok { + c.log.Warnf("Received unexpected error response for request %d of type %s", + producerID, sendError.GetError()) + return + } + + c.log.Warnf("server error: %s: %s", sendError.GetError(), sendError.GetMessage()) + case pb.ServerError_TopicTerminatedError: + _, ok := c.deletePendingProducers(producerID) + if !ok { + c.log.Warnf("Received unexpected error response for producer %d of type %s", + producerID, sendError.GetError()) + return + } + c.log.Warnf("server error: %s: %s", sendError.GetError(), sendError.GetMessage()) + default: + // By default, for transient error, let the reconnection logic + // to take place and re-establish the produce again + c.Close() + } +} + +func (c *connection) deletePendingProducers(producerID uint64) (ConnectionListener, bool) { + c.listenersLock.Lock() + producer, ok := c.listeners[producerID] + if ok { + delete(c.listeners, producerID) + } + c.listenersLock.Unlock() + + return producer, ok +} + +func (c *connection) handleCloseConsumer(closeConsumer *pb.CommandCloseConsumer) { + consumerID := closeConsumer.GetConsumerId() + c.log.Infof("Broker notification of Closed consumer: %d", consumerID) + + if consumer, ok := c.consumerHandler(consumerID); ok { + consumer.ConnectionClosed() + c.DeleteConsumeHandler(consumerID) + } else { + c.log.WithField("consumerID", consumerID).Warnf("Consumer with ID not found while closing consumer") + } +} + +func (c *connection) handleActiveConsumerChange(consumerChange *pb.CommandActiveConsumerChange) { + consumerID := consumerChange.GetConsumerId() + isActive := consumerChange.GetIsActive() + if consumer, ok := c.consumerHandler(consumerID); ok { + consumer.ActiveConsumerChanged(isActive) + } else { + c.log.WithField("consumerID", consumerID).Warnf("Consumer not found while active consumer change") + } +} + +func (c *connection) handleCloseProducer(closeProducer *pb.CommandCloseProducer) { + c.log.Infof("Broker notification of Closed producer: %d", closeProducer.GetProducerId()) + producerID := closeProducer.GetProducerId() + + producer, ok := c.deletePendingProducers(producerID) + // did we find a producer? + if ok { + producer.ConnectionClosed() + } else { + c.log.WithField("producerID", producerID).Warn("Producer with ID not found while closing producer") + } +} + +func (c *connection) RegisterListener(id uint64, listener ConnectionListener) error { + // do not add if connection is closed + if c.closed() { + c.log.Warnf("Connection closed unable register listener id=%+v", id) + return errUnableRegisterListener + } + + c.listenersLock.Lock() + defer c.listenersLock.Unlock() + + c.listeners[id] = listener + return nil +} + +func (c *connection) UnregisterListener(id uint64) { + c.listenersLock.Lock() + defer c.listenersLock.Unlock() + + delete(c.listeners, id) +} + +func (c *connection) ResetLastActive() { + c.Lock() + defer c.Unlock() + c.lastActive = time.Now() +} + +func (c *connection) isIdle() bool { + { + c.pendingLock.Lock() + defer c.pendingLock.Unlock() + if len(c.pendingReqs) != 0 { + return false + } + } + + { + c.listenersLock.RLock() + defer c.listenersLock.RUnlock() + if len(c.listeners) != 0 { + return false + } + } + + { + c.consumerHandlersLock.Lock() + defer c.consumerHandlersLock.Unlock() + if len(c.consumerHandlers) != 0 { + return false + } + } + + if len(c.incomingRequestsCh) != 0 || len(c.writeRequestsCh) != 0 { + return false + } + return true +} + +func (c *connection) CheckIdle(maxIdleTime time.Duration) bool { + // We don't need to lock here because this method should only be + // called in a single goroutine of the connectionPool + if !c.isIdle() { + c.lastActive = time.Now() + } + return time.Since(c.lastActive) > maxIdleTime +} + +// Close closes the connection by +// closing underlying socket connection and closeCh. +// This also triggers callbacks to the ConnectionClosed listeners. +func (c *connection) Close() { + c.closeOnce.Do(func() { + c.Lock() + cnx := c.cnx + c.Unlock() + c.changeState(connectionClosed) + + if cnx != nil { + _ = cnx.Close() + } + + close(c.closeCh) + + listeners := make(map[uint64]ConnectionListener) + c.listenersLock.Lock() + for id, listener := range c.listeners { + listeners[id] = listener + delete(c.listeners, id) + } + c.listenersLock.Unlock() + + consumerHandlers := make(map[uint64]ConsumerHandler) + c.consumerHandlersLock.Lock() + for id, handler := range c.consumerHandlers { + consumerHandlers[id] = handler + delete(c.consumerHandlers, id) + } + c.consumerHandlersLock.Unlock() + + // notify producers connection closed + for _, listener := range listeners { + listener.ConnectionClosed() + } + + // notify consumers connection closed + for _, handler := range consumerHandlers { + handler.ConnectionClosed() + } + + c.metrics.ConnectionsClosed.Inc() + }) +} + +func (c *connection) changeState(state connectionState) { + // The lock is held here because we need setState() and cond.Broadcast() to be + // an atomic operation from the point of view of waitUntilReady(). + c.Lock() + defer c.Unlock() + + c.setState(state) + c.cond.Broadcast() +} + +func (c *connection) getState() connectionState { + return connectionState(c.state.Load()) +} + +func (c *connection) setState(state connectionState) { + c.state.Store(int32(state)) +} + +func (c *connection) closed() bool { + return connectionClosed == c.getState() +} + +func (c *connection) getTLSConfig() (*tls.Config, error) { + tlsConfig := &tls.Config{ + InsecureSkipVerify: c.tlsOptions.AllowInsecureConnection, + } + + if c.tlsOptions.TrustCertsFilePath != "" { + caCerts, err := os.ReadFile(c.tlsOptions.TrustCertsFilePath) + if err != nil { + return nil, err + } + + tlsConfig.RootCAs = x509.NewCertPool() + ok := tlsConfig.RootCAs.AppendCertsFromPEM(caCerts) + if !ok { + return nil, errors.New("failed to parse root CAs certificates") + } + } + + if c.tlsOptions.ValidateHostname { + if c.tlsOptions.ServerName != "" { + tlsConfig.ServerName = c.tlsOptions.ServerName + } else { + tlsConfig.ServerName = c.physicalAddr.Hostname() + } + c.log.Debugf("getTLSConfig(): setting tlsConfig.ServerName = %+v", tlsConfig.ServerName) + } + + if c.tlsOptions.CertFile != "" && c.tlsOptions.KeyFile != "" { + cert, err := tls.LoadX509KeyPair(c.tlsOptions.CertFile, c.tlsOptions.KeyFile) + if err != nil { + return nil, errors.New(err.Error()) + } + tlsConfig.Certificates = []tls.Certificate{cert} + } + + cert, err := c.auth.GetTLSCertificate() + if err != nil { + return nil, err + } + + if cert != nil { + tlsConfig.Certificates = []tls.Certificate{*cert} + } + + return tlsConfig, nil +} + +func (c *connection) AddConsumeHandler(id uint64, handler ConsumerHandler) error { + // do not add if connection is closed + if c.closed() { + c.log.Warnf("Closed connection unable add consumer with id=%+v", id) + return errUnableAddConsumeHandler + } + + c.consumerHandlersLock.Lock() + defer c.consumerHandlersLock.Unlock() + c.consumerHandlers[id] = handler + return nil +} + +func (c *connection) DeleteConsumeHandler(id uint64) { + c.consumerHandlersLock.Lock() + defer c.consumerHandlersLock.Unlock() + delete(c.consumerHandlers, id) +} + +func (c *connection) consumerHandler(id uint64) (ConsumerHandler, bool) { + c.consumerHandlersLock.RLock() + defer c.consumerHandlersLock.RUnlock() + h, ok := c.consumerHandlers[id] + return h, ok +} + +func (c *connection) ID() string { + return fmt.Sprintf("%s -> %s", c.cnx.LocalAddr(), c.cnx.RemoteAddr()) +} + +func (c *connection) GetMaxMessageSize() int32 { + return c.maxMessageSize +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/connection_pool.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/connection_pool.go new file mode 100644 index 00000000..6ff79919 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/connection_pool.go @@ -0,0 +1,166 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "fmt" + "net/url" + "sync" + "sync/atomic" + "time" + + "github.com/apache/pulsar-client-go/pulsar/auth" + + "github.com/apache/pulsar-client-go/pulsar/log" +) + +// ConnectionPool is a interface of connection pool. +type ConnectionPool interface { + // GetConnection get a connection from ConnectionPool. + GetConnection(logicalAddr *url.URL, physicalAddr *url.URL) (Connection, error) + + // Close all the connections in the pool + Close() +} + +type connectionPool struct { + sync.Mutex + connections map[string]*connection + connectionTimeout time.Duration + tlsOptions *TLSOptions + auth auth.Provider + maxConnectionsPerHost int32 + roundRobinCnt int32 + keepAliveInterval time.Duration + closeCh chan struct{} + + metrics *Metrics + log log.Logger +} + +// NewConnectionPool init connection pool. +func NewConnectionPool( + tlsOptions *TLSOptions, + auth auth.Provider, + connectionTimeout time.Duration, + keepAliveInterval time.Duration, + maxConnectionsPerHost int, + logger log.Logger, + metrics *Metrics, + connectionMaxIdleTime time.Duration) ConnectionPool { + p := &connectionPool{ + connections: make(map[string]*connection), + tlsOptions: tlsOptions, + auth: auth, + connectionTimeout: connectionTimeout, + maxConnectionsPerHost: int32(maxConnectionsPerHost), + keepAliveInterval: keepAliveInterval, + log: logger, + metrics: metrics, + closeCh: make(chan struct{}), + } + go p.checkAndCleanIdleConnections(connectionMaxIdleTime) + return p +} + +func (p *connectionPool) GetConnection(logicalAddr *url.URL, physicalAddr *url.URL) (Connection, error) { + key := p.getMapKey(logicalAddr) + + p.Lock() + conn, ok := p.connections[key] + if ok { + p.log.Debugf("Found connection in pool key=%s logical_addr=%+v physical_addr=%+v", + key, conn.logicalAddr, conn.physicalAddr) + + // When the current connection is in a closed state or the broker actively notifies that the + // current connection is closed, we need to remove the connection object from the current + // connection pool and create a new connection. + if conn.closed() { + p.log.Debugf("Removed connection from pool key=%s logical_addr=%+v physical_addr=%+v", + key, conn.logicalAddr, conn.physicalAddr) + delete(p.connections, key) + conn.Close() + conn = nil // set to nil so we create a new one + } + } + + if conn == nil { + conn = newConnection(connectionOptions{ + logicalAddr: logicalAddr, + physicalAddr: physicalAddr, + tls: p.tlsOptions, + connectionTimeout: p.connectionTimeout, + auth: p.auth, + keepAliveInterval: p.keepAliveInterval, + logger: p.log, + metrics: p.metrics, + }) + p.connections[key] = conn + p.Unlock() + conn.start() + } else { + conn.ResetLastActive() + // we already have a connection + p.Unlock() + } + + err := conn.waitUntilReady() + return conn, err +} + +func (p *connectionPool) Close() { + p.Lock() + close(p.closeCh) + for k, c := range p.connections { + delete(p.connections, k) + c.Close() + } + p.Unlock() +} + +func (p *connectionPool) getMapKey(addr *url.URL) string { + cnt := atomic.AddInt32(&p.roundRobinCnt, 1) + if cnt < 0 { + cnt = -cnt + } + idx := cnt % p.maxConnectionsPerHost + return fmt.Sprint(addr.Host, '-', idx) +} + +func (p *connectionPool) checkAndCleanIdleConnections(maxIdleTime time.Duration) { + if maxIdleTime < 0 { + return + } + for { + select { + case <-p.closeCh: + return + case <-time.After(maxIdleTime): + p.Lock() + for k, c := range p.connections { + if c.CheckIdle(maxIdleTime) { + p.log.Debugf("Closed connection from pool due to inactivity. logical_addr=%+v physical_addr=%+v", + c.logicalAddr, c.physicalAddr) + delete(p.connections, k) + c.Close() + } + } + p.Unlock() + } + } +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/connection_reader.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/connection_reader.go new file mode 100644 index 00000000..c451562c --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/connection_reader.go @@ -0,0 +1,148 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "bufio" + "fmt" + "io" + + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "google.golang.org/protobuf/proto" +) + +type connectionReader struct { + cnx *connection + buffer Buffer + reader *bufio.Reader +} + +func newConnectionReader(cnx *connection) *connectionReader { + return &connectionReader{ + cnx: cnx, + reader: bufio.NewReader(cnx.cnx), + buffer: NewBuffer(4096), + } +} + +func (r *connectionReader) readFromConnection() { + for { + cmd, headersAndPayload, err := r.readSingleCommand() + if err != nil { + if !r.cnx.closed() { + r.cnx.log.WithError(err).Infof("Error reading from connection") + r.cnx.Close() + } + break + } + + // Process + var payloadLen uint32 + if headersAndPayload != nil { + payloadLen = headersAndPayload.ReadableBytes() + } + r.cnx.log.Debug("Got command! ", cmd, " with payload size: ", payloadLen, " maxMsgSize: ", r.cnx.maxMessageSize) + r.cnx.receivedCommand(cmd, headersAndPayload) + } +} + +func (r *connectionReader) readSingleCommand() (cmd *pb.BaseCommand, headersAndPayload Buffer, err error) { + // First, we need to read the frame size + if r.buffer.ReadableBytes() < 4 { + if r.buffer.ReadableBytes() == 0 { + // If the buffer is empty, just go back to write at the beginning + r.buffer.Clear() + } + if err := r.readAtLeast(4); err != nil { + return nil, nil, fmt.Errorf("unable to read frame size: %+v", err) + } + } + + // We have enough to read frame size + frameSize := r.buffer.ReadUint32() + maxFrameSize := r.cnx.maxMessageSize + MessageFramePadding + if r.cnx.maxMessageSize != 0 && int32(frameSize) > maxFrameSize { + frameSizeError := fmt.Errorf("received too big frame size=%d maxFrameSize=%d", frameSize, maxFrameSize) + r.cnx.log.Error(frameSizeError) + r.cnx.Close() + return nil, nil, frameSizeError + } + + // Next, we read the rest of the frame + if r.buffer.ReadableBytes() < frameSize { + remainingBytes := frameSize - r.buffer.ReadableBytes() + if err := r.readAtLeast(remainingBytes); err != nil { + return nil, nil, + fmt.Errorf("unable to read frame: %+v", err) + } + } + + // We have now the complete frame + cmdSize := r.buffer.ReadUint32() + cmd, err = r.deserializeCmd(r.buffer.Read(cmdSize)) + if err != nil { + return nil, nil, err + } + + // Also read the eventual payload + headersAndPayloadSize := frameSize - (cmdSize + 4) + if cmdSize+4 < frameSize { + headersAndPayload = NewBuffer(int(headersAndPayloadSize)) + headersAndPayload.Write(r.buffer.Read(headersAndPayloadSize)) + } + return cmd, headersAndPayload, nil +} + +func (r *connectionReader) readAtLeast(size uint32) error { + if r.buffer.WritableBytes() < size { + // There's not enough room in the current buffer to read the requested amount of data + totalFrameSize := r.buffer.ReadableBytes() + size + if r.buffer.ReadableBytes()+size > r.buffer.Capacity() { + // Resize to a bigger buffer to avoid continuous resizing + r.buffer.Resize(totalFrameSize * 2) + } else { + // Compact the buffer by moving the partial data to the beginning. + // This will have enough room for reading the remainder of the data + r.buffer.MoveToFront() + } + } + + n, err := io.ReadAtLeast(r.cnx.cnx, r.buffer.WritableSlice(), int(size)) + if err != nil { + // has the connection been closed? + if r.cnx.closed() { + return errConnectionClosed + } + r.cnx.Close() + return err + } + + r.buffer.WrittenBytes(uint32(n)) + return nil +} + +func (r *connectionReader) deserializeCmd(data []byte) (*pb.BaseCommand, error) { + cmd := &pb.BaseCommand{} + err := proto.Unmarshal(data, cmd) + if err != nil { + r.cnx.log.WithError(err).Warn("Failed to parse protobuf command") + r.cnx.Close() + return nil, err + } + return cmd, nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/consumer_decryptor.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/consumer_decryptor.go new file mode 100644 index 00000000..bbc1f9b1 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/consumer_decryptor.go @@ -0,0 +1,60 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package crypto + +import ( + "fmt" + + "github.com/apache/pulsar-client-go/pulsar/crypto" + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "github.com/apache/pulsar-client-go/pulsar/log" +) + +type consumerDecryptor struct { + keyReader crypto.KeyReader + messageCrypto crypto.MessageCrypto + logger log.Logger +} + +func NewConsumerDecryptor(keyReader crypto.KeyReader, + messageCrypto crypto.MessageCrypto, + logger log.Logger) Decryptor { + return &consumerDecryptor{ + keyReader: keyReader, + messageCrypto: messageCrypto, + logger: logger, + } +} + +func (d *consumerDecryptor) Decrypt(payload []byte, + msgID *pb.MessageIdData, + msgMetadata *pb.MessageMetadata) ([]byte, error) { + // encryption keys are not present in message metadta, no need decrypt the payload + if len(msgMetadata.GetEncryptionKeys()) == 0 { + return payload, nil + } + + // KeyReader interface is not implemented + if d.keyReader == nil { + return payload, fmt.Errorf("KeyReader interface is not implemented") + } + + return d.messageCrypto.Decrypt(crypto.NewMessageMetadataSupplier(msgMetadata), + payload, + d.keyReader) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/decryptor.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/decryptor.go new file mode 100644 index 00000000..da67d5cd --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/decryptor.go @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package crypto + +import ( + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" +) + +// Decryptor support decrypting of message +type Decryptor interface { + Decrypt(payload []byte, msgID *pb.MessageIdData, msgMetadata *pb.MessageMetadata) ([]byte, error) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/encryptor.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/encryptor.go new file mode 100644 index 00000000..7fdbf06a --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/encryptor.go @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package crypto + +import ( + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" +) + +// Encryptor support encryption +type Encryptor interface { + Encrypt([]byte, *pb.MessageMetadata) ([]byte, error) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/noop_decryptor.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/noop_decryptor.go new file mode 100644 index 00000000..c049c472 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/noop_decryptor.go @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package crypto + +import ( + "fmt" + + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" +) + +type noopDecryptor struct{} + +func NewNoopDecryptor() Decryptor { + return &noopDecryptor{} +} + +// Decrypt noop decryptor +func (d *noopDecryptor) Decrypt(payload []byte, + msgID *pb.MessageIdData, + msgMetadata *pb.MessageMetadata) ([]byte, error) { + if len(msgMetadata.GetEncryptionKeys()) > 0 { + return payload, fmt.Errorf("incoming message payload is encrypted, consumer is not configured to decrypt") + } + return payload, nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/noop_encryptor.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/noop_encryptor.go new file mode 100644 index 00000000..4512e7bd --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/noop_encryptor.go @@ -0,0 +1,33 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package crypto + +import ( + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" +) + +type noopEncryptor struct{} + +func NewNoopEncryptor() Encryptor { + return &noopEncryptor{} +} + +// Encrypt Noop ecryptor +func (e *noopEncryptor) Encrypt(data []byte, msgMetadata *pb.MessageMetadata) ([]byte, error) { + return data, nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/producer_encryptor.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/producer_encryptor.go new file mode 100644 index 00000000..a5b972da --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/crypto/producer_encryptor.go @@ -0,0 +1,73 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package crypto + +import ( + "fmt" + + "github.com/apache/pulsar-client-go/pulsar/crypto" + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "github.com/apache/pulsar-client-go/pulsar/log" +) + +type producerEncryptor struct { + keys []string + keyReader crypto.KeyReader + messageCrypto crypto.MessageCrypto + logger log.Logger + producerCryptoFailureAction int +} + +func NewProducerEncryptor(keys []string, + keyReader crypto.KeyReader, + messageCrypto crypto.MessageCrypto, + producerCryptoFailureAction int, + logger log.Logger) Encryptor { + return &producerEncryptor{ + keys: keys, + keyReader: keyReader, + messageCrypto: messageCrypto, + logger: logger, + producerCryptoFailureAction: producerCryptoFailureAction, + } +} + +// Encrypt producer encryptor +func (e *producerEncryptor) Encrypt(payload []byte, msgMetadata *pb.MessageMetadata) ([]byte, error) { + // encrypt payload + encryptedPayload, err := e.messageCrypto.Encrypt(e.keys, + e.keyReader, + crypto.NewMessageMetadataSupplier(msgMetadata), + payload) + + // error encryping the payload + if err != nil { + // error occurred in encrypting the payload + // crypto ProducerCryptoFailureAction is set to send + // send unencrypted message + if e.producerCryptoFailureAction == crypto.ProducerCryptoFailureActionSend { + e.logger. + WithError(err). + Warnf("Encryption failed for payload sending unencrypted message ProducerCryptoFailureAction is set to send") + return payload, nil + } + + return nil, fmt.Errorf("ProducerCryptoFailureAction is set to Fail and error occurred in encrypting payload :%v", err) + } + return encryptedPayload, nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/hash.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/hash.go new file mode 100644 index 00000000..0ac85907 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/hash.go @@ -0,0 +1,41 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import "github.com/spaolacci/murmur3" + +// JavaStringHash and Java String.hashCode() equivalent +func JavaStringHash(s string) uint32 { + var h uint32 + for i, size := 0, len(s); i < size; i++ { + h = 31*h + uint32(s[i]) + } + + return h +} + +// Murmur3_32Hash use Murmur3 hashing function +func Murmur3_32Hash(s string) uint32 { + h := murmur3.New32() + _, err := h.Write([]byte(s)) + if err != nil { + return 0 + } + // Maintain compatibility with values used in Java client + return h.Sum32() & 0x7fffffff +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/helper.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/helper.go new file mode 100644 index 00000000..3bca1ee0 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/helper.go @@ -0,0 +1,33 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import "time" + +// These method should only be used by tests + +func StartCleanConnectionsTask(p *ConnectionPool, connectionMaxIdleTime time.Duration) { + go (*p).(*connectionPool).checkAndCleanIdleConnections(connectionMaxIdleTime) +} + +func GetConnectionsCount(p *ConnectionPool) int { + pool := (*p).(*connectionPool) + pool.Lock() + defer pool.Unlock() + return len(pool.connections) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/http_client.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/http_client.go new file mode 100644 index 00000000..dccc1431 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/http_client.go @@ -0,0 +1,360 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "io" + "net/http" + "net/url" + "os" + "path" + "time" + + "github.com/apache/pulsar-client-go/pulsar/auth" + + "github.com/apache/pulsar-client-go/pulsar/log" + + "github.com/pkg/errors" +) + +// httpClient is a base client that is used to make http httpRequest to the ServiceURL +type httpClient struct { + ServiceNameResolver ServiceNameResolver + HTTPClient *http.Client + requestTimeout time.Duration + log log.Logger + metrics *Metrics +} + +func (c *httpClient) Close() { + if c.HTTPClient != nil { + c.HTTPClient.CloseIdleConnections() + } +} + +type HTTPClient interface { + Get(endpoint string, obj interface{}, params map[string]string) error + Closable +} + +func NewHTTPClient(serviceURL *url.URL, serviceNameResolver ServiceNameResolver, tlsConfig *TLSOptions, + requestTimeout time.Duration, logger log.Logger, metrics *Metrics, + authProvider auth.Provider) (HTTPClient, error) { + h := &httpClient{ + ServiceNameResolver: serviceNameResolver, + requestTimeout: requestTimeout, + log: logger.SubLogger(log.Fields{"serviceURL": serviceURL}), + metrics: metrics, + } + c := &http.Client{Timeout: requestTimeout} + transport, err := getDefaultTransport(tlsConfig) + if err != nil { + return nil, err + } + c.Transport = transport + if authProvider.Name() != "" { + err = authProvider.WithTransport(c.Transport) + if err != nil { + return nil, err + } + c.Transport = authProvider + } + h.HTTPClient = c + return h, nil +} + +func (c *httpClient) newRequest(method, path string) (*httpRequest, error) { + base, err := c.ServiceNameResolver.ResolveHost() + if err != nil { + return nil, err + } + + u, err := url.Parse(path) + if err != nil { + return nil, err + } + + req := &httpRequest{ + method: method, + url: &url.URL{ + Scheme: base.Scheme, + User: base.User, + Host: base.Host, + Path: endpoint(base.Path, u.Path), + }, + params: make(url.Values), + } + return req, nil +} + +func (c *httpClient) doRequest(r *httpRequest) (*http.Response, error) { + req, err := r.toHTTP() + if err != nil { + return nil, err + } + + if r.contentType != "" { + req.Header.Set("Content-Type", r.contentType) + } else if req.Body != nil { + req.Header.Set("Content-Type", "application/json") + } + + req.Header.Set("Accept", "application/json") + req.Header.Set("User-Agent", c.useragent()) + hc := c.HTTPClient + if hc == nil { + hc = http.DefaultClient + } + + return hc.Do(req) +} + +// MakeRequest can make a simple httpRequest and handle the response by yourself +func (c *httpClient) MakeRequest(method, endpoint string) (*http.Response, error) { + req, err := c.newRequest(method, endpoint) + if err != nil { + return nil, err + } + + resp, err := checkSuccessful(c.doRequest(req)) + if err != nil { + return nil, err + } + + return resp, nil +} + +func (c *httpClient) Get(endpoint string, obj interface{}, params map[string]string) error { + _, err := c.GetWithQueryParams(endpoint, obj, params, true) + if _, ok := err.(*url.Error); ok { + // We can retry this kind of requests over a connection error because they're + // not specific to a particular broker. + backoff := DefaultBackoff{100 * time.Millisecond} + startTime := time.Now() + var retryTime time.Duration + + for time.Since(startTime) < c.requestTimeout { + retryTime = backoff.Next() + c.log.Debugf("Retrying httpRequest in {%v} with timeout in {%v}", retryTime, c.requestTimeout) + time.Sleep(retryTime) + _, err = c.GetWithQueryParams(endpoint, obj, params, true) + if _, ok := err.(*url.Error); ok { + continue + } else { + // We either succeeded or encountered a non connection error + break + } + } + } + return err +} + +func (c *httpClient) GetWithQueryParams(endpoint string, obj interface{}, params map[string]string, + decode bool) ([]byte, error) { + return c.GetWithOptions(endpoint, obj, params, decode, nil) +} + +func (c *httpClient) GetWithOptions(endpoint string, obj interface{}, params map[string]string, + decode bool, file io.Writer) ([]byte, error) { + + req, err := c.newRequest(http.MethodGet, endpoint) + if err != nil { + return nil, err + } + + if params != nil { + query := req.url.Query() + for k, v := range params { + query.Add(k, v) + } + req.params = query + } + + resp, err := checkSuccessful(c.doRequest(req)) + if err != nil { + return nil, err + } + defer safeRespClose(resp) + + if obj != nil { + if err := decodeJSONBody(resp, &obj); err != nil { + if err == io.EOF { + return nil, nil + } + return nil, err + } + } else if !decode { + if file != nil { + _, err := io.Copy(file, resp.Body) + if err != nil { + return nil, err + } + } else { + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + return body, err + } + } + + return nil, err +} + +func (c *httpClient) useragent() string { + return "Pulsar-httpClient-Go-v2" +} + +type httpRequest struct { + method string + contentType string + url *url.URL + params url.Values + + obj interface{} + body io.Reader +} + +func (r *httpRequest) toHTTP() (*http.Request, error) { + r.url.RawQuery = r.params.Encode() + + // add a httpRequest body if there is one + if r.body == nil && r.obj != nil { + body, err := encodeJSONBody(r.obj) + if err != nil { + return nil, err + } + r.body = body + } + + req, err := http.NewRequest(r.method, r.url.RequestURI(), r.body) + if err != nil { + return nil, err + } + + req.URL.Host = r.url.Host + req.URL.Scheme = r.url.Scheme + req.Host = r.url.Host + return req, nil +} + +// respIsOk is used to validate a successful http status code +func respIsOk(resp *http.Response) bool { + return resp.StatusCode >= http.StatusOK && resp.StatusCode <= http.StatusNoContent +} + +// checkSuccessful checks for a valid response and parses an error +func checkSuccessful(resp *http.Response, err error) (*http.Response, error) { + if err != nil { + safeRespClose(resp) + return nil, err + } + + if !respIsOk(resp) { + defer safeRespClose(resp) + return nil, responseError(resp) + } + + return resp, nil +} + +func endpoint(parts ...string) string { + return path.Join(parts...) +} + +// encodeJSONBody is used to JSON encode a body +func encodeJSONBody(obj interface{}) (io.Reader, error) { + buf := bytes.NewBuffer(nil) + enc := json.NewEncoder(buf) + if err := enc.Encode(obj); err != nil { + return nil, err + } + return buf, nil +} + +// decodeJSONBody is used to JSON decode a body +func decodeJSONBody(resp *http.Response, out interface{}) error { + if resp.ContentLength == 0 { + return nil + } + dec := json.NewDecoder(resp.Body) + return dec.Decode(out) +} + +// safeRespClose is used to close a response body +func safeRespClose(resp *http.Response) { + if resp != nil { + // ignore error since it is closing a response body + _ = resp.Body.Close() + } +} + +// responseError is used to parse a response into a client error +func responseError(resp *http.Response) error { + var e error + body, err := io.ReadAll(resp.Body) + reason := "" + code := resp.StatusCode + if err != nil { + reason = err.Error() + return errors.Errorf("Code: %d, Reason: %s", code, reason) + } + + err = json.Unmarshal(body, &e) + if err != nil { + reason = string(body) + } + + if reason == "" { + reason = "Unknown error" + } + + return errors.Errorf("Code: %d, Reason: %s", code, reason) +} + +func getDefaultTransport(tlsConfig *TLSOptions) (http.RoundTripper, error) { + transport := http.DefaultTransport.(*http.Transport) + if tlsConfig != nil { + cfg := &tls.Config{ + InsecureSkipVerify: tlsConfig.AllowInsecureConnection, + } + if len(tlsConfig.TrustCertsFilePath) > 0 { + rootCA, err := os.ReadFile(tlsConfig.TrustCertsFilePath) + if err != nil { + return nil, err + } + cfg.RootCAs = x509.NewCertPool() + cfg.RootCAs.AppendCertsFromPEM(rootCA) + } + + if tlsConfig.CertFile != "" && tlsConfig.KeyFile != "" { + cert, err := tls.LoadX509KeyPair(tlsConfig.CertFile, tlsConfig.KeyFile) + if err != nil { + return nil, errors.New(err.Error()) + } + cfg.Certificates = []tls.Certificate{cert} + } + transport.TLSClientConfig = cfg + } + transport.MaxIdleConnsPerHost = 10 + return transport, nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/key_based_batch_builder.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/key_based_batch_builder.go new file mode 100644 index 00000000..334e6746 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/key_based_batch_builder.go @@ -0,0 +1,251 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "encoding/base64" + "sort" + "sync" + "time" + + "github.com/apache/pulsar-client-go/pulsar/internal/compression" + "github.com/apache/pulsar-client-go/pulsar/internal/crypto" + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "github.com/apache/pulsar-client-go/pulsar/log" +) + +/** + * Key based batch message container + * + * incoming single messages: + * (k1, v1), (k2, v1), (k3, v1), (k1, v2), (k2, v2), (k3, v2), (k1, v3), (k2, v3), (k3, v3) + * + * batched into multiple batch messages: + * [(k1, v1), (k1, v2), (k1, v3)], [(k2, v1), (k2, v2), (k2, v3)], [(k3, v1), (k3, v2), (k3, v3)] + */ + +// keyBasedBatches is a simple concurrent-safe map for the batchContainer type +type keyBasedBatches struct { + containers map[string]*batchContainer + l *sync.RWMutex +} + +// keyBasedBatchContainer wraps the objects needed to key based batch. +// keyBasedBatchContainer implement BatchBuilder as a multiple batches +// container. +type keyBasedBatchContainer struct { + batches keyBasedBatches + batchContainer + compressionType pb.CompressionType + level compression.Level +} + +// newKeyBasedBatches init a keyBasedBatches +func newKeyBasedBatches() keyBasedBatches { + return keyBasedBatches{ + containers: map[string]*batchContainer{}, + l: &sync.RWMutex{}, + } +} + +func (h *keyBasedBatches) Add(key string, val *batchContainer) { + h.l.Lock() + defer h.l.Unlock() + h.containers[key] = val +} + +func (h *keyBasedBatches) Del(key string) { + h.l.Lock() + defer h.l.Unlock() + delete(h.containers, key) +} + +func (h *keyBasedBatches) Val(key string) *batchContainer { + h.l.RLock() + defer h.l.RUnlock() + return h.containers[key] +} + +// NewKeyBasedBatchBuilder init batch builder and return BatchBuilder +// pointer. Build a new key based batch message container. +func NewKeyBasedBatchBuilder( + maxMessages uint, maxBatchSize uint, maxMessageSize uint32, producerName string, producerID uint64, + compressionType pb.CompressionType, level compression.Level, + bufferPool BuffersPool, logger log.Logger, encryptor crypto.Encryptor, +) (BatchBuilder, error) { + + bb := &keyBasedBatchContainer{ + batches: newKeyBasedBatches(), + batchContainer: newBatchContainer( + maxMessages, maxBatchSize, maxMessageSize, producerName, producerID, + compressionType, level, bufferPool, logger, encryptor, + ), + compressionType: compressionType, + level: level, + } + + if compressionType != pb.CompressionType_NONE { + bb.msgMetadata.Compression = &compressionType + } + + return bb, nil +} + +// IsFull checks if the size in the current batch meets or exceeds the maximum size allowed by the batch +func (bc *keyBasedBatchContainer) IsFull() bool { + return bc.numMessages >= bc.maxMessages || bc.buffer.ReadableBytes() >= uint32(bc.maxBatchSize) +} + +func (bc *keyBasedBatchContainer) IsMultiBatches() bool { + return true +} + +// hasSpace should return true if and only if the batch container can accommodate another message of length payload. +func (bc *keyBasedBatchContainer) hasSpace(payload []byte) bool { + if bc.numMessages == 0 { + // allow to add at least one message + // and a single max message size is checked in the producer partition, therefore no need to validate batch size + return true + } + msgSize := uint32(len(payload)) + return bc.numMessages+1 <= bc.maxMessages && bc.buffer.ReadableBytes()+msgSize <= uint32(bc.maxBatchSize) +} + +// Add will add single message to key-based batch with message key. +func (bc *keyBasedBatchContainer) Add( + metadata *pb.SingleMessageMetadata, sequenceIDGenerator *uint64, + payload []byte, + callback interface{}, replicateTo []string, deliverAt time.Time, + schemaVersion []byte, multiSchemaEnabled bool, +) bool { + if replicateTo != nil && bc.numMessages != 0 { + // If the current batch is not empty and we're trying to set the replication clusters, + // then we need to force the current batch to flush and send the message individually + return false + } else if bc.msgMetadata.ReplicateTo != nil { + // There's already a message with cluster replication list. need to flush before next + // message can be sent + return false + } else if !bc.hasSpace(payload) { + // The current batch is full. Producer has to call Flush() to + return false + } + + var msgKey = getMessageKey(metadata) + batchPart := bc.batches.Val(msgKey) + if batchPart == nil { + // create batchContainer for new key + t := newBatchContainer( + bc.maxMessages, bc.maxBatchSize, bc.maxMessageSize, bc.producerName, bc.producerID, + bc.compressionType, bc.level, bc.buffersPool, bc.log, bc.encryptor, + ) + batchPart = &t + bc.batches.Add(msgKey, &t) + } + + // add message to batch container + add := batchPart.Add( + metadata, sequenceIDGenerator, payload, callback, replicateTo, + deliverAt, + schemaVersion, multiSchemaEnabled, + ) + if !add { + return false + } + addSingleMessageToBatch(bc.buffer, metadata, payload) + + bc.numMessages++ + bc.callbacks = append(bc.callbacks, callback) + return true +} + +func (bc *keyBasedBatchContainer) reset() { + bc.batches.l.RLock() + defer bc.batches.l.RUnlock() + for _, container := range bc.batches.containers { + container.reset() + } + bc.numMessages = 0 + bc.buffer.Clear() + bc.callbacks = []interface{}{} + bc.msgMetadata.ReplicateTo = nil + bc.msgMetadata.DeliverAtTime = nil + bc.batches.containers = map[string]*batchContainer{} +} + +// Flush all the messages buffered in multiple batches and wait until all +// messages have been successfully persisted. +func (bc *keyBasedBatchContainer) FlushBatches() ( + batchesData []Buffer, sequenceIDs []uint64, callbacks [][]interface{}, errors []error, +) { + if bc.numMessages == 0 { + // No-Op for empty batch + return nil, nil, nil, nil + } + + bc.log.Debug("keyBasedBatchContainer flush: messages: ", bc.numMessages) + var batchesLen = len(bc.batches.containers) + var idx = 0 + sortedKeys := make([]string, 0, batchesLen) + + batchesData = make([]Buffer, batchesLen) + sequenceIDs = make([]uint64, batchesLen) + callbacks = make([][]interface{}, batchesLen) + errors = make([]error, batchesLen) + + bc.batches.l.RLock() + defer bc.batches.l.RUnlock() + for k := range bc.batches.containers { + sortedKeys = append(sortedKeys, k) + } + sort.Strings(sortedKeys) + for _, k := range sortedKeys { + container := bc.batches.containers[k] + b, s, c, err := container.Flush() + if b != nil { + batchesData[idx] = b + sequenceIDs[idx] = s + callbacks[idx] = c + errors[idx] = err + } + idx++ + } + + bc.reset() + return batchesData, sequenceIDs, callbacks, errors +} + +func (bc *keyBasedBatchContainer) Flush() ( + batchData Buffer, sequenceID uint64, callbacks []interface{}, err error, +) { + panic("multi batches container not support Flush(), please use FlushBatches() instead") +} + +func (bc *keyBasedBatchContainer) Close() error { + return bc.compressionProvider.Close() +} + +// getMessageKey extracts message key from message metadata. +// If the OrderingKey exists, the base64-encoded string is returned, +// otherwise the PartitionKey is returned. +func getMessageKey(metadata *pb.SingleMessageMetadata) string { + if k := metadata.GetOrderingKey(); k != nil { + return base64.StdEncoding.EncodeToString(k) + } + return metadata.GetPartitionKey() +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/lookup_service.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/lookup_service.go new file mode 100644 index 00000000..e30bec1d --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/lookup_service.go @@ -0,0 +1,399 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "errors" + "fmt" + "net/url" + + "google.golang.org/protobuf/proto" + + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "github.com/apache/pulsar-client-go/pulsar/log" +) + +// LookupResult encapsulates a struct for lookup a request, containing two parts: LogicalAddr, PhysicalAddr. +type LookupResult struct { + LogicalAddr *url.URL + PhysicalAddr *url.URL +} + +// GetTopicsOfNamespaceMode for CommandGetTopicsOfNamespace_Mode +type GetTopicsOfNamespaceMode string + +const ( + Persistent GetTopicsOfNamespaceMode = "PERSISTENT" + NonPersistent = "NON_PERSISTENT" + All = "ALL" +) + +// PartitionedTopicMetadata encapsulates a struct for metadata of a partitioned topic +type PartitionedTopicMetadata struct { + Partitions int `json:"partitions"` // Number of partitions for the topic +} + +// LookupService is a interface of lookup service. +type LookupService interface { + // Lookup perform a lookup for the given topic, confirm the location of the broker + // where the topic is located, and return the LookupResult. + Lookup(topic string) (*LookupResult, error) + + // GetPartitionedTopicMetadata perform a CommandPartitionedTopicMetadata request for + // the given topic, returns the CommandPartitionedTopicMetadataResponse as the result. + GetPartitionedTopicMetadata(topic string) (*PartitionedTopicMetadata, error) + + // GetTopicsOfNamespace returns all the topics name for a given namespace. + GetTopicsOfNamespace(namespace string, mode GetTopicsOfNamespaceMode) ([]string, error) + + // GetSchema returns schema for a given version. + GetSchema(topic string, schemaVersion []byte) (schema *pb.Schema, err error) + + // Closable Allow Lookup Service's internal client to be able to closed + Closable +} + +type lookupService struct { + rpcClient RPCClient + serviceNameResolver ServiceNameResolver + tlsEnabled bool + listenerName string + log log.Logger + metrics *Metrics +} + +// NewLookupService init a lookup service struct and return an object of LookupService. +func NewLookupService(rpcClient RPCClient, serviceURL *url.URL, serviceNameResolver ServiceNameResolver, + tlsEnabled bool, listenerName string, logger log.Logger, metrics *Metrics) LookupService { + return &lookupService{ + rpcClient: rpcClient, + serviceNameResolver: serviceNameResolver, + tlsEnabled: tlsEnabled, + log: logger.SubLogger(log.Fields{"serviceURL": serviceURL}), + metrics: metrics, + listenerName: listenerName, + } +} + +func (ls *lookupService) GetSchema(topic string, schemaVersion []byte) (schema *pb.Schema, err error) { + id := ls.rpcClient.NewRequestID() + req := &pb.CommandGetSchema{ + RequestId: proto.Uint64(id), + Topic: proto.String(topic), + SchemaVersion: schemaVersion, + } + res, err := ls.rpcClient.RequestToAnyBroker(id, pb.BaseCommand_GET_SCHEMA, req) + if err != nil { + return nil, err + } + if res.Response.Error != nil { + return nil, errors.New(res.Response.GetError().String()) + } + return res.Response.GetSchemaResponse.Schema, nil +} + +func (ls *lookupService) getBrokerAddress(lr *pb.CommandLookupTopicResponse) (logicalAddress *url.URL, + physicalAddress *url.URL, err error) { + if ls.tlsEnabled { + logicalAddress, err = url.ParseRequestURI(lr.GetBrokerServiceUrlTls()) + } else { + logicalAddress, err = url.ParseRequestURI(lr.GetBrokerServiceUrl()) + } + + if err != nil { + return nil, nil, err + } + + var physicalAddr *url.URL + if lr.GetProxyThroughServiceUrl() { + physicalAddr, err = ls.serviceNameResolver.ResolveHost() + if err != nil { + return nil, nil, err + } + } else { + physicalAddr = logicalAddress + } + + return logicalAddress, physicalAddr, nil +} + +// Follow brokers redirect up to certain number of times +const lookupResultMaxRedirect = 20 + +func (ls *lookupService) Lookup(topic string) (*LookupResult, error) { + ls.metrics.LookupRequestsCount.Inc() + id := ls.rpcClient.NewRequestID() + res, err := ls.rpcClient.RequestToAnyBroker(id, pb.BaseCommand_LOOKUP, &pb.CommandLookupTopic{ + RequestId: &id, + Topic: &topic, + Authoritative: proto.Bool(false), + AdvertisedListenerName: proto.String(ls.listenerName), + }) + if err != nil { + return nil, err + } + ls.log.Debugf("Got topic{%s} lookup response: %+v", topic, res) + + for i := 0; i < lookupResultMaxRedirect; i++ { + lr := res.Response.LookupTopicResponse + switch *lr.Response { + + case pb.CommandLookupTopicResponse_Redirect: + logicalAddress, physicalAddr, err := ls.getBrokerAddress(lr) + if err != nil { + return nil, err + } + + ls.log.Debugf("Follow topic{%s} redirect to broker. %v / %v - Use proxy: %v", + topic, lr.BrokerServiceUrl, lr.BrokerServiceUrlTls, lr.ProxyThroughServiceUrl) + + id := ls.rpcClient.NewRequestID() + res, err = ls.rpcClient.Request(logicalAddress, physicalAddr, id, pb.BaseCommand_LOOKUP, &pb.CommandLookupTopic{ + RequestId: &id, + Topic: &topic, + Authoritative: lr.Authoritative, + AdvertisedListenerName: proto.String(ls.listenerName), + }) + if err != nil { + return nil, err + } + + // Process the response at the top of the loop + continue + + case pb.CommandLookupTopicResponse_Connect: + ls.log.Debugf("Successfully looked up topic{%s} on broker. %s / %s - Use proxy: %t", + topic, lr.GetBrokerServiceUrl(), lr.GetBrokerServiceUrlTls(), lr.GetProxyThroughServiceUrl()) + + logicalAddress, physicalAddress, err := ls.getBrokerAddress(lr) + if err != nil { + return nil, err + } + + return &LookupResult{ + LogicalAddr: logicalAddress, + PhysicalAddr: physicalAddress, + }, nil + + case pb.CommandLookupTopicResponse_Failed: + ls.log.WithFields(log.Fields{ + "topic": topic, + "error": lr.GetError(), + "message": lr.GetMessage(), + }).Warn("Failed to lookup topic") + return nil, errors.New(lr.GetError().String()) + } + } + + return nil, errors.New("exceeded max number of redirection during topic lookup") +} + +func (ls *lookupService) GetPartitionedTopicMetadata(topic string) (*PartitionedTopicMetadata, + error) { + ls.metrics.PartitionedTopicMetadataRequestsCount.Inc() + topicName, err := ParseTopicName(topic) + if err != nil { + return nil, err + } + + id := ls.rpcClient.NewRequestID() + res, err := ls.rpcClient.RequestToAnyBroker(id, pb.BaseCommand_PARTITIONED_METADATA, + &pb.CommandPartitionedTopicMetadata{ + RequestId: &id, + Topic: &topicName.Name, + }) + if err != nil { + return nil, err + } + ls.log.Debugf("Got topic{%s} partitioned metadata response: %+v", topic, res) + + var partitionedTopicMetadata PartitionedTopicMetadata + + if res.Response.Error != nil { + return nil, errors.New(res.Response.GetError().String()) + } + + if res.Response.PartitionMetadataResponse != nil { + if res.Response.PartitionMetadataResponse.Error != nil { + return nil, errors.New(res.Response.PartitionMetadataResponse.GetError().String()) + } + + partitionedTopicMetadata.Partitions = int(res.Response.PartitionMetadataResponse.GetPartitions()) + } else { + return nil, fmt.Errorf("no partitioned metadata for topic{%s} in lookup response", topic) + } + + return &partitionedTopicMetadata, nil +} + +func (ls *lookupService) GetTopicsOfNamespace(namespace string, mode GetTopicsOfNamespaceMode) ([]string, error) { + id := ls.rpcClient.NewRequestID() + pbMode := pb.CommandGetTopicsOfNamespace_Mode(pb.CommandGetTopicsOfNamespace_Mode_value[string(mode)]) + req := &pb.CommandGetTopicsOfNamespace{ + RequestId: proto.Uint64(id), + Namespace: proto.String(namespace), + Mode: &pbMode, + } + res, err := ls.rpcClient.RequestToAnyBroker(id, pb.BaseCommand_GET_TOPICS_OF_NAMESPACE, req) + if err != nil { + return nil, err + } + if res.Response.Error != nil { + return []string{}, errors.New(res.Response.GetError().String()) + } + + return res.Response.GetTopicsOfNamespaceResponse.GetTopics(), nil +} + +func (ls *lookupService) Close() {} + +const HTTPLookupServiceBasePathV1 string = "/lookup/v2/destination/" +const HTTPLookupServiceBasePathV2 string = "/lookup/v2/topic/" +const HTTPAdminServiceV1Format string = "/admin/%s/partitions" +const HTTPAdminServiceV2Format string = "/admin/v2/%s/partitions" +const HTTPTopicUnderNamespaceV1 string = "/admin/namespaces/%s/destinations?mode=%s" +const HTTPTopicUnderNamespaceV2 string = "/admin/v2/namespaces/%s/topics?mode=%s" + +type httpLookupData struct { + BrokerURL string `json:"brokerUrl"` + BrokerURLTLS string `json:"brokerUrlTls"` + HTTPURL string `json:"httpUrl"` + HTTPURLTLS string `json:"httpUrlTls"` +} + +type httpLookupService struct { + httpClient HTTPClient + serviceNameResolver ServiceNameResolver + tlsEnabled bool + log log.Logger + metrics *Metrics +} + +func (h *httpLookupService) getBrokerAddress(ld *httpLookupData) (logicalAddress *url.URL, + physicalAddress *url.URL, err error) { + if h.tlsEnabled { + logicalAddress, err = url.ParseRequestURI(ld.BrokerURLTLS) + } else { + logicalAddress, err = url.ParseRequestURI(ld.BrokerURL) + } + + if err != nil { + return nil, nil, err + } + + return logicalAddress, logicalAddress, nil +} + +func (h *httpLookupService) Lookup(topic string) (*LookupResult, error) { + topicName, err := ParseTopicName(topic) + if err != nil { + return nil, err + } + + basePath := HTTPLookupServiceBasePathV2 + if !IsV2TopicName(topicName) { + basePath = HTTPLookupServiceBasePathV1 + } + + lookupData := &httpLookupData{} + err = h.httpClient.Get(basePath+GetTopicRestPath(topicName), lookupData, nil) + if err != nil { + return nil, err + } + + h.log.Debugf("Successfully looked up topic{%s} on http broker. %+v", + topic, lookupData) + + logicalAddress, physicalAddress, err := h.getBrokerAddress(lookupData) + if err != nil { + return nil, err + } + + return &LookupResult{ + LogicalAddr: logicalAddress, + PhysicalAddr: physicalAddress, + }, nil + +} + +func (h *httpLookupService) GetPartitionedTopicMetadata(topic string) (*PartitionedTopicMetadata, + error) { + topicName, err := ParseTopicName(topic) + if err != nil { + return nil, err + } + + format := HTTPAdminServiceV2Format + if !IsV2TopicName(topicName) { + format = HTTPAdminServiceV1Format + } + + path := fmt.Sprintf(format, GetTopicRestPath(topicName)) + + tMetadata := &PartitionedTopicMetadata{} + + err = h.httpClient.Get(path, tMetadata, map[string]string{"checkAllowAutoCreation": "true"}) + if err != nil { + return nil, err + } + + h.log.Debugf("Got topic{%s} partitioned metadata response: %+v", topic, tMetadata) + + return tMetadata, nil +} + +func (h *httpLookupService) GetTopicsOfNamespace(namespace string, mode GetTopicsOfNamespaceMode) ([]string, error) { + + format := HTTPTopicUnderNamespaceV2 + if !IsV2Namespace(namespace) { + format = HTTPTopicUnderNamespaceV1 + } + + path := fmt.Sprintf(format, namespace, string(mode)) + + topics := []string{} + + err := h.httpClient.Get(path, &topics, nil) + if err != nil { + return nil, err + } + + h.log.Debugf("Got namespace{%s} mode{%s} topics response: %+v", namespace, mode, topics) + + return topics, nil +} + +func (h *httpLookupService) GetSchema(topic string, schemaVersion []byte) (schema *pb.Schema, err error) { + return nil, errors.New("GetSchema is not supported by httpLookupService") +} +func (h *httpLookupService) Close() { + h.httpClient.Close() +} + +// NewHTTPLookupService init a http based lookup service struct and return an object of LookupService. +func NewHTTPLookupService(httpClient HTTPClient, serviceURL *url.URL, serviceNameResolver ServiceNameResolver, + tlsEnabled bool, logger log.Logger, metrics *Metrics) LookupService { + + return &httpLookupService{ + httpClient: httpClient, + serviceNameResolver: serviceNameResolver, + tlsEnabled: tlsEnabled, + log: logger.SubLogger(log.Fields{"serviceURL": serviceURL}), + metrics: metrics, + } +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/memory_limit_controller.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/memory_limit_controller.go new file mode 100644 index 00000000..5ead9f5b --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/memory_limit_controller.go @@ -0,0 +1,151 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "context" + "sync" + "sync/atomic" +) + +type MemoryLimitController interface { + ReserveMemory(ctx context.Context, size int64) bool + TryReserveMemory(size int64) bool + ForceReserveMemory(size int64) + ReleaseMemory(size int64) + CurrentUsage() int64 + CurrentUsagePercent() float64 + IsMemoryLimited() bool + RegisterTrigger(trigger func()) +} + +type memoryLimitController struct { + limit int64 + chCond *chCond + currentUsage int64 + + triggers []*thresholdTrigger + // valid range is (0, 1.0) + triggerThreshold float64 +} + +type thresholdTrigger struct { + triggerFunc func() + triggerRunning int32 +} + +func (t *thresholdTrigger) canTryRunning() bool { + return atomic.CompareAndSwapInt32(&t.triggerRunning, 0, 1) +} + +func (t *thresholdTrigger) setRunning(isRunning bool) { + if isRunning { + atomic.StoreInt32(&t.triggerRunning, 1) + } else { + atomic.StoreInt32(&t.triggerRunning, 0) + } +} + +// NewMemoryLimitController threshold valid range is (0, 1.0) +func NewMemoryLimitController(limit int64, threshold float64) MemoryLimitController { + mlc := &memoryLimitController{ + limit: limit, + chCond: newCond(&sync.Mutex{}), + triggerThreshold: threshold, + } + return mlc +} + +func (m *memoryLimitController) ReserveMemory(ctx context.Context, size int64) bool { + if !m.TryReserveMemory(size) { + m.chCond.L.Lock() + defer m.chCond.L.Unlock() + + for !m.TryReserveMemory(size) { + if !m.chCond.waitWithContext(ctx) { + return false + } + } + } + return true +} + +func (m *memoryLimitController) TryReserveMemory(size int64) bool { + for { + current := atomic.LoadInt64(&m.currentUsage) + newUsage := current + size + + // This condition means we allowed one request to go over the limit. + if m.IsMemoryLimited() && current > m.limit { + return false + } + + if atomic.CompareAndSwapInt64(&m.currentUsage, current, newUsage) { + m.checkTrigger(current, newUsage) + return true + } + } +} + +func (m *memoryLimitController) ForceReserveMemory(size int64) { + nextUsage := atomic.AddInt64(&m.currentUsage, size) + prevUsage := nextUsage - size + m.checkTrigger(prevUsage, nextUsage) +} + +func (m *memoryLimitController) ReleaseMemory(size int64) { + newUsage := atomic.AddInt64(&m.currentUsage, -size) + if newUsage+size > m.limit && newUsage <= m.limit { + m.chCond.broadcast() + } +} + +func (m *memoryLimitController) CurrentUsage() int64 { + return atomic.LoadInt64(&m.currentUsage) +} + +func (m *memoryLimitController) CurrentUsagePercent() float64 { + return float64(atomic.LoadInt64(&m.currentUsage)) / float64(m.limit) +} + +func (m *memoryLimitController) IsMemoryLimited() bool { + return m.limit > 0 +} + +func (m *memoryLimitController) RegisterTrigger(trigger func()) { + m.chCond.L.Lock() + defer m.chCond.L.Unlock() + m.triggers = append(m.triggers, &thresholdTrigger{ + triggerFunc: trigger, + }) +} + +func (m *memoryLimitController) checkTrigger(prevUsage int64, nextUsage int64) { + nextUsagePercent := float64(nextUsage) / float64(m.limit) + prevUsagePercent := float64(prevUsage) / float64(m.limit) + if nextUsagePercent >= m.triggerThreshold && prevUsagePercent < m.triggerThreshold { + for _, trigger := range m.triggers { + if trigger.canTryRunning() { + go func(trigger *thresholdTrigger) { + trigger.triggerFunc() + trigger.setRunning(false) + }(trigger) + } + } + } +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/metrics.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/metrics.go new file mode 100644 index 00000000..e9bc8152 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/metrics.go @@ -0,0 +1,605 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +type Metrics struct { + metricsLevel int + messagesPublished *prometheus.CounterVec + bytesPublished *prometheus.CounterVec + messagesPending *prometheus.GaugeVec + bytesPending *prometheus.GaugeVec + publishErrors *prometheus.CounterVec + publishLatency *prometheus.HistogramVec + publishRPCLatency *prometheus.HistogramVec + + messagesReceived *prometheus.CounterVec + bytesReceived *prometheus.CounterVec + prefetchedMessages *prometheus.GaugeVec + prefetchedBytes *prometheus.GaugeVec + acksCounter *prometheus.CounterVec + nacksCounter *prometheus.CounterVec + dlqCounter *prometheus.CounterVec + processingTime *prometheus.HistogramVec + + producersOpened *prometheus.CounterVec + producersClosed *prometheus.CounterVec + producersReconnectFailure *prometheus.CounterVec + producersReconnectMaxRetry *prometheus.CounterVec + producersPartitions *prometheus.GaugeVec + consumersOpened *prometheus.CounterVec + consumersClosed *prometheus.CounterVec + consumersReconnectFailure *prometheus.CounterVec + consumersReconnectMaxRetry *prometheus.CounterVec + consumersPartitions *prometheus.GaugeVec + readersOpened *prometheus.CounterVec + readersClosed *prometheus.CounterVec + + // Metrics that are not labeled with specificity are immediately available + ConnectionsOpened prometheus.Counter + ConnectionsClosed prometheus.Counter + ConnectionsEstablishmentErrors prometheus.Counter + ConnectionsHandshakeErrors prometheus.Counter + LookupRequestsCount prometheus.Counter + PartitionedTopicMetadataRequestsCount prometheus.Counter + RPCRequestCount prometheus.Counter +} + +type LeveledMetrics struct { + MessagesPublished prometheus.Counter + BytesPublished prometheus.Counter + MessagesPending prometheus.Gauge + BytesPending prometheus.Gauge + PublishErrorsTimeout prometheus.Counter + PublishErrorsMsgTooLarge prometheus.Counter + PublishLatency prometheus.Observer + PublishRPCLatency prometheus.Observer + + MessagesReceived prometheus.Counter + BytesReceived prometheus.Counter + PrefetchedMessages prometheus.Gauge + PrefetchedBytes prometheus.Gauge + AcksCounter prometheus.Counter + NacksCounter prometheus.Counter + DlqCounter prometheus.Counter + ProcessingTime prometheus.Observer + + ProducersOpened prometheus.Counter + ProducersClosed prometheus.Counter + ProducersReconnectFailure prometheus.Counter + ProducersReconnectMaxRetry prometheus.Counter + ProducersPartitions prometheus.Gauge + ConsumersOpened prometheus.Counter + ConsumersClosed prometheus.Counter + ConsumersReconnectFailure prometheus.Counter + ConsumersReconnectMaxRetry prometheus.Counter + ConsumersPartitions prometheus.Gauge + ReadersOpened prometheus.Counter + ReadersClosed prometheus.Counter +} + +// NewMetricsProvider returns metrics registered to registerer. +func NewMetricsProvider(metricsCardinality int, userDefinedLabels map[string]string, + registerer prometheus.Registerer) *Metrics { + constLabels := map[string]string{ + "client": "go", + } + for k, v := range userDefinedLabels { + constLabels[k] = v + } + var metricsLevelLabels []string + + // note: ints here mirror MetricsCardinality in client.go to avoid import cycle + switch metricsCardinality { + case 1: //MetricsCardinalityNone + metricsLevelLabels = []string{} + case 2: //MetricsCardinalityTenant + metricsLevelLabels = []string{"pulsar_tenant"} + case 3: //MetricsCardinalityNamespace + metricsLevelLabels = []string{"pulsar_tenant", "pulsar_namespace"} + case 4: //MetricsCardinalityTopic + metricsLevelLabels = []string{"pulsar_tenant", "pulsar_namespace", "topic"} + default: //Anything else is namespace + metricsLevelLabels = []string{"pulsar_tenant", "pulsar_namespace"} + } + + metrics := &Metrics{ + metricsLevel: metricsCardinality, + messagesPublished: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_messages_published", + Help: "Counter of messages published by the client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + bytesPublished: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_bytes_published", + Help: "Counter of messages published by the client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + messagesPending: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "pulsar_client_producer_pending_messages", + Help: "Counter of messages pending to be published by the client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + bytesPending: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "pulsar_client_producer_pending_bytes", + Help: "Counter of bytes pending to be published by the client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + publishErrors: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_producer_errors", + Help: "Counter of publish errors", + ConstLabels: constLabels, + }, append(metricsLevelLabels, "error")), + + publishLatency: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "pulsar_client_producer_latency_seconds", + Help: "Publish latency experienced by the client", + ConstLabels: constLabels, + Buckets: []float64{.0005, .001, .005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}, + }, metricsLevelLabels), + + publishRPCLatency: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "pulsar_client_producer_rpc_latency_seconds", + Help: "Publish RPC latency experienced internally by the client when sending data to receiving an ack", + ConstLabels: constLabels, + Buckets: []float64{.0005, .001, .005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}, + }, metricsLevelLabels), + + producersOpened: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_producers_opened", + Help: "Counter of producers created by the client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + producersClosed: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_producers_closed", + Help: "Counter of producers closed by the client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + producersPartitions: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "pulsar_client_producers_partitions_active", + Help: "Counter of individual partitions the producers are currently active", + ConstLabels: constLabels, + }, metricsLevelLabels), + + producersReconnectFailure: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_producers_reconnect_failure", + Help: "Counter of reconnect failure of producers", + ConstLabels: constLabels, + }, metricsLevelLabels), + + producersReconnectMaxRetry: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_producers_reconnect_max_retry", + Help: "Counter of producer reconnect max retry reached", + ConstLabels: constLabels, + }, metricsLevelLabels), + + consumersOpened: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_consumers_opened", + Help: "Counter of consumers created by the client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + consumersClosed: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_consumers_closed", + Help: "Counter of consumers closed by the client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + consumersReconnectFailure: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_consumers_reconnect_failure", + Help: "Counter of reconnect failure of consumers", + ConstLabels: constLabels, + }, metricsLevelLabels), + + consumersReconnectMaxRetry: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_consumers_reconnect_max_retry", + Help: "Counter of consumer reconnect max retry reached", + ConstLabels: constLabels, + }, metricsLevelLabels), + + consumersPartitions: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "pulsar_client_consumers_partitions_active", + Help: "Counter of individual partitions the consumers are currently active", + ConstLabels: constLabels, + }, metricsLevelLabels), + + messagesReceived: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_messages_received", + Help: "Counter of messages received by the client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + bytesReceived: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_bytes_received", + Help: "Counter of bytes received by the client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + prefetchedMessages: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "pulsar_client_consumer_prefetched_messages", + Help: "Number of messages currently sitting in the consumer pre-fetch queue", + ConstLabels: constLabels, + }, metricsLevelLabels), + + prefetchedBytes: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "pulsar_client_consumer_prefetched_bytes", + Help: "Total number of bytes currently sitting in the consumer pre-fetch queue", + ConstLabels: constLabels, + }, metricsLevelLabels), + + acksCounter: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_consumer_acks", + Help: "Counter of messages acked by client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + nacksCounter: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_consumer_nacks", + Help: "Counter of messages nacked by client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + dlqCounter: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_consumer_dlq_messages", + Help: "Counter of messages sent to Dead letter queue", + ConstLabels: constLabels, + }, metricsLevelLabels), + + processingTime: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "pulsar_client_consumer_processing_time_seconds", + Help: "Time it takes for application to process messages", + Buckets: []float64{.0005, .001, .005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}, + ConstLabels: constLabels, + }, metricsLevelLabels), + + readersOpened: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_readers_opened", + Help: "Counter of readers created by the client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + readersClosed: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pulsar_client_readers_closed", + Help: "Counter of readers closed by the client", + ConstLabels: constLabels, + }, metricsLevelLabels), + + ConnectionsOpened: prometheus.NewCounter(prometheus.CounterOpts{ + Name: "pulsar_client_connections_opened", + Help: "Counter of connections created by the client", + ConstLabels: constLabels, + }), + + ConnectionsClosed: prometheus.NewCounter(prometheus.CounterOpts{ + Name: "pulsar_client_connections_closed", + Help: "Counter of connections closed by the client", + ConstLabels: constLabels, + }), + + ConnectionsEstablishmentErrors: prometheus.NewCounter(prometheus.CounterOpts{ + Name: "pulsar_client_connections_establishment_errors", + Help: "Counter of errors in connections establishment", + ConstLabels: constLabels, + }), + + ConnectionsHandshakeErrors: prometheus.NewCounter(prometheus.CounterOpts{ + Name: "pulsar_client_connections_handshake_errors", + Help: "Counter of errors in connections handshake (eg: authz)", + ConstLabels: constLabels, + }), + + LookupRequestsCount: prometheus.NewCounter(prometheus.CounterOpts{ + Name: "pulsar_client_lookup_count", + Help: "Counter of lookup requests made by the client", + ConstLabels: constLabels, + }), + + PartitionedTopicMetadataRequestsCount: prometheus.NewCounter(prometheus.CounterOpts{ + Name: "pulsar_client_partitioned_topic_metadata_count", + Help: "Counter of partitioned_topic_metadata requests made by the client", + ConstLabels: constLabels, + }), + + RPCRequestCount: prometheus.NewCounter(prometheus.CounterOpts{ + Name: "pulsar_client_rpc_count", + Help: "Counter of RPC requests made by the client", + ConstLabels: constLabels, + }), + } + + err := registerer.Register(metrics.messagesPublished) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.messagesPublished = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.bytesPublished) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.bytesPublished = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.messagesPending) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.messagesPending = are.ExistingCollector.(*prometheus.GaugeVec) + } + } + err = registerer.Register(metrics.bytesPending) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.bytesPending = are.ExistingCollector.(*prometheus.GaugeVec) + } + } + err = registerer.Register(metrics.publishErrors) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.publishErrors = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.publishLatency) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.publishLatency = are.ExistingCollector.(*prometheus.HistogramVec) + } + } + err = registerer.Register(metrics.publishRPCLatency) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.publishRPCLatency = are.ExistingCollector.(*prometheus.HistogramVec) + } + } + err = registerer.Register(metrics.messagesReceived) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.messagesReceived = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.bytesReceived) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.bytesReceived = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.prefetchedMessages) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.prefetchedMessages = are.ExistingCollector.(*prometheus.GaugeVec) + } + } + err = registerer.Register(metrics.prefetchedBytes) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.prefetchedBytes = are.ExistingCollector.(*prometheus.GaugeVec) + } + } + err = registerer.Register(metrics.acksCounter) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.acksCounter = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.nacksCounter) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.nacksCounter = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.dlqCounter) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.dlqCounter = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.processingTime) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.processingTime = are.ExistingCollector.(*prometheus.HistogramVec) + } + } + err = registerer.Register(metrics.producersOpened) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.producersOpened = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.producersClosed) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.producersClosed = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.producersReconnectFailure) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.producersReconnectFailure = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.producersReconnectMaxRetry) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.producersReconnectMaxRetry = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.producersPartitions) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.producersPartitions = are.ExistingCollector.(*prometheus.GaugeVec) + } + } + err = registerer.Register(metrics.consumersOpened) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.consumersOpened = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.consumersClosed) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.consumersClosed = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.consumersReconnectFailure) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.consumersReconnectFailure = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.consumersReconnectMaxRetry) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.consumersReconnectMaxRetry = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.consumersPartitions) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.consumersPartitions = are.ExistingCollector.(*prometheus.GaugeVec) + } + } + err = registerer.Register(metrics.readersOpened) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.readersOpened = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.readersClosed) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.readersClosed = are.ExistingCollector.(*prometheus.CounterVec) + } + } + err = registerer.Register(metrics.ConnectionsOpened) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.ConnectionsOpened = are.ExistingCollector.(prometheus.Counter) + } + } + err = registerer.Register(metrics.ConnectionsClosed) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.ConnectionsClosed = are.ExistingCollector.(prometheus.Counter) + } + } + err = registerer.Register(metrics.ConnectionsEstablishmentErrors) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.ConnectionsEstablishmentErrors = are.ExistingCollector.(prometheus.Counter) + } + } + err = registerer.Register(metrics.ConnectionsHandshakeErrors) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.ConnectionsHandshakeErrors = are.ExistingCollector.(prometheus.Counter) + } + } + err = registerer.Register(metrics.LookupRequestsCount) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.LookupRequestsCount = are.ExistingCollector.(prometheus.Counter) + } + } + err = registerer.Register(metrics.PartitionedTopicMetadataRequestsCount) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.PartitionedTopicMetadataRequestsCount = are.ExistingCollector.(prometheus.Counter) + } + } + err = registerer.Register(metrics.RPCRequestCount) + if err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + metrics.RPCRequestCount = are.ExistingCollector.(prometheus.Counter) + } + } + return metrics +} + +func (mp *Metrics) GetLeveledMetrics(t string) *LeveledMetrics { + labels := make(map[string]string, 3) + tn, err := ParseTopicName(t) + if err != nil { + return nil + } + topic := TopicNameWithoutPartitionPart(tn) + switch mp.metricsLevel { + case 4: + labels["topic"] = topic + fallthrough + case 3: + labels["pulsar_namespace"] = tn.Namespace + fallthrough + case 2: + labels["pulsar_tenant"] = tn.Tenant + } + + lm := &LeveledMetrics{ + MessagesPublished: mp.messagesPublished.With(labels), + BytesPublished: mp.bytesPublished.With(labels), + MessagesPending: mp.messagesPending.With(labels), + BytesPending: mp.bytesPending.With(labels), + PublishErrorsTimeout: mp.publishErrors.With(mergeMaps(labels, map[string]string{"error": "timeout"})), + PublishErrorsMsgTooLarge: mp.publishErrors.With(mergeMaps(labels, map[string]string{"error": "msg_too_large"})), + PublishLatency: mp.publishLatency.With(labels), + PublishRPCLatency: mp.publishRPCLatency.With(labels), + + MessagesReceived: mp.messagesReceived.With(labels), + BytesReceived: mp.bytesReceived.With(labels), + PrefetchedMessages: mp.prefetchedMessages.With(labels), + PrefetchedBytes: mp.prefetchedBytes.With(labels), + AcksCounter: mp.acksCounter.With(labels), + NacksCounter: mp.nacksCounter.With(labels), + DlqCounter: mp.dlqCounter.With(labels), + ProcessingTime: mp.processingTime.With(labels), + + ProducersOpened: mp.producersOpened.With(labels), + ProducersClosed: mp.producersClosed.With(labels), + ProducersReconnectFailure: mp.producersReconnectFailure.With(labels), + ProducersReconnectMaxRetry: mp.producersReconnectMaxRetry.With(labels), + ProducersPartitions: mp.producersPartitions.With(labels), + ConsumersOpened: mp.consumersOpened.With(labels), + ConsumersClosed: mp.consumersClosed.With(labels), + ConsumersReconnectFailure: mp.consumersReconnectFailure.With(labels), + ConsumersReconnectMaxRetry: mp.consumersReconnectMaxRetry.With(labels), + ConsumersPartitions: mp.consumersPartitions.With(labels), + ReadersOpened: mp.readersOpened.With(labels), + ReadersClosed: mp.readersClosed.With(labels), + } + + return lm +} + +func mergeMaps(a, b map[string]string) map[string]string { + res := make(map[string]string) + for k, v := range a { + res[k] = v + } + for k, v := range b { + res[k] = v + } + + return res +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/namespace_name.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/namespace_name.go new file mode 100644 index 00000000..5e9fee22 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/namespace_name.go @@ -0,0 +1,26 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import "strings" + +func IsV2Namespace(namespace string) bool { + parts := strings.Split(namespace, "/") + // Legacy namespace name that includes cluster name + return len(parts) == 2 +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto/PulsarApi.pb.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto/PulsarApi.pb.go new file mode 100644 index 00000000..c8e6ad9b --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto/PulsarApi.pb.go @@ -0,0 +1,10216 @@ +//* +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.21.9 +// source: PulsarApi.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CompressionType int32 + +const ( + CompressionType_NONE CompressionType = 0 + CompressionType_LZ4 CompressionType = 1 + CompressionType_ZLIB CompressionType = 2 + CompressionType_ZSTD CompressionType = 3 + CompressionType_SNAPPY CompressionType = 4 +) + +// Enum value maps for CompressionType. +var ( + CompressionType_name = map[int32]string{ + 0: "NONE", + 1: "LZ4", + 2: "ZLIB", + 3: "ZSTD", + 4: "SNAPPY", + } + CompressionType_value = map[string]int32{ + "NONE": 0, + "LZ4": 1, + "ZLIB": 2, + "ZSTD": 3, + "SNAPPY": 4, + } +) + +func (x CompressionType) Enum() *CompressionType { + p := new(CompressionType) + *p = x + return p +} + +func (x CompressionType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CompressionType) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[0].Descriptor() +} + +func (CompressionType) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[0] +} + +func (x CompressionType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *CompressionType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = CompressionType(num) + return nil +} + +// Deprecated: Use CompressionType.Descriptor instead. +func (CompressionType) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{0} +} + +type ProducerAccessMode int32 + +const ( + ProducerAccessMode_Shared ProducerAccessMode = 0 // By default multiple producers can publish on a topic + ProducerAccessMode_Exclusive ProducerAccessMode = 1 // Require exclusive access for producer. Fail immediately if there's already a producer connected. + ProducerAccessMode_WaitForExclusive ProducerAccessMode = 2 // Producer creation is pending until it can acquire exclusive access + ProducerAccessMode_ExclusiveWithFencing ProducerAccessMode = 3 // Require exclusive access for producer. Fence out old producer. +) + +// Enum value maps for ProducerAccessMode. +var ( + ProducerAccessMode_name = map[int32]string{ + 0: "Shared", + 1: "Exclusive", + 2: "WaitForExclusive", + 3: "ExclusiveWithFencing", + } + ProducerAccessMode_value = map[string]int32{ + "Shared": 0, + "Exclusive": 1, + "WaitForExclusive": 2, + "ExclusiveWithFencing": 3, + } +) + +func (x ProducerAccessMode) Enum() *ProducerAccessMode { + p := new(ProducerAccessMode) + *p = x + return p +} + +func (x ProducerAccessMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ProducerAccessMode) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[1].Descriptor() +} + +func (ProducerAccessMode) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[1] +} + +func (x ProducerAccessMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *ProducerAccessMode) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = ProducerAccessMode(num) + return nil +} + +// Deprecated: Use ProducerAccessMode.Descriptor instead. +func (ProducerAccessMode) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{1} +} + +type ServerError int32 + +const ( + ServerError_UnknownError ServerError = 0 + ServerError_MetadataError ServerError = 1 // Error with ZK/metadata + ServerError_PersistenceError ServerError = 2 // Error writing reading from BK + ServerError_AuthenticationError ServerError = 3 // Non valid authentication + ServerError_AuthorizationError ServerError = 4 // Not authorized to use resource + ServerError_ConsumerBusy ServerError = 5 // Unable to subscribe/unsubscribe because + // other consumers are connected + ServerError_ServiceNotReady ServerError = 6 // Any error that requires client retry operation with a fresh lookup + ServerError_ProducerBlockedQuotaExceededError ServerError = 7 // Unable to create producer because backlog quota exceeded + ServerError_ProducerBlockedQuotaExceededException ServerError = 8 // Exception while creating producer because quota exceeded + ServerError_ChecksumError ServerError = 9 // Error while verifying message checksum + ServerError_UnsupportedVersionError ServerError = 10 // Error when an older client/version doesn't support a required feature + ServerError_TopicNotFound ServerError = 11 // Topic not found + ServerError_SubscriptionNotFound ServerError = 12 // Subscription not found + ServerError_ConsumerNotFound ServerError = 13 // Consumer not found + ServerError_TooManyRequests ServerError = 14 // Error with too many simultaneously request + ServerError_TopicTerminatedError ServerError = 15 // The topic has been terminated + ServerError_ProducerBusy ServerError = 16 // Producer with same name is already connected + ServerError_InvalidTopicName ServerError = 17 // The topic name is not valid + ServerError_IncompatibleSchema ServerError = 18 // Specified schema was incompatible with topic schema + ServerError_ConsumerAssignError ServerError = 19 // Dispatcher assign consumer error + ServerError_TransactionCoordinatorNotFound ServerError = 20 // Transaction coordinator not found error + ServerError_InvalidTxnStatus ServerError = 21 // Invalid txn status error + ServerError_NotAllowedError ServerError = 22 // Not allowed error + ServerError_TransactionConflict ServerError = 23 // Ack with transaction conflict + ServerError_TransactionNotFound ServerError = 24 // Transaction not found + ServerError_ProducerFenced ServerError = 25 // When a producer asks and fail to get exclusive producer access, +) + +// Enum value maps for ServerError. +var ( + ServerError_name = map[int32]string{ + 0: "UnknownError", + 1: "MetadataError", + 2: "PersistenceError", + 3: "AuthenticationError", + 4: "AuthorizationError", + 5: "ConsumerBusy", + 6: "ServiceNotReady", + 7: "ProducerBlockedQuotaExceededError", + 8: "ProducerBlockedQuotaExceededException", + 9: "ChecksumError", + 10: "UnsupportedVersionError", + 11: "TopicNotFound", + 12: "SubscriptionNotFound", + 13: "ConsumerNotFound", + 14: "TooManyRequests", + 15: "TopicTerminatedError", + 16: "ProducerBusy", + 17: "InvalidTopicName", + 18: "IncompatibleSchema", + 19: "ConsumerAssignError", + 20: "TransactionCoordinatorNotFound", + 21: "InvalidTxnStatus", + 22: "NotAllowedError", + 23: "TransactionConflict", + 24: "TransactionNotFound", + 25: "ProducerFenced", + } + ServerError_value = map[string]int32{ + "UnknownError": 0, + "MetadataError": 1, + "PersistenceError": 2, + "AuthenticationError": 3, + "AuthorizationError": 4, + "ConsumerBusy": 5, + "ServiceNotReady": 6, + "ProducerBlockedQuotaExceededError": 7, + "ProducerBlockedQuotaExceededException": 8, + "ChecksumError": 9, + "UnsupportedVersionError": 10, + "TopicNotFound": 11, + "SubscriptionNotFound": 12, + "ConsumerNotFound": 13, + "TooManyRequests": 14, + "TopicTerminatedError": 15, + "ProducerBusy": 16, + "InvalidTopicName": 17, + "IncompatibleSchema": 18, + "ConsumerAssignError": 19, + "TransactionCoordinatorNotFound": 20, + "InvalidTxnStatus": 21, + "NotAllowedError": 22, + "TransactionConflict": 23, + "TransactionNotFound": 24, + "ProducerFenced": 25, + } +) + +func (x ServerError) Enum() *ServerError { + p := new(ServerError) + *p = x + return p +} + +func (x ServerError) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ServerError) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[2].Descriptor() +} + +func (ServerError) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[2] +} + +func (x ServerError) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *ServerError) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = ServerError(num) + return nil +} + +// Deprecated: Use ServerError.Descriptor instead. +func (ServerError) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{2} +} + +type AuthMethod int32 + +const ( + AuthMethod_AuthMethodNone AuthMethod = 0 + AuthMethod_AuthMethodYcaV1 AuthMethod = 1 + AuthMethod_AuthMethodAthens AuthMethod = 2 +) + +// Enum value maps for AuthMethod. +var ( + AuthMethod_name = map[int32]string{ + 0: "AuthMethodNone", + 1: "AuthMethodYcaV1", + 2: "AuthMethodAthens", + } + AuthMethod_value = map[string]int32{ + "AuthMethodNone": 0, + "AuthMethodYcaV1": 1, + "AuthMethodAthens": 2, + } +) + +func (x AuthMethod) Enum() *AuthMethod { + p := new(AuthMethod) + *p = x + return p +} + +func (x AuthMethod) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AuthMethod) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[3].Descriptor() +} + +func (AuthMethod) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[3] +} + +func (x AuthMethod) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *AuthMethod) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = AuthMethod(num) + return nil +} + +// Deprecated: Use AuthMethod.Descriptor instead. +func (AuthMethod) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{3} +} + +// Each protocol version identify new features that are +// incrementally added to the protocol +type ProtocolVersion int32 + +const ( + ProtocolVersion_v0 ProtocolVersion = 0 // Initial versioning + ProtocolVersion_v1 ProtocolVersion = 1 // Added application keep-alive + ProtocolVersion_v2 ProtocolVersion = 2 // Added RedeliverUnacknowledgedMessages Command + ProtocolVersion_v3 ProtocolVersion = 3 // Added compression with LZ4 and ZLib + ProtocolVersion_v4 ProtocolVersion = 4 // Added batch message support + ProtocolVersion_v5 ProtocolVersion = 5 // Added disconnect client w/o closing connection + ProtocolVersion_v6 ProtocolVersion = 6 // Added checksum computation for metadata + payload + ProtocolVersion_v7 ProtocolVersion = 7 // Added CommandLookupTopic - Binary Lookup + ProtocolVersion_v8 ProtocolVersion = 8 // Added CommandConsumerStats - Client fetches broker side consumer stats + ProtocolVersion_v9 ProtocolVersion = 9 // Added end of topic notification + ProtocolVersion_v10 ProtocolVersion = 10 // Added proxy to broker + ProtocolVersion_v11 ProtocolVersion = 11 // C++ consumers before this version are not correctly handling the checksum field + ProtocolVersion_v12 ProtocolVersion = 12 // Added get topic's last messageId from broker + // Added CommandActiveConsumerChange + // Added CommandGetTopicsOfNamespace + ProtocolVersion_v13 ProtocolVersion = 13 // Schema-registry : added avro schema format for json + ProtocolVersion_v14 ProtocolVersion = 14 // Add CommandAuthChallenge and CommandAuthResponse for mutual auth + // Added Key_Shared subscription + ProtocolVersion_v15 ProtocolVersion = 15 // Add CommandGetOrCreateSchema and CommandGetOrCreateSchemaResponse + ProtocolVersion_v16 ProtocolVersion = 16 // Add support for broker entry metadata + ProtocolVersion_v17 ProtocolVersion = 17 // Added support ack receipt + ProtocolVersion_v18 ProtocolVersion = 18 // Add client support for broker entry metadata + ProtocolVersion_v19 ProtocolVersion = 19 // Add CommandTcClientConnectRequest and CommandTcClientConnectResponse +) + +// Enum value maps for ProtocolVersion. +var ( + ProtocolVersion_name = map[int32]string{ + 0: "v0", + 1: "v1", + 2: "v2", + 3: "v3", + 4: "v4", + 5: "v5", + 6: "v6", + 7: "v7", + 8: "v8", + 9: "v9", + 10: "v10", + 11: "v11", + 12: "v12", + 13: "v13", + 14: "v14", + 15: "v15", + 16: "v16", + 17: "v17", + 18: "v18", + 19: "v19", + } + ProtocolVersion_value = map[string]int32{ + "v0": 0, + "v1": 1, + "v2": 2, + "v3": 3, + "v4": 4, + "v5": 5, + "v6": 6, + "v7": 7, + "v8": 8, + "v9": 9, + "v10": 10, + "v11": 11, + "v12": 12, + "v13": 13, + "v14": 14, + "v15": 15, + "v16": 16, + "v17": 17, + "v18": 18, + "v19": 19, + } +) + +func (x ProtocolVersion) Enum() *ProtocolVersion { + p := new(ProtocolVersion) + *p = x + return p +} + +func (x ProtocolVersion) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ProtocolVersion) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[4].Descriptor() +} + +func (ProtocolVersion) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[4] +} + +func (x ProtocolVersion) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *ProtocolVersion) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = ProtocolVersion(num) + return nil +} + +// Deprecated: Use ProtocolVersion.Descriptor instead. +func (ProtocolVersion) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{4} +} + +type KeySharedMode int32 + +const ( + KeySharedMode_AUTO_SPLIT KeySharedMode = 0 + KeySharedMode_STICKY KeySharedMode = 1 +) + +// Enum value maps for KeySharedMode. +var ( + KeySharedMode_name = map[int32]string{ + 0: "AUTO_SPLIT", + 1: "STICKY", + } + KeySharedMode_value = map[string]int32{ + "AUTO_SPLIT": 0, + "STICKY": 1, + } +) + +func (x KeySharedMode) Enum() *KeySharedMode { + p := new(KeySharedMode) + *p = x + return p +} + +func (x KeySharedMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (KeySharedMode) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[5].Descriptor() +} + +func (KeySharedMode) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[5] +} + +func (x KeySharedMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *KeySharedMode) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = KeySharedMode(num) + return nil +} + +// Deprecated: Use KeySharedMode.Descriptor instead. +func (KeySharedMode) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{5} +} + +type TxnAction int32 + +const ( + TxnAction_COMMIT TxnAction = 0 + TxnAction_ABORT TxnAction = 1 +) + +// Enum value maps for TxnAction. +var ( + TxnAction_name = map[int32]string{ + 0: "COMMIT", + 1: "ABORT", + } + TxnAction_value = map[string]int32{ + "COMMIT": 0, + "ABORT": 1, + } +) + +func (x TxnAction) Enum() *TxnAction { + p := new(TxnAction) + *p = x + return p +} + +func (x TxnAction) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (TxnAction) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[6].Descriptor() +} + +func (TxnAction) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[6] +} + +func (x TxnAction) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *TxnAction) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = TxnAction(num) + return nil +} + +// Deprecated: Use TxnAction.Descriptor instead. +func (TxnAction) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{6} +} + +type Schema_Type int32 + +const ( + Schema_None Schema_Type = 0 + Schema_String Schema_Type = 1 + Schema_Json Schema_Type = 2 + Schema_Protobuf Schema_Type = 3 + Schema_Avro Schema_Type = 4 + Schema_Bool Schema_Type = 5 + Schema_Int8 Schema_Type = 6 + Schema_Int16 Schema_Type = 7 + Schema_Int32 Schema_Type = 8 + Schema_Int64 Schema_Type = 9 + Schema_Float Schema_Type = 10 + Schema_Double Schema_Type = 11 + Schema_Date Schema_Type = 12 + Schema_Time Schema_Type = 13 + Schema_Timestamp Schema_Type = 14 + Schema_KeyValue Schema_Type = 15 + Schema_Instant Schema_Type = 16 + Schema_LocalDate Schema_Type = 17 + Schema_LocalTime Schema_Type = 18 + Schema_LocalDateTime Schema_Type = 19 + Schema_ProtobufNative Schema_Type = 20 +) + +// Enum value maps for Schema_Type. +var ( + Schema_Type_name = map[int32]string{ + 0: "None", + 1: "String", + 2: "Json", + 3: "Protobuf", + 4: "Avro", + 5: "Bool", + 6: "Int8", + 7: "Int16", + 8: "Int32", + 9: "Int64", + 10: "Float", + 11: "Double", + 12: "Date", + 13: "Time", + 14: "Timestamp", + 15: "KeyValue", + 16: "Instant", + 17: "LocalDate", + 18: "LocalTime", + 19: "LocalDateTime", + 20: "ProtobufNative", + } + Schema_Type_value = map[string]int32{ + "None": 0, + "String": 1, + "Json": 2, + "Protobuf": 3, + "Avro": 4, + "Bool": 5, + "Int8": 6, + "Int16": 7, + "Int32": 8, + "Int64": 9, + "Float": 10, + "Double": 11, + "Date": 12, + "Time": 13, + "Timestamp": 14, + "KeyValue": 15, + "Instant": 16, + "LocalDate": 17, + "LocalTime": 18, + "LocalDateTime": 19, + "ProtobufNative": 20, + } +) + +func (x Schema_Type) Enum() *Schema_Type { + p := new(Schema_Type) + *p = x + return p +} + +func (x Schema_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Schema_Type) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[7].Descriptor() +} + +func (Schema_Type) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[7] +} + +func (x Schema_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *Schema_Type) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = Schema_Type(num) + return nil +} + +// Deprecated: Use Schema_Type.Descriptor instead. +func (Schema_Type) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{0, 0} +} + +type CommandSubscribe_SubType int32 + +const ( + CommandSubscribe_Exclusive CommandSubscribe_SubType = 0 + CommandSubscribe_Shared CommandSubscribe_SubType = 1 + CommandSubscribe_Failover CommandSubscribe_SubType = 2 + CommandSubscribe_Key_Shared CommandSubscribe_SubType = 3 +) + +// Enum value maps for CommandSubscribe_SubType. +var ( + CommandSubscribe_SubType_name = map[int32]string{ + 0: "Exclusive", + 1: "Shared", + 2: "Failover", + 3: "Key_Shared", + } + CommandSubscribe_SubType_value = map[string]int32{ + "Exclusive": 0, + "Shared": 1, + "Failover": 2, + "Key_Shared": 3, + } +) + +func (x CommandSubscribe_SubType) Enum() *CommandSubscribe_SubType { + p := new(CommandSubscribe_SubType) + *p = x + return p +} + +func (x CommandSubscribe_SubType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CommandSubscribe_SubType) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[8].Descriptor() +} + +func (CommandSubscribe_SubType) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[8] +} + +func (x CommandSubscribe_SubType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *CommandSubscribe_SubType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = CommandSubscribe_SubType(num) + return nil +} + +// Deprecated: Use CommandSubscribe_SubType.Descriptor instead. +func (CommandSubscribe_SubType) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{16, 0} +} + +type CommandSubscribe_InitialPosition int32 + +const ( + CommandSubscribe_Latest CommandSubscribe_InitialPosition = 0 + CommandSubscribe_Earliest CommandSubscribe_InitialPosition = 1 +) + +// Enum value maps for CommandSubscribe_InitialPosition. +var ( + CommandSubscribe_InitialPosition_name = map[int32]string{ + 0: "Latest", + 1: "Earliest", + } + CommandSubscribe_InitialPosition_value = map[string]int32{ + "Latest": 0, + "Earliest": 1, + } +) + +func (x CommandSubscribe_InitialPosition) Enum() *CommandSubscribe_InitialPosition { + p := new(CommandSubscribe_InitialPosition) + *p = x + return p +} + +func (x CommandSubscribe_InitialPosition) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CommandSubscribe_InitialPosition) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[9].Descriptor() +} + +func (CommandSubscribe_InitialPosition) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[9] +} + +func (x CommandSubscribe_InitialPosition) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *CommandSubscribe_InitialPosition) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = CommandSubscribe_InitialPosition(num) + return nil +} + +// Deprecated: Use CommandSubscribe_InitialPosition.Descriptor instead. +func (CommandSubscribe_InitialPosition) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{16, 1} +} + +type CommandPartitionedTopicMetadataResponse_LookupType int32 + +const ( + CommandPartitionedTopicMetadataResponse_Success CommandPartitionedTopicMetadataResponse_LookupType = 0 + CommandPartitionedTopicMetadataResponse_Failed CommandPartitionedTopicMetadataResponse_LookupType = 1 +) + +// Enum value maps for CommandPartitionedTopicMetadataResponse_LookupType. +var ( + CommandPartitionedTopicMetadataResponse_LookupType_name = map[int32]string{ + 0: "Success", + 1: "Failed", + } + CommandPartitionedTopicMetadataResponse_LookupType_value = map[string]int32{ + "Success": 0, + "Failed": 1, + } +) + +func (x CommandPartitionedTopicMetadataResponse_LookupType) Enum() *CommandPartitionedTopicMetadataResponse_LookupType { + p := new(CommandPartitionedTopicMetadataResponse_LookupType) + *p = x + return p +} + +func (x CommandPartitionedTopicMetadataResponse_LookupType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CommandPartitionedTopicMetadataResponse_LookupType) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[10].Descriptor() +} + +func (CommandPartitionedTopicMetadataResponse_LookupType) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[10] +} + +func (x CommandPartitionedTopicMetadataResponse_LookupType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *CommandPartitionedTopicMetadataResponse_LookupType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = CommandPartitionedTopicMetadataResponse_LookupType(num) + return nil +} + +// Deprecated: Use CommandPartitionedTopicMetadataResponse_LookupType.Descriptor instead. +func (CommandPartitionedTopicMetadataResponse_LookupType) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{18, 0} +} + +type CommandLookupTopicResponse_LookupType int32 + +const ( + CommandLookupTopicResponse_Redirect CommandLookupTopicResponse_LookupType = 0 + CommandLookupTopicResponse_Connect CommandLookupTopicResponse_LookupType = 1 + CommandLookupTopicResponse_Failed CommandLookupTopicResponse_LookupType = 2 +) + +// Enum value maps for CommandLookupTopicResponse_LookupType. +var ( + CommandLookupTopicResponse_LookupType_name = map[int32]string{ + 0: "Redirect", + 1: "Connect", + 2: "Failed", + } + CommandLookupTopicResponse_LookupType_value = map[string]int32{ + "Redirect": 0, + "Connect": 1, + "Failed": 2, + } +) + +func (x CommandLookupTopicResponse_LookupType) Enum() *CommandLookupTopicResponse_LookupType { + p := new(CommandLookupTopicResponse_LookupType) + *p = x + return p +} + +func (x CommandLookupTopicResponse_LookupType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CommandLookupTopicResponse_LookupType) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[11].Descriptor() +} + +func (CommandLookupTopicResponse_LookupType) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[11] +} + +func (x CommandLookupTopicResponse_LookupType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *CommandLookupTopicResponse_LookupType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = CommandLookupTopicResponse_LookupType(num) + return nil +} + +// Deprecated: Use CommandLookupTopicResponse_LookupType.Descriptor instead. +func (CommandLookupTopicResponse_LookupType) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{20, 0} +} + +type CommandAck_AckType int32 + +const ( + CommandAck_Individual CommandAck_AckType = 0 + CommandAck_Cumulative CommandAck_AckType = 1 +) + +// Enum value maps for CommandAck_AckType. +var ( + CommandAck_AckType_name = map[int32]string{ + 0: "Individual", + 1: "Cumulative", + } + CommandAck_AckType_value = map[string]int32{ + "Individual": 0, + "Cumulative": 1, + } +) + +func (x CommandAck_AckType) Enum() *CommandAck_AckType { + p := new(CommandAck_AckType) + *p = x + return p +} + +func (x CommandAck_AckType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CommandAck_AckType) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[12].Descriptor() +} + +func (CommandAck_AckType) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[12] +} + +func (x CommandAck_AckType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *CommandAck_AckType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = CommandAck_AckType(num) + return nil +} + +// Deprecated: Use CommandAck_AckType.Descriptor instead. +func (CommandAck_AckType) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{26, 0} +} + +// Acks can contain a flag to indicate the consumer +// received an invalid message that got discarded +// before being passed on to the application. +type CommandAck_ValidationError int32 + +const ( + CommandAck_UncompressedSizeCorruption CommandAck_ValidationError = 0 + CommandAck_DecompressionError CommandAck_ValidationError = 1 + CommandAck_ChecksumMismatch CommandAck_ValidationError = 2 + CommandAck_BatchDeSerializeError CommandAck_ValidationError = 3 + CommandAck_DecryptionError CommandAck_ValidationError = 4 +) + +// Enum value maps for CommandAck_ValidationError. +var ( + CommandAck_ValidationError_name = map[int32]string{ + 0: "UncompressedSizeCorruption", + 1: "DecompressionError", + 2: "ChecksumMismatch", + 3: "BatchDeSerializeError", + 4: "DecryptionError", + } + CommandAck_ValidationError_value = map[string]int32{ + "UncompressedSizeCorruption": 0, + "DecompressionError": 1, + "ChecksumMismatch": 2, + "BatchDeSerializeError": 3, + "DecryptionError": 4, + } +) + +func (x CommandAck_ValidationError) Enum() *CommandAck_ValidationError { + p := new(CommandAck_ValidationError) + *p = x + return p +} + +func (x CommandAck_ValidationError) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CommandAck_ValidationError) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[13].Descriptor() +} + +func (CommandAck_ValidationError) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[13] +} + +func (x CommandAck_ValidationError) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *CommandAck_ValidationError) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = CommandAck_ValidationError(num) + return nil +} + +// Deprecated: Use CommandAck_ValidationError.Descriptor instead. +func (CommandAck_ValidationError) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{26, 1} +} + +type CommandGetTopicsOfNamespace_Mode int32 + +const ( + CommandGetTopicsOfNamespace_PERSISTENT CommandGetTopicsOfNamespace_Mode = 0 + CommandGetTopicsOfNamespace_NON_PERSISTENT CommandGetTopicsOfNamespace_Mode = 1 + CommandGetTopicsOfNamespace_ALL CommandGetTopicsOfNamespace_Mode = 2 +) + +// Enum value maps for CommandGetTopicsOfNamespace_Mode. +var ( + CommandGetTopicsOfNamespace_Mode_name = map[int32]string{ + 0: "PERSISTENT", + 1: "NON_PERSISTENT", + 2: "ALL", + } + CommandGetTopicsOfNamespace_Mode_value = map[string]int32{ + "PERSISTENT": 0, + "NON_PERSISTENT": 1, + "ALL": 2, + } +) + +func (x CommandGetTopicsOfNamespace_Mode) Enum() *CommandGetTopicsOfNamespace_Mode { + p := new(CommandGetTopicsOfNamespace_Mode) + *p = x + return p +} + +func (x CommandGetTopicsOfNamespace_Mode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CommandGetTopicsOfNamespace_Mode) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[14].Descriptor() +} + +func (CommandGetTopicsOfNamespace_Mode) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[14] +} + +func (x CommandGetTopicsOfNamespace_Mode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *CommandGetTopicsOfNamespace_Mode) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = CommandGetTopicsOfNamespace_Mode(num) + return nil +} + +// Deprecated: Use CommandGetTopicsOfNamespace_Mode.Descriptor instead. +func (CommandGetTopicsOfNamespace_Mode) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{45, 0} +} + +type BaseCommand_Type int32 + +const ( + BaseCommand_CONNECT BaseCommand_Type = 2 + BaseCommand_CONNECTED BaseCommand_Type = 3 + BaseCommand_SUBSCRIBE BaseCommand_Type = 4 + BaseCommand_PRODUCER BaseCommand_Type = 5 + BaseCommand_SEND BaseCommand_Type = 6 + BaseCommand_SEND_RECEIPT BaseCommand_Type = 7 + BaseCommand_SEND_ERROR BaseCommand_Type = 8 + BaseCommand_MESSAGE BaseCommand_Type = 9 + BaseCommand_ACK BaseCommand_Type = 10 + BaseCommand_FLOW BaseCommand_Type = 11 + BaseCommand_UNSUBSCRIBE BaseCommand_Type = 12 + BaseCommand_SUCCESS BaseCommand_Type = 13 + BaseCommand_ERROR BaseCommand_Type = 14 + BaseCommand_CLOSE_PRODUCER BaseCommand_Type = 15 + BaseCommand_CLOSE_CONSUMER BaseCommand_Type = 16 + BaseCommand_PRODUCER_SUCCESS BaseCommand_Type = 17 + BaseCommand_PING BaseCommand_Type = 18 + BaseCommand_PONG BaseCommand_Type = 19 + BaseCommand_REDELIVER_UNACKNOWLEDGED_MESSAGES BaseCommand_Type = 20 + BaseCommand_PARTITIONED_METADATA BaseCommand_Type = 21 + BaseCommand_PARTITIONED_METADATA_RESPONSE BaseCommand_Type = 22 + BaseCommand_LOOKUP BaseCommand_Type = 23 + BaseCommand_LOOKUP_RESPONSE BaseCommand_Type = 24 + BaseCommand_CONSUMER_STATS BaseCommand_Type = 25 + BaseCommand_CONSUMER_STATS_RESPONSE BaseCommand_Type = 26 + BaseCommand_REACHED_END_OF_TOPIC BaseCommand_Type = 27 + BaseCommand_SEEK BaseCommand_Type = 28 + BaseCommand_GET_LAST_MESSAGE_ID BaseCommand_Type = 29 + BaseCommand_GET_LAST_MESSAGE_ID_RESPONSE BaseCommand_Type = 30 + BaseCommand_ACTIVE_CONSUMER_CHANGE BaseCommand_Type = 31 + BaseCommand_GET_TOPICS_OF_NAMESPACE BaseCommand_Type = 32 + BaseCommand_GET_TOPICS_OF_NAMESPACE_RESPONSE BaseCommand_Type = 33 + BaseCommand_GET_SCHEMA BaseCommand_Type = 34 + BaseCommand_GET_SCHEMA_RESPONSE BaseCommand_Type = 35 + BaseCommand_AUTH_CHALLENGE BaseCommand_Type = 36 + BaseCommand_AUTH_RESPONSE BaseCommand_Type = 37 + BaseCommand_ACK_RESPONSE BaseCommand_Type = 38 + BaseCommand_GET_OR_CREATE_SCHEMA BaseCommand_Type = 39 + BaseCommand_GET_OR_CREATE_SCHEMA_RESPONSE BaseCommand_Type = 40 + // transaction related + BaseCommand_NEW_TXN BaseCommand_Type = 50 + BaseCommand_NEW_TXN_RESPONSE BaseCommand_Type = 51 + BaseCommand_ADD_PARTITION_TO_TXN BaseCommand_Type = 52 + BaseCommand_ADD_PARTITION_TO_TXN_RESPONSE BaseCommand_Type = 53 + BaseCommand_ADD_SUBSCRIPTION_TO_TXN BaseCommand_Type = 54 + BaseCommand_ADD_SUBSCRIPTION_TO_TXN_RESPONSE BaseCommand_Type = 55 + BaseCommand_END_TXN BaseCommand_Type = 56 + BaseCommand_END_TXN_RESPONSE BaseCommand_Type = 57 + BaseCommand_END_TXN_ON_PARTITION BaseCommand_Type = 58 + BaseCommand_END_TXN_ON_PARTITION_RESPONSE BaseCommand_Type = 59 + BaseCommand_END_TXN_ON_SUBSCRIPTION BaseCommand_Type = 60 + BaseCommand_END_TXN_ON_SUBSCRIPTION_RESPONSE BaseCommand_Type = 61 + BaseCommand_TC_CLIENT_CONNECT_REQUEST BaseCommand_Type = 62 + BaseCommand_TC_CLIENT_CONNECT_RESPONSE BaseCommand_Type = 63 + BaseCommand_WATCH_TOPIC_LIST BaseCommand_Type = 64 + BaseCommand_WATCH_TOPIC_LIST_SUCCESS BaseCommand_Type = 65 + BaseCommand_WATCH_TOPIC_UPDATE BaseCommand_Type = 66 + BaseCommand_WATCH_TOPIC_LIST_CLOSE BaseCommand_Type = 67 +) + +// Enum value maps for BaseCommand_Type. +var ( + BaseCommand_Type_name = map[int32]string{ + 2: "CONNECT", + 3: "CONNECTED", + 4: "SUBSCRIBE", + 5: "PRODUCER", + 6: "SEND", + 7: "SEND_RECEIPT", + 8: "SEND_ERROR", + 9: "MESSAGE", + 10: "ACK", + 11: "FLOW", + 12: "UNSUBSCRIBE", + 13: "SUCCESS", + 14: "ERROR", + 15: "CLOSE_PRODUCER", + 16: "CLOSE_CONSUMER", + 17: "PRODUCER_SUCCESS", + 18: "PING", + 19: "PONG", + 20: "REDELIVER_UNACKNOWLEDGED_MESSAGES", + 21: "PARTITIONED_METADATA", + 22: "PARTITIONED_METADATA_RESPONSE", + 23: "LOOKUP", + 24: "LOOKUP_RESPONSE", + 25: "CONSUMER_STATS", + 26: "CONSUMER_STATS_RESPONSE", + 27: "REACHED_END_OF_TOPIC", + 28: "SEEK", + 29: "GET_LAST_MESSAGE_ID", + 30: "GET_LAST_MESSAGE_ID_RESPONSE", + 31: "ACTIVE_CONSUMER_CHANGE", + 32: "GET_TOPICS_OF_NAMESPACE", + 33: "GET_TOPICS_OF_NAMESPACE_RESPONSE", + 34: "GET_SCHEMA", + 35: "GET_SCHEMA_RESPONSE", + 36: "AUTH_CHALLENGE", + 37: "AUTH_RESPONSE", + 38: "ACK_RESPONSE", + 39: "GET_OR_CREATE_SCHEMA", + 40: "GET_OR_CREATE_SCHEMA_RESPONSE", + 50: "NEW_TXN", + 51: "NEW_TXN_RESPONSE", + 52: "ADD_PARTITION_TO_TXN", + 53: "ADD_PARTITION_TO_TXN_RESPONSE", + 54: "ADD_SUBSCRIPTION_TO_TXN", + 55: "ADD_SUBSCRIPTION_TO_TXN_RESPONSE", + 56: "END_TXN", + 57: "END_TXN_RESPONSE", + 58: "END_TXN_ON_PARTITION", + 59: "END_TXN_ON_PARTITION_RESPONSE", + 60: "END_TXN_ON_SUBSCRIPTION", + 61: "END_TXN_ON_SUBSCRIPTION_RESPONSE", + 62: "TC_CLIENT_CONNECT_REQUEST", + 63: "TC_CLIENT_CONNECT_RESPONSE", + 64: "WATCH_TOPIC_LIST", + 65: "WATCH_TOPIC_LIST_SUCCESS", + 66: "WATCH_TOPIC_UPDATE", + 67: "WATCH_TOPIC_LIST_CLOSE", + } + BaseCommand_Type_value = map[string]int32{ + "CONNECT": 2, + "CONNECTED": 3, + "SUBSCRIBE": 4, + "PRODUCER": 5, + "SEND": 6, + "SEND_RECEIPT": 7, + "SEND_ERROR": 8, + "MESSAGE": 9, + "ACK": 10, + "FLOW": 11, + "UNSUBSCRIBE": 12, + "SUCCESS": 13, + "ERROR": 14, + "CLOSE_PRODUCER": 15, + "CLOSE_CONSUMER": 16, + "PRODUCER_SUCCESS": 17, + "PING": 18, + "PONG": 19, + "REDELIVER_UNACKNOWLEDGED_MESSAGES": 20, + "PARTITIONED_METADATA": 21, + "PARTITIONED_METADATA_RESPONSE": 22, + "LOOKUP": 23, + "LOOKUP_RESPONSE": 24, + "CONSUMER_STATS": 25, + "CONSUMER_STATS_RESPONSE": 26, + "REACHED_END_OF_TOPIC": 27, + "SEEK": 28, + "GET_LAST_MESSAGE_ID": 29, + "GET_LAST_MESSAGE_ID_RESPONSE": 30, + "ACTIVE_CONSUMER_CHANGE": 31, + "GET_TOPICS_OF_NAMESPACE": 32, + "GET_TOPICS_OF_NAMESPACE_RESPONSE": 33, + "GET_SCHEMA": 34, + "GET_SCHEMA_RESPONSE": 35, + "AUTH_CHALLENGE": 36, + "AUTH_RESPONSE": 37, + "ACK_RESPONSE": 38, + "GET_OR_CREATE_SCHEMA": 39, + "GET_OR_CREATE_SCHEMA_RESPONSE": 40, + "NEW_TXN": 50, + "NEW_TXN_RESPONSE": 51, + "ADD_PARTITION_TO_TXN": 52, + "ADD_PARTITION_TO_TXN_RESPONSE": 53, + "ADD_SUBSCRIPTION_TO_TXN": 54, + "ADD_SUBSCRIPTION_TO_TXN_RESPONSE": 55, + "END_TXN": 56, + "END_TXN_RESPONSE": 57, + "END_TXN_ON_PARTITION": 58, + "END_TXN_ON_PARTITION_RESPONSE": 59, + "END_TXN_ON_SUBSCRIPTION": 60, + "END_TXN_ON_SUBSCRIPTION_RESPONSE": 61, + "TC_CLIENT_CONNECT_REQUEST": 62, + "TC_CLIENT_CONNECT_RESPONSE": 63, + "WATCH_TOPIC_LIST": 64, + "WATCH_TOPIC_LIST_SUCCESS": 65, + "WATCH_TOPIC_UPDATE": 66, + "WATCH_TOPIC_LIST_CLOSE": 67, + } +) + +func (x BaseCommand_Type) Enum() *BaseCommand_Type { + p := new(BaseCommand_Type) + *p = x + return p +} + +func (x BaseCommand_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (BaseCommand_Type) Descriptor() protoreflect.EnumDescriptor { + return file_PulsarApi_proto_enumTypes[15].Descriptor() +} + +func (BaseCommand_Type) Type() protoreflect.EnumType { + return &file_PulsarApi_proto_enumTypes[15] +} + +func (x BaseCommand_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *BaseCommand_Type) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = BaseCommand_Type(num) + return nil +} + +// Deprecated: Use BaseCommand_Type.Descriptor instead. +func (BaseCommand_Type) EnumDescriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{70, 0} +} + +type Schema struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` + SchemaData []byte `protobuf:"bytes,3,req,name=schema_data,json=schemaData" json:"schema_data,omitempty"` + Type *Schema_Type `protobuf:"varint,4,req,name=type,enum=pulsar.proto.Schema_Type" json:"type,omitempty"` + Properties []*KeyValue `protobuf:"bytes,5,rep,name=properties" json:"properties,omitempty"` +} + +func (x *Schema) Reset() { + *x = Schema{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Schema) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Schema) ProtoMessage() {} + +func (x *Schema) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Schema.ProtoReflect.Descriptor instead. +func (*Schema) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{0} +} + +func (x *Schema) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *Schema) GetSchemaData() []byte { + if x != nil { + return x.SchemaData + } + return nil +} + +func (x *Schema) GetType() Schema_Type { + if x != nil && x.Type != nil { + return *x.Type + } + return Schema_None +} + +func (x *Schema) GetProperties() []*KeyValue { + if x != nil { + return x.Properties + } + return nil +} + +type MessageIdData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LedgerId *uint64 `protobuf:"varint,1,req,name=ledgerId" json:"ledgerId,omitempty"` + EntryId *uint64 `protobuf:"varint,2,req,name=entryId" json:"entryId,omitempty"` + Partition *int32 `protobuf:"varint,3,opt,name=partition,def=-1" json:"partition,omitempty"` + BatchIndex *int32 `protobuf:"varint,4,opt,name=batch_index,json=batchIndex,def=-1" json:"batch_index,omitempty"` + AckSet []int64 `protobuf:"varint,5,rep,name=ack_set,json=ackSet" json:"ack_set,omitempty"` + BatchSize *int32 `protobuf:"varint,6,opt,name=batch_size,json=batchSize" json:"batch_size,omitempty"` + // For the chunk message id, we need to specify the first chunk message id. + FirstChunkMessageId *MessageIdData `protobuf:"bytes,7,opt,name=first_chunk_message_id,json=firstChunkMessageId" json:"first_chunk_message_id,omitempty"` +} + +// Default values for MessageIdData fields. +const ( + Default_MessageIdData_Partition = int32(-1) + Default_MessageIdData_BatchIndex = int32(-1) +) + +func (x *MessageIdData) Reset() { + *x = MessageIdData{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MessageIdData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MessageIdData) ProtoMessage() {} + +func (x *MessageIdData) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MessageIdData.ProtoReflect.Descriptor instead. +func (*MessageIdData) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{1} +} + +func (x *MessageIdData) GetLedgerId() uint64 { + if x != nil && x.LedgerId != nil { + return *x.LedgerId + } + return 0 +} + +func (x *MessageIdData) GetEntryId() uint64 { + if x != nil && x.EntryId != nil { + return *x.EntryId + } + return 0 +} + +func (x *MessageIdData) GetPartition() int32 { + if x != nil && x.Partition != nil { + return *x.Partition + } + return Default_MessageIdData_Partition +} + +func (x *MessageIdData) GetBatchIndex() int32 { + if x != nil && x.BatchIndex != nil { + return *x.BatchIndex + } + return Default_MessageIdData_BatchIndex +} + +func (x *MessageIdData) GetAckSet() []int64 { + if x != nil { + return x.AckSet + } + return nil +} + +func (x *MessageIdData) GetBatchSize() int32 { + if x != nil && x.BatchSize != nil { + return *x.BatchSize + } + return 0 +} + +func (x *MessageIdData) GetFirstChunkMessageId() *MessageIdData { + if x != nil { + return x.FirstChunkMessageId + } + return nil +} + +type KeyValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"` + Value *string `protobuf:"bytes,2,req,name=value" json:"value,omitempty"` +} + +func (x *KeyValue) Reset() { + *x = KeyValue{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *KeyValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*KeyValue) ProtoMessage() {} + +func (x *KeyValue) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use KeyValue.ProtoReflect.Descriptor instead. +func (*KeyValue) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{2} +} + +func (x *KeyValue) GetKey() string { + if x != nil && x.Key != nil { + return *x.Key + } + return "" +} + +func (x *KeyValue) GetValue() string { + if x != nil && x.Value != nil { + return *x.Value + } + return "" +} + +type KeyLongValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"` + Value *uint64 `protobuf:"varint,2,req,name=value" json:"value,omitempty"` +} + +func (x *KeyLongValue) Reset() { + *x = KeyLongValue{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *KeyLongValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*KeyLongValue) ProtoMessage() {} + +func (x *KeyLongValue) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use KeyLongValue.ProtoReflect.Descriptor instead. +func (*KeyLongValue) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{3} +} + +func (x *KeyLongValue) GetKey() string { + if x != nil && x.Key != nil { + return *x.Key + } + return "" +} + +func (x *KeyLongValue) GetValue() uint64 { + if x != nil && x.Value != nil { + return *x.Value + } + return 0 +} + +type IntRange struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Start *int32 `protobuf:"varint,1,req,name=start" json:"start,omitempty"` + End *int32 `protobuf:"varint,2,req,name=end" json:"end,omitempty"` +} + +func (x *IntRange) Reset() { + *x = IntRange{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IntRange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IntRange) ProtoMessage() {} + +func (x *IntRange) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IntRange.ProtoReflect.Descriptor instead. +func (*IntRange) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{4} +} + +func (x *IntRange) GetStart() int32 { + if x != nil && x.Start != nil { + return *x.Start + } + return 0 +} + +func (x *IntRange) GetEnd() int32 { + if x != nil && x.End != nil { + return *x.End + } + return 0 +} + +type EncryptionKeys struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"` + Value []byte `protobuf:"bytes,2,req,name=value" json:"value,omitempty"` + Metadata []*KeyValue `protobuf:"bytes,3,rep,name=metadata" json:"metadata,omitempty"` +} + +func (x *EncryptionKeys) Reset() { + *x = EncryptionKeys{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EncryptionKeys) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EncryptionKeys) ProtoMessage() {} + +func (x *EncryptionKeys) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EncryptionKeys.ProtoReflect.Descriptor instead. +func (*EncryptionKeys) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{5} +} + +func (x *EncryptionKeys) GetKey() string { + if x != nil && x.Key != nil { + return *x.Key + } + return "" +} + +func (x *EncryptionKeys) GetValue() []byte { + if x != nil { + return x.Value + } + return nil +} + +func (x *EncryptionKeys) GetMetadata() []*KeyValue { + if x != nil { + return x.Metadata + } + return nil +} + +type MessageMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProducerName *string `protobuf:"bytes,1,req,name=producer_name,json=producerName" json:"producer_name,omitempty"` + SequenceId *uint64 `protobuf:"varint,2,req,name=sequence_id,json=sequenceId" json:"sequence_id,omitempty"` + PublishTime *uint64 `protobuf:"varint,3,req,name=publish_time,json=publishTime" json:"publish_time,omitempty"` + Properties []*KeyValue `protobuf:"bytes,4,rep,name=properties" json:"properties,omitempty"` + // Property set on replicated message, + // includes the source cluster name + ReplicatedFrom *string `protobuf:"bytes,5,opt,name=replicated_from,json=replicatedFrom" json:"replicated_from,omitempty"` + //key to decide partition for the msg + PartitionKey *string `protobuf:"bytes,6,opt,name=partition_key,json=partitionKey" json:"partition_key,omitempty"` + // Override namespace's replication + ReplicateTo []string `protobuf:"bytes,7,rep,name=replicate_to,json=replicateTo" json:"replicate_to,omitempty"` + Compression *CompressionType `protobuf:"varint,8,opt,name=compression,enum=pulsar.proto.CompressionType,def=0" json:"compression,omitempty"` + UncompressedSize *uint32 `protobuf:"varint,9,opt,name=uncompressed_size,json=uncompressedSize,def=0" json:"uncompressed_size,omitempty"` + // Removed below checksum field from Metadata as + // it should be part of send-command which keeps checksum of header + payload + //optional sfixed64 checksum = 10; + // differentiate single and batch message metadata + NumMessagesInBatch *int32 `protobuf:"varint,11,opt,name=num_messages_in_batch,json=numMessagesInBatch,def=1" json:"num_messages_in_batch,omitempty"` + // the timestamp that this event occurs. it is typically set by applications. + // if this field is omitted, `publish_time` can be used for the purpose of `event_time`. + EventTime *uint64 `protobuf:"varint,12,opt,name=event_time,json=eventTime,def=0" json:"event_time,omitempty"` + // Contains encryption key name, encrypted key and metadata to describe the key + EncryptionKeys []*EncryptionKeys `protobuf:"bytes,13,rep,name=encryption_keys,json=encryptionKeys" json:"encryption_keys,omitempty"` + // Algorithm used to encrypt data key + EncryptionAlgo *string `protobuf:"bytes,14,opt,name=encryption_algo,json=encryptionAlgo" json:"encryption_algo,omitempty"` + // Additional parameters required by encryption + EncryptionParam []byte `protobuf:"bytes,15,opt,name=encryption_param,json=encryptionParam" json:"encryption_param,omitempty"` + SchemaVersion []byte `protobuf:"bytes,16,opt,name=schema_version,json=schemaVersion" json:"schema_version,omitempty"` + PartitionKeyB64Encoded *bool `protobuf:"varint,17,opt,name=partition_key_b64_encoded,json=partitionKeyB64Encoded,def=0" json:"partition_key_b64_encoded,omitempty"` + // Specific a key to overwrite the message key which used for ordering dispatch in Key_Shared mode. + OrderingKey []byte `protobuf:"bytes,18,opt,name=ordering_key,json=orderingKey" json:"ordering_key,omitempty"` + // Mark the message to be delivered at or after the specified timestamp + DeliverAtTime *int64 `protobuf:"varint,19,opt,name=deliver_at_time,json=deliverAtTime" json:"deliver_at_time,omitempty"` + // Identify whether a message is a "marker" message used for + // internal metadata instead of application published data. + // Markers will generally not be propagated back to clients + MarkerType *int32 `protobuf:"varint,20,opt,name=marker_type,json=markerType" json:"marker_type,omitempty"` + // transaction related message info + TxnidLeastBits *uint64 `protobuf:"varint,22,opt,name=txnid_least_bits,json=txnidLeastBits" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,23,opt,name=txnid_most_bits,json=txnidMostBits" json:"txnid_most_bits,omitempty"` + /// Add highest sequence id to support batch message with external sequence id + HighestSequenceId *uint64 `protobuf:"varint,24,opt,name=highest_sequence_id,json=highestSequenceId,def=0" json:"highest_sequence_id,omitempty"` + // Indicate if the message payload value is set + NullValue *bool `protobuf:"varint,25,opt,name=null_value,json=nullValue,def=0" json:"null_value,omitempty"` + Uuid *string `protobuf:"bytes,26,opt,name=uuid" json:"uuid,omitempty"` + NumChunksFromMsg *int32 `protobuf:"varint,27,opt,name=num_chunks_from_msg,json=numChunksFromMsg" json:"num_chunks_from_msg,omitempty"` + TotalChunkMsgSize *int32 `protobuf:"varint,28,opt,name=total_chunk_msg_size,json=totalChunkMsgSize" json:"total_chunk_msg_size,omitempty"` + ChunkId *int32 `protobuf:"varint,29,opt,name=chunk_id,json=chunkId" json:"chunk_id,omitempty"` + // Indicate if the message partition key is set + NullPartitionKey *bool `protobuf:"varint,30,opt,name=null_partition_key,json=nullPartitionKey,def=0" json:"null_partition_key,omitempty"` +} + +// Default values for MessageMetadata fields. +const ( + Default_MessageMetadata_Compression = CompressionType_NONE + Default_MessageMetadata_UncompressedSize = uint32(0) + Default_MessageMetadata_NumMessagesInBatch = int32(1) + Default_MessageMetadata_EventTime = uint64(0) + Default_MessageMetadata_PartitionKeyB64Encoded = bool(false) + Default_MessageMetadata_HighestSequenceId = uint64(0) + Default_MessageMetadata_NullValue = bool(false) + Default_MessageMetadata_NullPartitionKey = bool(false) +) + +func (x *MessageMetadata) Reset() { + *x = MessageMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MessageMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MessageMetadata) ProtoMessage() {} + +func (x *MessageMetadata) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MessageMetadata.ProtoReflect.Descriptor instead. +func (*MessageMetadata) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{6} +} + +func (x *MessageMetadata) GetProducerName() string { + if x != nil && x.ProducerName != nil { + return *x.ProducerName + } + return "" +} + +func (x *MessageMetadata) GetSequenceId() uint64 { + if x != nil && x.SequenceId != nil { + return *x.SequenceId + } + return 0 +} + +func (x *MessageMetadata) GetPublishTime() uint64 { + if x != nil && x.PublishTime != nil { + return *x.PublishTime + } + return 0 +} + +func (x *MessageMetadata) GetProperties() []*KeyValue { + if x != nil { + return x.Properties + } + return nil +} + +func (x *MessageMetadata) GetReplicatedFrom() string { + if x != nil && x.ReplicatedFrom != nil { + return *x.ReplicatedFrom + } + return "" +} + +func (x *MessageMetadata) GetPartitionKey() string { + if x != nil && x.PartitionKey != nil { + return *x.PartitionKey + } + return "" +} + +func (x *MessageMetadata) GetReplicateTo() []string { + if x != nil { + return x.ReplicateTo + } + return nil +} + +func (x *MessageMetadata) GetCompression() CompressionType { + if x != nil && x.Compression != nil { + return *x.Compression + } + return Default_MessageMetadata_Compression +} + +func (x *MessageMetadata) GetUncompressedSize() uint32 { + if x != nil && x.UncompressedSize != nil { + return *x.UncompressedSize + } + return Default_MessageMetadata_UncompressedSize +} + +func (x *MessageMetadata) GetNumMessagesInBatch() int32 { + if x != nil && x.NumMessagesInBatch != nil { + return *x.NumMessagesInBatch + } + return Default_MessageMetadata_NumMessagesInBatch +} + +func (x *MessageMetadata) GetEventTime() uint64 { + if x != nil && x.EventTime != nil { + return *x.EventTime + } + return Default_MessageMetadata_EventTime +} + +func (x *MessageMetadata) GetEncryptionKeys() []*EncryptionKeys { + if x != nil { + return x.EncryptionKeys + } + return nil +} + +func (x *MessageMetadata) GetEncryptionAlgo() string { + if x != nil && x.EncryptionAlgo != nil { + return *x.EncryptionAlgo + } + return "" +} + +func (x *MessageMetadata) GetEncryptionParam() []byte { + if x != nil { + return x.EncryptionParam + } + return nil +} + +func (x *MessageMetadata) GetSchemaVersion() []byte { + if x != nil { + return x.SchemaVersion + } + return nil +} + +func (x *MessageMetadata) GetPartitionKeyB64Encoded() bool { + if x != nil && x.PartitionKeyB64Encoded != nil { + return *x.PartitionKeyB64Encoded + } + return Default_MessageMetadata_PartitionKeyB64Encoded +} + +func (x *MessageMetadata) GetOrderingKey() []byte { + if x != nil { + return x.OrderingKey + } + return nil +} + +func (x *MessageMetadata) GetDeliverAtTime() int64 { + if x != nil && x.DeliverAtTime != nil { + return *x.DeliverAtTime + } + return 0 +} + +func (x *MessageMetadata) GetMarkerType() int32 { + if x != nil && x.MarkerType != nil { + return *x.MarkerType + } + return 0 +} + +func (x *MessageMetadata) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return 0 +} + +func (x *MessageMetadata) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return 0 +} + +func (x *MessageMetadata) GetHighestSequenceId() uint64 { + if x != nil && x.HighestSequenceId != nil { + return *x.HighestSequenceId + } + return Default_MessageMetadata_HighestSequenceId +} + +func (x *MessageMetadata) GetNullValue() bool { + if x != nil && x.NullValue != nil { + return *x.NullValue + } + return Default_MessageMetadata_NullValue +} + +func (x *MessageMetadata) GetUuid() string { + if x != nil && x.Uuid != nil { + return *x.Uuid + } + return "" +} + +func (x *MessageMetadata) GetNumChunksFromMsg() int32 { + if x != nil && x.NumChunksFromMsg != nil { + return *x.NumChunksFromMsg + } + return 0 +} + +func (x *MessageMetadata) GetTotalChunkMsgSize() int32 { + if x != nil && x.TotalChunkMsgSize != nil { + return *x.TotalChunkMsgSize + } + return 0 +} + +func (x *MessageMetadata) GetChunkId() int32 { + if x != nil && x.ChunkId != nil { + return *x.ChunkId + } + return 0 +} + +func (x *MessageMetadata) GetNullPartitionKey() bool { + if x != nil && x.NullPartitionKey != nil { + return *x.NullPartitionKey + } + return Default_MessageMetadata_NullPartitionKey +} + +type SingleMessageMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Properties []*KeyValue `protobuf:"bytes,1,rep,name=properties" json:"properties,omitempty"` + PartitionKey *string `protobuf:"bytes,2,opt,name=partition_key,json=partitionKey" json:"partition_key,omitempty"` + PayloadSize *int32 `protobuf:"varint,3,req,name=payload_size,json=payloadSize" json:"payload_size,omitempty"` + CompactedOut *bool `protobuf:"varint,4,opt,name=compacted_out,json=compactedOut,def=0" json:"compacted_out,omitempty"` + // the timestamp that this event occurs. it is typically set by applications. + // if this field is omitted, `publish_time` can be used for the purpose of `event_time`. + EventTime *uint64 `protobuf:"varint,5,opt,name=event_time,json=eventTime,def=0" json:"event_time,omitempty"` + PartitionKeyB64Encoded *bool `protobuf:"varint,6,opt,name=partition_key_b64_encoded,json=partitionKeyB64Encoded,def=0" json:"partition_key_b64_encoded,omitempty"` + // Specific a key to overwrite the message key which used for ordering dispatch in Key_Shared mode. + OrderingKey []byte `protobuf:"bytes,7,opt,name=ordering_key,json=orderingKey" json:"ordering_key,omitempty"` + // Allows consumer retrieve the sequence id that the producer set. + SequenceId *uint64 `protobuf:"varint,8,opt,name=sequence_id,json=sequenceId" json:"sequence_id,omitempty"` + // Indicate if the message payload value is set + NullValue *bool `protobuf:"varint,9,opt,name=null_value,json=nullValue,def=0" json:"null_value,omitempty"` + // Indicate if the message partition key is set + NullPartitionKey *bool `protobuf:"varint,10,opt,name=null_partition_key,json=nullPartitionKey,def=0" json:"null_partition_key,omitempty"` +} + +// Default values for SingleMessageMetadata fields. +const ( + Default_SingleMessageMetadata_CompactedOut = bool(false) + Default_SingleMessageMetadata_EventTime = uint64(0) + Default_SingleMessageMetadata_PartitionKeyB64Encoded = bool(false) + Default_SingleMessageMetadata_NullValue = bool(false) + Default_SingleMessageMetadata_NullPartitionKey = bool(false) +) + +func (x *SingleMessageMetadata) Reset() { + *x = SingleMessageMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SingleMessageMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SingleMessageMetadata) ProtoMessage() {} + +func (x *SingleMessageMetadata) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SingleMessageMetadata.ProtoReflect.Descriptor instead. +func (*SingleMessageMetadata) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{7} +} + +func (x *SingleMessageMetadata) GetProperties() []*KeyValue { + if x != nil { + return x.Properties + } + return nil +} + +func (x *SingleMessageMetadata) GetPartitionKey() string { + if x != nil && x.PartitionKey != nil { + return *x.PartitionKey + } + return "" +} + +func (x *SingleMessageMetadata) GetPayloadSize() int32 { + if x != nil && x.PayloadSize != nil { + return *x.PayloadSize + } + return 0 +} + +func (x *SingleMessageMetadata) GetCompactedOut() bool { + if x != nil && x.CompactedOut != nil { + return *x.CompactedOut + } + return Default_SingleMessageMetadata_CompactedOut +} + +func (x *SingleMessageMetadata) GetEventTime() uint64 { + if x != nil && x.EventTime != nil { + return *x.EventTime + } + return Default_SingleMessageMetadata_EventTime +} + +func (x *SingleMessageMetadata) GetPartitionKeyB64Encoded() bool { + if x != nil && x.PartitionKeyB64Encoded != nil { + return *x.PartitionKeyB64Encoded + } + return Default_SingleMessageMetadata_PartitionKeyB64Encoded +} + +func (x *SingleMessageMetadata) GetOrderingKey() []byte { + if x != nil { + return x.OrderingKey + } + return nil +} + +func (x *SingleMessageMetadata) GetSequenceId() uint64 { + if x != nil && x.SequenceId != nil { + return *x.SequenceId + } + return 0 +} + +func (x *SingleMessageMetadata) GetNullValue() bool { + if x != nil && x.NullValue != nil { + return *x.NullValue + } + return Default_SingleMessageMetadata_NullValue +} + +func (x *SingleMessageMetadata) GetNullPartitionKey() bool { + if x != nil && x.NullPartitionKey != nil { + return *x.NullPartitionKey + } + return Default_SingleMessageMetadata_NullPartitionKey +} + +// metadata added for entry from broker +type BrokerEntryMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BrokerTimestamp *uint64 `protobuf:"varint,1,opt,name=broker_timestamp,json=brokerTimestamp" json:"broker_timestamp,omitempty"` + Index *uint64 `protobuf:"varint,2,opt,name=index" json:"index,omitempty"` +} + +func (x *BrokerEntryMetadata) Reset() { + *x = BrokerEntryMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BrokerEntryMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BrokerEntryMetadata) ProtoMessage() {} + +func (x *BrokerEntryMetadata) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BrokerEntryMetadata.ProtoReflect.Descriptor instead. +func (*BrokerEntryMetadata) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{8} +} + +func (x *BrokerEntryMetadata) GetBrokerTimestamp() uint64 { + if x != nil && x.BrokerTimestamp != nil { + return *x.BrokerTimestamp + } + return 0 +} + +func (x *BrokerEntryMetadata) GetIndex() uint64 { + if x != nil && x.Index != nil { + return *x.Index + } + return 0 +} + +type CommandConnect struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientVersion *string `protobuf:"bytes,1,req,name=client_version,json=clientVersion" json:"client_version,omitempty"` + AuthMethod *AuthMethod `protobuf:"varint,2,opt,name=auth_method,json=authMethod,enum=pulsar.proto.AuthMethod" json:"auth_method,omitempty"` // Deprecated. Use "auth_method_name" instead. + AuthMethodName *string `protobuf:"bytes,5,opt,name=auth_method_name,json=authMethodName" json:"auth_method_name,omitempty"` + AuthData []byte `protobuf:"bytes,3,opt,name=auth_data,json=authData" json:"auth_data,omitempty"` + ProtocolVersion *int32 `protobuf:"varint,4,opt,name=protocol_version,json=protocolVersion,def=0" json:"protocol_version,omitempty"` + // Client can ask to be proxyied to a specific broker + // This is only honored by a Pulsar proxy + ProxyToBrokerUrl *string `protobuf:"bytes,6,opt,name=proxy_to_broker_url,json=proxyToBrokerUrl" json:"proxy_to_broker_url,omitempty"` + // Original principal that was verified by + // a Pulsar proxy. In this case the auth info above + // will be the auth of the proxy itself + OriginalPrincipal *string `protobuf:"bytes,7,opt,name=original_principal,json=originalPrincipal" json:"original_principal,omitempty"` + // Original auth role and auth Method that was passed + // to the proxy. In this case the auth info above + // will be the auth of the proxy itself + OriginalAuthData *string `protobuf:"bytes,8,opt,name=original_auth_data,json=originalAuthData" json:"original_auth_data,omitempty"` + OriginalAuthMethod *string `protobuf:"bytes,9,opt,name=original_auth_method,json=originalAuthMethod" json:"original_auth_method,omitempty"` + // Feature flags + FeatureFlags *FeatureFlags `protobuf:"bytes,10,opt,name=feature_flags,json=featureFlags" json:"feature_flags,omitempty"` +} + +// Default values for CommandConnect fields. +const ( + Default_CommandConnect_ProtocolVersion = int32(0) +) + +func (x *CommandConnect) Reset() { + *x = CommandConnect{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandConnect) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandConnect) ProtoMessage() {} + +func (x *CommandConnect) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandConnect.ProtoReflect.Descriptor instead. +func (*CommandConnect) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{9} +} + +func (x *CommandConnect) GetClientVersion() string { + if x != nil && x.ClientVersion != nil { + return *x.ClientVersion + } + return "" +} + +func (x *CommandConnect) GetAuthMethod() AuthMethod { + if x != nil && x.AuthMethod != nil { + return *x.AuthMethod + } + return AuthMethod_AuthMethodNone +} + +func (x *CommandConnect) GetAuthMethodName() string { + if x != nil && x.AuthMethodName != nil { + return *x.AuthMethodName + } + return "" +} + +func (x *CommandConnect) GetAuthData() []byte { + if x != nil { + return x.AuthData + } + return nil +} + +func (x *CommandConnect) GetProtocolVersion() int32 { + if x != nil && x.ProtocolVersion != nil { + return *x.ProtocolVersion + } + return Default_CommandConnect_ProtocolVersion +} + +func (x *CommandConnect) GetProxyToBrokerUrl() string { + if x != nil && x.ProxyToBrokerUrl != nil { + return *x.ProxyToBrokerUrl + } + return "" +} + +func (x *CommandConnect) GetOriginalPrincipal() string { + if x != nil && x.OriginalPrincipal != nil { + return *x.OriginalPrincipal + } + return "" +} + +func (x *CommandConnect) GetOriginalAuthData() string { + if x != nil && x.OriginalAuthData != nil { + return *x.OriginalAuthData + } + return "" +} + +func (x *CommandConnect) GetOriginalAuthMethod() string { + if x != nil && x.OriginalAuthMethod != nil { + return *x.OriginalAuthMethod + } + return "" +} + +func (x *CommandConnect) GetFeatureFlags() *FeatureFlags { + if x != nil { + return x.FeatureFlags + } + return nil +} + +type FeatureFlags struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SupportsAuthRefresh *bool `protobuf:"varint,1,opt,name=supports_auth_refresh,json=supportsAuthRefresh,def=0" json:"supports_auth_refresh,omitempty"` + SupportsBrokerEntryMetadata *bool `protobuf:"varint,2,opt,name=supports_broker_entry_metadata,json=supportsBrokerEntryMetadata,def=0" json:"supports_broker_entry_metadata,omitempty"` + SupportsPartialProducer *bool `protobuf:"varint,3,opt,name=supports_partial_producer,json=supportsPartialProducer,def=0" json:"supports_partial_producer,omitempty"` + SupportsTopicWatchers *bool `protobuf:"varint,4,opt,name=supports_topic_watchers,json=supportsTopicWatchers,def=0" json:"supports_topic_watchers,omitempty"` +} + +// Default values for FeatureFlags fields. +const ( + Default_FeatureFlags_SupportsAuthRefresh = bool(false) + Default_FeatureFlags_SupportsBrokerEntryMetadata = bool(false) + Default_FeatureFlags_SupportsPartialProducer = bool(false) + Default_FeatureFlags_SupportsTopicWatchers = bool(false) +) + +func (x *FeatureFlags) Reset() { + *x = FeatureFlags{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FeatureFlags) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FeatureFlags) ProtoMessage() {} + +func (x *FeatureFlags) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FeatureFlags.ProtoReflect.Descriptor instead. +func (*FeatureFlags) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{10} +} + +func (x *FeatureFlags) GetSupportsAuthRefresh() bool { + if x != nil && x.SupportsAuthRefresh != nil { + return *x.SupportsAuthRefresh + } + return Default_FeatureFlags_SupportsAuthRefresh +} + +func (x *FeatureFlags) GetSupportsBrokerEntryMetadata() bool { + if x != nil && x.SupportsBrokerEntryMetadata != nil { + return *x.SupportsBrokerEntryMetadata + } + return Default_FeatureFlags_SupportsBrokerEntryMetadata +} + +func (x *FeatureFlags) GetSupportsPartialProducer() bool { + if x != nil && x.SupportsPartialProducer != nil { + return *x.SupportsPartialProducer + } + return Default_FeatureFlags_SupportsPartialProducer +} + +func (x *FeatureFlags) GetSupportsTopicWatchers() bool { + if x != nil && x.SupportsTopicWatchers != nil { + return *x.SupportsTopicWatchers + } + return Default_FeatureFlags_SupportsTopicWatchers +} + +type CommandConnected struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ServerVersion *string `protobuf:"bytes,1,req,name=server_version,json=serverVersion" json:"server_version,omitempty"` + ProtocolVersion *int32 `protobuf:"varint,2,opt,name=protocol_version,json=protocolVersion,def=0" json:"protocol_version,omitempty"` + MaxMessageSize *int32 `protobuf:"varint,3,opt,name=max_message_size,json=maxMessageSize" json:"max_message_size,omitempty"` + FeatureFlags *FeatureFlags `protobuf:"bytes,4,opt,name=feature_flags,json=featureFlags" json:"feature_flags,omitempty"` +} + +// Default values for CommandConnected fields. +const ( + Default_CommandConnected_ProtocolVersion = int32(0) +) + +func (x *CommandConnected) Reset() { + *x = CommandConnected{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandConnected) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandConnected) ProtoMessage() {} + +func (x *CommandConnected) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandConnected.ProtoReflect.Descriptor instead. +func (*CommandConnected) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{11} +} + +func (x *CommandConnected) GetServerVersion() string { + if x != nil && x.ServerVersion != nil { + return *x.ServerVersion + } + return "" +} + +func (x *CommandConnected) GetProtocolVersion() int32 { + if x != nil && x.ProtocolVersion != nil { + return *x.ProtocolVersion + } + return Default_CommandConnected_ProtocolVersion +} + +func (x *CommandConnected) GetMaxMessageSize() int32 { + if x != nil && x.MaxMessageSize != nil { + return *x.MaxMessageSize + } + return 0 +} + +func (x *CommandConnected) GetFeatureFlags() *FeatureFlags { + if x != nil { + return x.FeatureFlags + } + return nil +} + +type CommandAuthResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientVersion *string `protobuf:"bytes,1,opt,name=client_version,json=clientVersion" json:"client_version,omitempty"` + Response *AuthData `protobuf:"bytes,2,opt,name=response" json:"response,omitempty"` + ProtocolVersion *int32 `protobuf:"varint,3,opt,name=protocol_version,json=protocolVersion,def=0" json:"protocol_version,omitempty"` +} + +// Default values for CommandAuthResponse fields. +const ( + Default_CommandAuthResponse_ProtocolVersion = int32(0) +) + +func (x *CommandAuthResponse) Reset() { + *x = CommandAuthResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandAuthResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandAuthResponse) ProtoMessage() {} + +func (x *CommandAuthResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandAuthResponse.ProtoReflect.Descriptor instead. +func (*CommandAuthResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{12} +} + +func (x *CommandAuthResponse) GetClientVersion() string { + if x != nil && x.ClientVersion != nil { + return *x.ClientVersion + } + return "" +} + +func (x *CommandAuthResponse) GetResponse() *AuthData { + if x != nil { + return x.Response + } + return nil +} + +func (x *CommandAuthResponse) GetProtocolVersion() int32 { + if x != nil && x.ProtocolVersion != nil { + return *x.ProtocolVersion + } + return Default_CommandAuthResponse_ProtocolVersion +} + +type CommandAuthChallenge struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ServerVersion *string `protobuf:"bytes,1,opt,name=server_version,json=serverVersion" json:"server_version,omitempty"` + Challenge *AuthData `protobuf:"bytes,2,opt,name=challenge" json:"challenge,omitempty"` + ProtocolVersion *int32 `protobuf:"varint,3,opt,name=protocol_version,json=protocolVersion,def=0" json:"protocol_version,omitempty"` +} + +// Default values for CommandAuthChallenge fields. +const ( + Default_CommandAuthChallenge_ProtocolVersion = int32(0) +) + +func (x *CommandAuthChallenge) Reset() { + *x = CommandAuthChallenge{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandAuthChallenge) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandAuthChallenge) ProtoMessage() {} + +func (x *CommandAuthChallenge) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandAuthChallenge.ProtoReflect.Descriptor instead. +func (*CommandAuthChallenge) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{13} +} + +func (x *CommandAuthChallenge) GetServerVersion() string { + if x != nil && x.ServerVersion != nil { + return *x.ServerVersion + } + return "" +} + +func (x *CommandAuthChallenge) GetChallenge() *AuthData { + if x != nil { + return x.Challenge + } + return nil +} + +func (x *CommandAuthChallenge) GetProtocolVersion() int32 { + if x != nil && x.ProtocolVersion != nil { + return *x.ProtocolVersion + } + return Default_CommandAuthChallenge_ProtocolVersion +} + +// To support mutual authentication type, such as Sasl, reuse this command to mutual auth. +type AuthData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AuthMethodName *string `protobuf:"bytes,1,opt,name=auth_method_name,json=authMethodName" json:"auth_method_name,omitempty"` + AuthData []byte `protobuf:"bytes,2,opt,name=auth_data,json=authData" json:"auth_data,omitempty"` +} + +func (x *AuthData) Reset() { + *x = AuthData{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AuthData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthData) ProtoMessage() {} + +func (x *AuthData) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuthData.ProtoReflect.Descriptor instead. +func (*AuthData) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{14} +} + +func (x *AuthData) GetAuthMethodName() string { + if x != nil && x.AuthMethodName != nil { + return *x.AuthMethodName + } + return "" +} + +func (x *AuthData) GetAuthData() []byte { + if x != nil { + return x.AuthData + } + return nil +} + +type KeySharedMeta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + KeySharedMode *KeySharedMode `protobuf:"varint,1,req,name=keySharedMode,enum=pulsar.proto.KeySharedMode" json:"keySharedMode,omitempty"` + HashRanges []*IntRange `protobuf:"bytes,3,rep,name=hashRanges" json:"hashRanges,omitempty"` + AllowOutOfOrderDelivery *bool `protobuf:"varint,4,opt,name=allowOutOfOrderDelivery,def=0" json:"allowOutOfOrderDelivery,omitempty"` +} + +// Default values for KeySharedMeta fields. +const ( + Default_KeySharedMeta_AllowOutOfOrderDelivery = bool(false) +) + +func (x *KeySharedMeta) Reset() { + *x = KeySharedMeta{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *KeySharedMeta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*KeySharedMeta) ProtoMessage() {} + +func (x *KeySharedMeta) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use KeySharedMeta.ProtoReflect.Descriptor instead. +func (*KeySharedMeta) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{15} +} + +func (x *KeySharedMeta) GetKeySharedMode() KeySharedMode { + if x != nil && x.KeySharedMode != nil { + return *x.KeySharedMode + } + return KeySharedMode_AUTO_SPLIT +} + +func (x *KeySharedMeta) GetHashRanges() []*IntRange { + if x != nil { + return x.HashRanges + } + return nil +} + +func (x *KeySharedMeta) GetAllowOutOfOrderDelivery() bool { + if x != nil && x.AllowOutOfOrderDelivery != nil { + return *x.AllowOutOfOrderDelivery + } + return Default_KeySharedMeta_AllowOutOfOrderDelivery +} + +type CommandSubscribe struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Topic *string `protobuf:"bytes,1,req,name=topic" json:"topic,omitempty"` + Subscription *string `protobuf:"bytes,2,req,name=subscription" json:"subscription,omitempty"` + SubType *CommandSubscribe_SubType `protobuf:"varint,3,req,name=subType,enum=pulsar.proto.CommandSubscribe_SubType" json:"subType,omitempty"` + ConsumerId *uint64 `protobuf:"varint,4,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"` + RequestId *uint64 `protobuf:"varint,5,req,name=request_id,json=requestId" json:"request_id,omitempty"` + ConsumerName *string `protobuf:"bytes,6,opt,name=consumer_name,json=consumerName" json:"consumer_name,omitempty"` + PriorityLevel *int32 `protobuf:"varint,7,opt,name=priority_level,json=priorityLevel" json:"priority_level,omitempty"` + // Signal wether the subscription should be backed by a + // durable cursor or not + Durable *bool `protobuf:"varint,8,opt,name=durable,def=1" json:"durable,omitempty"` + // If specified, the subscription will position the cursor + // markd-delete position on the particular message id and + // will send messages from that point + StartMessageId *MessageIdData `protobuf:"bytes,9,opt,name=start_message_id,json=startMessageId" json:"start_message_id,omitempty"` + /// Add optional metadata key=value to this consumer + Metadata []*KeyValue `protobuf:"bytes,10,rep,name=metadata" json:"metadata,omitempty"` + ReadCompacted *bool `protobuf:"varint,11,opt,name=read_compacted,json=readCompacted" json:"read_compacted,omitempty"` + Schema *Schema `protobuf:"bytes,12,opt,name=schema" json:"schema,omitempty"` + // Signal whether the subscription will initialize on latest + // or not -- earliest + InitialPosition *CommandSubscribe_InitialPosition `protobuf:"varint,13,opt,name=initialPosition,enum=pulsar.proto.CommandSubscribe_InitialPosition,def=0" json:"initialPosition,omitempty"` + // Mark the subscription as "replicated". Pulsar will make sure + // to periodically sync the state of replicated subscriptions + // across different clusters (when using geo-replication). + ReplicateSubscriptionState *bool `protobuf:"varint,14,opt,name=replicate_subscription_state,json=replicateSubscriptionState" json:"replicate_subscription_state,omitempty"` + // If true, the subscribe operation will cause a topic to be + // created if it does not exist already (and if topic auto-creation + // is allowed by broker. + // If false, the subscribe operation will fail if the topic + // does not exist. + ForceTopicCreation *bool `protobuf:"varint,15,opt,name=force_topic_creation,json=forceTopicCreation,def=1" json:"force_topic_creation,omitempty"` + // If specified, the subscription will reset cursor's position back + // to specified seconds and will send messages from that point + StartMessageRollbackDurationSec *uint64 `protobuf:"varint,16,opt,name=start_message_rollback_duration_sec,json=startMessageRollbackDurationSec,def=0" json:"start_message_rollback_duration_sec,omitempty"` + KeySharedMeta *KeySharedMeta `protobuf:"bytes,17,opt,name=keySharedMeta" json:"keySharedMeta,omitempty"` + SubscriptionProperties []*KeyValue `protobuf:"bytes,18,rep,name=subscription_properties,json=subscriptionProperties" json:"subscription_properties,omitempty"` + // The consumer epoch, when exclusive and failover consumer redeliver unack message will increase the epoch + ConsumerEpoch *uint64 `protobuf:"varint,19,opt,name=consumer_epoch,json=consumerEpoch" json:"consumer_epoch,omitempty"` +} + +// Default values for CommandSubscribe fields. +const ( + Default_CommandSubscribe_Durable = bool(true) + Default_CommandSubscribe_InitialPosition = CommandSubscribe_Latest + Default_CommandSubscribe_ForceTopicCreation = bool(true) + Default_CommandSubscribe_StartMessageRollbackDurationSec = uint64(0) +) + +func (x *CommandSubscribe) Reset() { + *x = CommandSubscribe{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandSubscribe) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandSubscribe) ProtoMessage() {} + +func (x *CommandSubscribe) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandSubscribe.ProtoReflect.Descriptor instead. +func (*CommandSubscribe) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{16} +} + +func (x *CommandSubscribe) GetTopic() string { + if x != nil && x.Topic != nil { + return *x.Topic + } + return "" +} + +func (x *CommandSubscribe) GetSubscription() string { + if x != nil && x.Subscription != nil { + return *x.Subscription + } + return "" +} + +func (x *CommandSubscribe) GetSubType() CommandSubscribe_SubType { + if x != nil && x.SubType != nil { + return *x.SubType + } + return CommandSubscribe_Exclusive +} + +func (x *CommandSubscribe) GetConsumerId() uint64 { + if x != nil && x.ConsumerId != nil { + return *x.ConsumerId + } + return 0 +} + +func (x *CommandSubscribe) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandSubscribe) GetConsumerName() string { + if x != nil && x.ConsumerName != nil { + return *x.ConsumerName + } + return "" +} + +func (x *CommandSubscribe) GetPriorityLevel() int32 { + if x != nil && x.PriorityLevel != nil { + return *x.PriorityLevel + } + return 0 +} + +func (x *CommandSubscribe) GetDurable() bool { + if x != nil && x.Durable != nil { + return *x.Durable + } + return Default_CommandSubscribe_Durable +} + +func (x *CommandSubscribe) GetStartMessageId() *MessageIdData { + if x != nil { + return x.StartMessageId + } + return nil +} + +func (x *CommandSubscribe) GetMetadata() []*KeyValue { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *CommandSubscribe) GetReadCompacted() bool { + if x != nil && x.ReadCompacted != nil { + return *x.ReadCompacted + } + return false +} + +func (x *CommandSubscribe) GetSchema() *Schema { + if x != nil { + return x.Schema + } + return nil +} + +func (x *CommandSubscribe) GetInitialPosition() CommandSubscribe_InitialPosition { + if x != nil && x.InitialPosition != nil { + return *x.InitialPosition + } + return Default_CommandSubscribe_InitialPosition +} + +func (x *CommandSubscribe) GetReplicateSubscriptionState() bool { + if x != nil && x.ReplicateSubscriptionState != nil { + return *x.ReplicateSubscriptionState + } + return false +} + +func (x *CommandSubscribe) GetForceTopicCreation() bool { + if x != nil && x.ForceTopicCreation != nil { + return *x.ForceTopicCreation + } + return Default_CommandSubscribe_ForceTopicCreation +} + +func (x *CommandSubscribe) GetStartMessageRollbackDurationSec() uint64 { + if x != nil && x.StartMessageRollbackDurationSec != nil { + return *x.StartMessageRollbackDurationSec + } + return Default_CommandSubscribe_StartMessageRollbackDurationSec +} + +func (x *CommandSubscribe) GetKeySharedMeta() *KeySharedMeta { + if x != nil { + return x.KeySharedMeta + } + return nil +} + +func (x *CommandSubscribe) GetSubscriptionProperties() []*KeyValue { + if x != nil { + return x.SubscriptionProperties + } + return nil +} + +func (x *CommandSubscribe) GetConsumerEpoch() uint64 { + if x != nil && x.ConsumerEpoch != nil { + return *x.ConsumerEpoch + } + return 0 +} + +type CommandPartitionedTopicMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Topic *string `protobuf:"bytes,1,req,name=topic" json:"topic,omitempty"` + RequestId *uint64 `protobuf:"varint,2,req,name=request_id,json=requestId" json:"request_id,omitempty"` + // TODO - Remove original_principal, original_auth_data, original_auth_method + // Original principal that was verified by + // a Pulsar proxy. + OriginalPrincipal *string `protobuf:"bytes,3,opt,name=original_principal,json=originalPrincipal" json:"original_principal,omitempty"` + // Original auth role and auth Method that was passed + // to the proxy. + OriginalAuthData *string `protobuf:"bytes,4,opt,name=original_auth_data,json=originalAuthData" json:"original_auth_data,omitempty"` + OriginalAuthMethod *string `protobuf:"bytes,5,opt,name=original_auth_method,json=originalAuthMethod" json:"original_auth_method,omitempty"` +} + +func (x *CommandPartitionedTopicMetadata) Reset() { + *x = CommandPartitionedTopicMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandPartitionedTopicMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandPartitionedTopicMetadata) ProtoMessage() {} + +func (x *CommandPartitionedTopicMetadata) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandPartitionedTopicMetadata.ProtoReflect.Descriptor instead. +func (*CommandPartitionedTopicMetadata) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{17} +} + +func (x *CommandPartitionedTopicMetadata) GetTopic() string { + if x != nil && x.Topic != nil { + return *x.Topic + } + return "" +} + +func (x *CommandPartitionedTopicMetadata) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandPartitionedTopicMetadata) GetOriginalPrincipal() string { + if x != nil && x.OriginalPrincipal != nil { + return *x.OriginalPrincipal + } + return "" +} + +func (x *CommandPartitionedTopicMetadata) GetOriginalAuthData() string { + if x != nil && x.OriginalAuthData != nil { + return *x.OriginalAuthData + } + return "" +} + +func (x *CommandPartitionedTopicMetadata) GetOriginalAuthMethod() string { + if x != nil && x.OriginalAuthMethod != nil { + return *x.OriginalAuthMethod + } + return "" +} + +type CommandPartitionedTopicMetadataResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Partitions *uint32 `protobuf:"varint,1,opt,name=partitions" json:"partitions,omitempty"` // Optional in case of error + RequestId *uint64 `protobuf:"varint,2,req,name=request_id,json=requestId" json:"request_id,omitempty"` + Response *CommandPartitionedTopicMetadataResponse_LookupType `protobuf:"varint,3,opt,name=response,enum=pulsar.proto.CommandPartitionedTopicMetadataResponse_LookupType" json:"response,omitempty"` + Error *ServerError `protobuf:"varint,4,opt,name=error,enum=pulsar.proto.ServerError" json:"error,omitempty"` + Message *string `protobuf:"bytes,5,opt,name=message" json:"message,omitempty"` +} + +func (x *CommandPartitionedTopicMetadataResponse) Reset() { + *x = CommandPartitionedTopicMetadataResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandPartitionedTopicMetadataResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandPartitionedTopicMetadataResponse) ProtoMessage() {} + +func (x *CommandPartitionedTopicMetadataResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandPartitionedTopicMetadataResponse.ProtoReflect.Descriptor instead. +func (*CommandPartitionedTopicMetadataResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{18} +} + +func (x *CommandPartitionedTopicMetadataResponse) GetPartitions() uint32 { + if x != nil && x.Partitions != nil { + return *x.Partitions + } + return 0 +} + +func (x *CommandPartitionedTopicMetadataResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandPartitionedTopicMetadataResponse) GetResponse() CommandPartitionedTopicMetadataResponse_LookupType { + if x != nil && x.Response != nil { + return *x.Response + } + return CommandPartitionedTopicMetadataResponse_Success +} + +func (x *CommandPartitionedTopicMetadataResponse) GetError() ServerError { + if x != nil && x.Error != nil { + return *x.Error + } + return ServerError_UnknownError +} + +func (x *CommandPartitionedTopicMetadataResponse) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message + } + return "" +} + +type CommandLookupTopic struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Topic *string `protobuf:"bytes,1,req,name=topic" json:"topic,omitempty"` + RequestId *uint64 `protobuf:"varint,2,req,name=request_id,json=requestId" json:"request_id,omitempty"` + Authoritative *bool `protobuf:"varint,3,opt,name=authoritative,def=0" json:"authoritative,omitempty"` + // TODO - Remove original_principal, original_auth_data, original_auth_method + // Original principal that was verified by + // a Pulsar proxy. + OriginalPrincipal *string `protobuf:"bytes,4,opt,name=original_principal,json=originalPrincipal" json:"original_principal,omitempty"` + // Original auth role and auth Method that was passed + // to the proxy. + OriginalAuthData *string `protobuf:"bytes,5,opt,name=original_auth_data,json=originalAuthData" json:"original_auth_data,omitempty"` + OriginalAuthMethod *string `protobuf:"bytes,6,opt,name=original_auth_method,json=originalAuthMethod" json:"original_auth_method,omitempty"` + // + AdvertisedListenerName *string `protobuf:"bytes,7,opt,name=advertised_listener_name,json=advertisedListenerName" json:"advertised_listener_name,omitempty"` +} + +// Default values for CommandLookupTopic fields. +const ( + Default_CommandLookupTopic_Authoritative = bool(false) +) + +func (x *CommandLookupTopic) Reset() { + *x = CommandLookupTopic{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandLookupTopic) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandLookupTopic) ProtoMessage() {} + +func (x *CommandLookupTopic) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandLookupTopic.ProtoReflect.Descriptor instead. +func (*CommandLookupTopic) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{19} +} + +func (x *CommandLookupTopic) GetTopic() string { + if x != nil && x.Topic != nil { + return *x.Topic + } + return "" +} + +func (x *CommandLookupTopic) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandLookupTopic) GetAuthoritative() bool { + if x != nil && x.Authoritative != nil { + return *x.Authoritative + } + return Default_CommandLookupTopic_Authoritative +} + +func (x *CommandLookupTopic) GetOriginalPrincipal() string { + if x != nil && x.OriginalPrincipal != nil { + return *x.OriginalPrincipal + } + return "" +} + +func (x *CommandLookupTopic) GetOriginalAuthData() string { + if x != nil && x.OriginalAuthData != nil { + return *x.OriginalAuthData + } + return "" +} + +func (x *CommandLookupTopic) GetOriginalAuthMethod() string { + if x != nil && x.OriginalAuthMethod != nil { + return *x.OriginalAuthMethod + } + return "" +} + +func (x *CommandLookupTopic) GetAdvertisedListenerName() string { + if x != nil && x.AdvertisedListenerName != nil { + return *x.AdvertisedListenerName + } + return "" +} + +type CommandLookupTopicResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BrokerServiceUrl *string `protobuf:"bytes,1,opt,name=brokerServiceUrl" json:"brokerServiceUrl,omitempty"` // Optional in case of error + BrokerServiceUrlTls *string `protobuf:"bytes,2,opt,name=brokerServiceUrlTls" json:"brokerServiceUrlTls,omitempty"` + Response *CommandLookupTopicResponse_LookupType `protobuf:"varint,3,opt,name=response,enum=pulsar.proto.CommandLookupTopicResponse_LookupType" json:"response,omitempty"` + RequestId *uint64 `protobuf:"varint,4,req,name=request_id,json=requestId" json:"request_id,omitempty"` + Authoritative *bool `protobuf:"varint,5,opt,name=authoritative,def=0" json:"authoritative,omitempty"` + Error *ServerError `protobuf:"varint,6,opt,name=error,enum=pulsar.proto.ServerError" json:"error,omitempty"` + Message *string `protobuf:"bytes,7,opt,name=message" json:"message,omitempty"` + // If it's true, indicates to the client that it must + // always connect through the service url after the + // lookup has been completed. + ProxyThroughServiceUrl *bool `protobuf:"varint,8,opt,name=proxy_through_service_url,json=proxyThroughServiceUrl,def=0" json:"proxy_through_service_url,omitempty"` +} + +// Default values for CommandLookupTopicResponse fields. +const ( + Default_CommandLookupTopicResponse_Authoritative = bool(false) + Default_CommandLookupTopicResponse_ProxyThroughServiceUrl = bool(false) +) + +func (x *CommandLookupTopicResponse) Reset() { + *x = CommandLookupTopicResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandLookupTopicResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandLookupTopicResponse) ProtoMessage() {} + +func (x *CommandLookupTopicResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandLookupTopicResponse.ProtoReflect.Descriptor instead. +func (*CommandLookupTopicResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{20} +} + +func (x *CommandLookupTopicResponse) GetBrokerServiceUrl() string { + if x != nil && x.BrokerServiceUrl != nil { + return *x.BrokerServiceUrl + } + return "" +} + +func (x *CommandLookupTopicResponse) GetBrokerServiceUrlTls() string { + if x != nil && x.BrokerServiceUrlTls != nil { + return *x.BrokerServiceUrlTls + } + return "" +} + +func (x *CommandLookupTopicResponse) GetResponse() CommandLookupTopicResponse_LookupType { + if x != nil && x.Response != nil { + return *x.Response + } + return CommandLookupTopicResponse_Redirect +} + +func (x *CommandLookupTopicResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandLookupTopicResponse) GetAuthoritative() bool { + if x != nil && x.Authoritative != nil { + return *x.Authoritative + } + return Default_CommandLookupTopicResponse_Authoritative +} + +func (x *CommandLookupTopicResponse) GetError() ServerError { + if x != nil && x.Error != nil { + return *x.Error + } + return ServerError_UnknownError +} + +func (x *CommandLookupTopicResponse) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message + } + return "" +} + +func (x *CommandLookupTopicResponse) GetProxyThroughServiceUrl() bool { + if x != nil && x.ProxyThroughServiceUrl != nil { + return *x.ProxyThroughServiceUrl + } + return Default_CommandLookupTopicResponse_ProxyThroughServiceUrl +} + +/// Create a new Producer on a topic, assigning the given producer_id, +/// all messages sent with this producer_id will be persisted on the topic +type CommandProducer struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Topic *string `protobuf:"bytes,1,req,name=topic" json:"topic,omitempty"` + ProducerId *uint64 `protobuf:"varint,2,req,name=producer_id,json=producerId" json:"producer_id,omitempty"` + RequestId *uint64 `protobuf:"varint,3,req,name=request_id,json=requestId" json:"request_id,omitempty"` + /// If a producer name is specified, the name will be used, + /// otherwise the broker will generate a unique name + ProducerName *string `protobuf:"bytes,4,opt,name=producer_name,json=producerName" json:"producer_name,omitempty"` + Encrypted *bool `protobuf:"varint,5,opt,name=encrypted,def=0" json:"encrypted,omitempty"` + /// Add optional metadata key=value to this producer + Metadata []*KeyValue `protobuf:"bytes,6,rep,name=metadata" json:"metadata,omitempty"` + Schema *Schema `protobuf:"bytes,7,opt,name=schema" json:"schema,omitempty"` + // If producer reconnect to broker, the epoch of this producer will +1 + Epoch *uint64 `protobuf:"varint,8,opt,name=epoch,def=0" json:"epoch,omitempty"` + // Indicate the name of the producer is generated or user provided + // Use default true here is in order to be forward compatible with the client + UserProvidedProducerName *bool `protobuf:"varint,9,opt,name=user_provided_producer_name,json=userProvidedProducerName,def=1" json:"user_provided_producer_name,omitempty"` + // Require that this producers will be the only producer allowed on the topic + ProducerAccessMode *ProducerAccessMode `protobuf:"varint,10,opt,name=producer_access_mode,json=producerAccessMode,enum=pulsar.proto.ProducerAccessMode,def=0" json:"producer_access_mode,omitempty"` + // Topic epoch is used to fence off producers that reconnects after a new + // exclusive producer has already taken over. This id is assigned by the + // broker on the CommandProducerSuccess. The first time, the client will + // leave it empty and then it will always carry the same epoch number on + // the subsequent reconnections. + TopicEpoch *uint64 `protobuf:"varint,11,opt,name=topic_epoch,json=topicEpoch" json:"topic_epoch,omitempty"` + TxnEnabled *bool `protobuf:"varint,12,opt,name=txn_enabled,json=txnEnabled,def=0" json:"txn_enabled,omitempty"` + // Name of the initial subscription of the topic. + // If this field is not set, the initial subscription will not be created. + // If this field is set but the broker's `allowAutoSubscriptionCreation` + // is disabled, the producer will fail to be created. + InitialSubscriptionName *string `protobuf:"bytes,13,opt,name=initial_subscription_name,json=initialSubscriptionName" json:"initial_subscription_name,omitempty"` +} + +// Default values for CommandProducer fields. +const ( + Default_CommandProducer_Encrypted = bool(false) + Default_CommandProducer_Epoch = uint64(0) + Default_CommandProducer_UserProvidedProducerName = bool(true) + Default_CommandProducer_ProducerAccessMode = ProducerAccessMode_Shared + Default_CommandProducer_TxnEnabled = bool(false) +) + +func (x *CommandProducer) Reset() { + *x = CommandProducer{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandProducer) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandProducer) ProtoMessage() {} + +func (x *CommandProducer) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandProducer.ProtoReflect.Descriptor instead. +func (*CommandProducer) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{21} +} + +func (x *CommandProducer) GetTopic() string { + if x != nil && x.Topic != nil { + return *x.Topic + } + return "" +} + +func (x *CommandProducer) GetProducerId() uint64 { + if x != nil && x.ProducerId != nil { + return *x.ProducerId + } + return 0 +} + +func (x *CommandProducer) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandProducer) GetProducerName() string { + if x != nil && x.ProducerName != nil { + return *x.ProducerName + } + return "" +} + +func (x *CommandProducer) GetEncrypted() bool { + if x != nil && x.Encrypted != nil { + return *x.Encrypted + } + return Default_CommandProducer_Encrypted +} + +func (x *CommandProducer) GetMetadata() []*KeyValue { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *CommandProducer) GetSchema() *Schema { + if x != nil { + return x.Schema + } + return nil +} + +func (x *CommandProducer) GetEpoch() uint64 { + if x != nil && x.Epoch != nil { + return *x.Epoch + } + return Default_CommandProducer_Epoch +} + +func (x *CommandProducer) GetUserProvidedProducerName() bool { + if x != nil && x.UserProvidedProducerName != nil { + return *x.UserProvidedProducerName + } + return Default_CommandProducer_UserProvidedProducerName +} + +func (x *CommandProducer) GetProducerAccessMode() ProducerAccessMode { + if x != nil && x.ProducerAccessMode != nil { + return *x.ProducerAccessMode + } + return Default_CommandProducer_ProducerAccessMode +} + +func (x *CommandProducer) GetTopicEpoch() uint64 { + if x != nil && x.TopicEpoch != nil { + return *x.TopicEpoch + } + return 0 +} + +func (x *CommandProducer) GetTxnEnabled() bool { + if x != nil && x.TxnEnabled != nil { + return *x.TxnEnabled + } + return Default_CommandProducer_TxnEnabled +} + +func (x *CommandProducer) GetInitialSubscriptionName() string { + if x != nil && x.InitialSubscriptionName != nil { + return *x.InitialSubscriptionName + } + return "" +} + +type CommandSend struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProducerId *uint64 `protobuf:"varint,1,req,name=producer_id,json=producerId" json:"producer_id,omitempty"` + SequenceId *uint64 `protobuf:"varint,2,req,name=sequence_id,json=sequenceId" json:"sequence_id,omitempty"` + NumMessages *int32 `protobuf:"varint,3,opt,name=num_messages,json=numMessages,def=1" json:"num_messages,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,4,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,5,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + /// Add highest sequence id to support batch message with external sequence id + HighestSequenceId *uint64 `protobuf:"varint,6,opt,name=highest_sequence_id,json=highestSequenceId,def=0" json:"highest_sequence_id,omitempty"` + IsChunk *bool `protobuf:"varint,7,opt,name=is_chunk,json=isChunk,def=0" json:"is_chunk,omitempty"` + // Specify if the message being published is a Pulsar marker or not + Marker *bool `protobuf:"varint,8,opt,name=marker,def=0" json:"marker,omitempty"` + // Message id of this message, currently is used in replicator for shadow topic. + MessageId *MessageIdData `protobuf:"bytes,9,opt,name=message_id,json=messageId" json:"message_id,omitempty"` +} + +// Default values for CommandSend fields. +const ( + Default_CommandSend_NumMessages = int32(1) + Default_CommandSend_TxnidLeastBits = uint64(0) + Default_CommandSend_TxnidMostBits = uint64(0) + Default_CommandSend_HighestSequenceId = uint64(0) + Default_CommandSend_IsChunk = bool(false) + Default_CommandSend_Marker = bool(false) +) + +func (x *CommandSend) Reset() { + *x = CommandSend{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandSend) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandSend) ProtoMessage() {} + +func (x *CommandSend) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandSend.ProtoReflect.Descriptor instead. +func (*CommandSend) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{22} +} + +func (x *CommandSend) GetProducerId() uint64 { + if x != nil && x.ProducerId != nil { + return *x.ProducerId + } + return 0 +} + +func (x *CommandSend) GetSequenceId() uint64 { + if x != nil && x.SequenceId != nil { + return *x.SequenceId + } + return 0 +} + +func (x *CommandSend) GetNumMessages() int32 { + if x != nil && x.NumMessages != nil { + return *x.NumMessages + } + return Default_CommandSend_NumMessages +} + +func (x *CommandSend) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandSend_TxnidLeastBits +} + +func (x *CommandSend) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandSend_TxnidMostBits +} + +func (x *CommandSend) GetHighestSequenceId() uint64 { + if x != nil && x.HighestSequenceId != nil { + return *x.HighestSequenceId + } + return Default_CommandSend_HighestSequenceId +} + +func (x *CommandSend) GetIsChunk() bool { + if x != nil && x.IsChunk != nil { + return *x.IsChunk + } + return Default_CommandSend_IsChunk +} + +func (x *CommandSend) GetMarker() bool { + if x != nil && x.Marker != nil { + return *x.Marker + } + return Default_CommandSend_Marker +} + +func (x *CommandSend) GetMessageId() *MessageIdData { + if x != nil { + return x.MessageId + } + return nil +} + +type CommandSendReceipt struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProducerId *uint64 `protobuf:"varint,1,req,name=producer_id,json=producerId" json:"producer_id,omitempty"` + SequenceId *uint64 `protobuf:"varint,2,req,name=sequence_id,json=sequenceId" json:"sequence_id,omitempty"` + MessageId *MessageIdData `protobuf:"bytes,3,opt,name=message_id,json=messageId" json:"message_id,omitempty"` + HighestSequenceId *uint64 `protobuf:"varint,4,opt,name=highest_sequence_id,json=highestSequenceId,def=0" json:"highest_sequence_id,omitempty"` +} + +// Default values for CommandSendReceipt fields. +const ( + Default_CommandSendReceipt_HighestSequenceId = uint64(0) +) + +func (x *CommandSendReceipt) Reset() { + *x = CommandSendReceipt{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandSendReceipt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandSendReceipt) ProtoMessage() {} + +func (x *CommandSendReceipt) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandSendReceipt.ProtoReflect.Descriptor instead. +func (*CommandSendReceipt) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{23} +} + +func (x *CommandSendReceipt) GetProducerId() uint64 { + if x != nil && x.ProducerId != nil { + return *x.ProducerId + } + return 0 +} + +func (x *CommandSendReceipt) GetSequenceId() uint64 { + if x != nil && x.SequenceId != nil { + return *x.SequenceId + } + return 0 +} + +func (x *CommandSendReceipt) GetMessageId() *MessageIdData { + if x != nil { + return x.MessageId + } + return nil +} + +func (x *CommandSendReceipt) GetHighestSequenceId() uint64 { + if x != nil && x.HighestSequenceId != nil { + return *x.HighestSequenceId + } + return Default_CommandSendReceipt_HighestSequenceId +} + +type CommandSendError struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProducerId *uint64 `protobuf:"varint,1,req,name=producer_id,json=producerId" json:"producer_id,omitempty"` + SequenceId *uint64 `protobuf:"varint,2,req,name=sequence_id,json=sequenceId" json:"sequence_id,omitempty"` + Error *ServerError `protobuf:"varint,3,req,name=error,enum=pulsar.proto.ServerError" json:"error,omitempty"` + Message *string `protobuf:"bytes,4,req,name=message" json:"message,omitempty"` +} + +func (x *CommandSendError) Reset() { + *x = CommandSendError{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandSendError) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandSendError) ProtoMessage() {} + +func (x *CommandSendError) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandSendError.ProtoReflect.Descriptor instead. +func (*CommandSendError) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{24} +} + +func (x *CommandSendError) GetProducerId() uint64 { + if x != nil && x.ProducerId != nil { + return *x.ProducerId + } + return 0 +} + +func (x *CommandSendError) GetSequenceId() uint64 { + if x != nil && x.SequenceId != nil { + return *x.SequenceId + } + return 0 +} + +func (x *CommandSendError) GetError() ServerError { + if x != nil && x.Error != nil { + return *x.Error + } + return ServerError_UnknownError +} + +func (x *CommandSendError) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message + } + return "" +} + +type CommandMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConsumerId *uint64 `protobuf:"varint,1,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"` + MessageId *MessageIdData `protobuf:"bytes,2,req,name=message_id,json=messageId" json:"message_id,omitempty"` + RedeliveryCount *uint32 `protobuf:"varint,3,opt,name=redelivery_count,json=redeliveryCount,def=0" json:"redelivery_count,omitempty"` + AckSet []int64 `protobuf:"varint,4,rep,name=ack_set,json=ackSet" json:"ack_set,omitempty"` + ConsumerEpoch *uint64 `protobuf:"varint,5,opt,name=consumer_epoch,json=consumerEpoch" json:"consumer_epoch,omitempty"` +} + +// Default values for CommandMessage fields. +const ( + Default_CommandMessage_RedeliveryCount = uint32(0) +) + +func (x *CommandMessage) Reset() { + *x = CommandMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandMessage) ProtoMessage() {} + +func (x *CommandMessage) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandMessage.ProtoReflect.Descriptor instead. +func (*CommandMessage) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{25} +} + +func (x *CommandMessage) GetConsumerId() uint64 { + if x != nil && x.ConsumerId != nil { + return *x.ConsumerId + } + return 0 +} + +func (x *CommandMessage) GetMessageId() *MessageIdData { + if x != nil { + return x.MessageId + } + return nil +} + +func (x *CommandMessage) GetRedeliveryCount() uint32 { + if x != nil && x.RedeliveryCount != nil { + return *x.RedeliveryCount + } + return Default_CommandMessage_RedeliveryCount +} + +func (x *CommandMessage) GetAckSet() []int64 { + if x != nil { + return x.AckSet + } + return nil +} + +func (x *CommandMessage) GetConsumerEpoch() uint64 { + if x != nil && x.ConsumerEpoch != nil { + return *x.ConsumerEpoch + } + return 0 +} + +type CommandAck struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConsumerId *uint64 `protobuf:"varint,1,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"` + AckType *CommandAck_AckType `protobuf:"varint,2,req,name=ack_type,json=ackType,enum=pulsar.proto.CommandAck_AckType" json:"ack_type,omitempty"` + // In case of individual acks, the client can pass a list of message ids + MessageId []*MessageIdData `protobuf:"bytes,3,rep,name=message_id,json=messageId" json:"message_id,omitempty"` + ValidationError *CommandAck_ValidationError `protobuf:"varint,4,opt,name=validation_error,json=validationError,enum=pulsar.proto.CommandAck_ValidationError" json:"validation_error,omitempty"` + Properties []*KeyLongValue `protobuf:"bytes,5,rep,name=properties" json:"properties,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,6,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,7,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + RequestId *uint64 `protobuf:"varint,8,opt,name=request_id,json=requestId" json:"request_id,omitempty"` +} + +// Default values for CommandAck fields. +const ( + Default_CommandAck_TxnidLeastBits = uint64(0) + Default_CommandAck_TxnidMostBits = uint64(0) +) + +func (x *CommandAck) Reset() { + *x = CommandAck{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandAck) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandAck) ProtoMessage() {} + +func (x *CommandAck) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandAck.ProtoReflect.Descriptor instead. +func (*CommandAck) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{26} +} + +func (x *CommandAck) GetConsumerId() uint64 { + if x != nil && x.ConsumerId != nil { + return *x.ConsumerId + } + return 0 +} + +func (x *CommandAck) GetAckType() CommandAck_AckType { + if x != nil && x.AckType != nil { + return *x.AckType + } + return CommandAck_Individual +} + +func (x *CommandAck) GetMessageId() []*MessageIdData { + if x != nil { + return x.MessageId + } + return nil +} + +func (x *CommandAck) GetValidationError() CommandAck_ValidationError { + if x != nil && x.ValidationError != nil { + return *x.ValidationError + } + return CommandAck_UncompressedSizeCorruption +} + +func (x *CommandAck) GetProperties() []*KeyLongValue { + if x != nil { + return x.Properties + } + return nil +} + +func (x *CommandAck) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandAck_TxnidLeastBits +} + +func (x *CommandAck) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandAck_TxnidMostBits +} + +func (x *CommandAck) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +type CommandAckResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConsumerId *uint64 `protobuf:"varint,1,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,2,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,3,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + Error *ServerError `protobuf:"varint,4,opt,name=error,enum=pulsar.proto.ServerError" json:"error,omitempty"` + Message *string `protobuf:"bytes,5,opt,name=message" json:"message,omitempty"` + RequestId *uint64 `protobuf:"varint,6,opt,name=request_id,json=requestId" json:"request_id,omitempty"` +} + +// Default values for CommandAckResponse fields. +const ( + Default_CommandAckResponse_TxnidLeastBits = uint64(0) + Default_CommandAckResponse_TxnidMostBits = uint64(0) +) + +func (x *CommandAckResponse) Reset() { + *x = CommandAckResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandAckResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandAckResponse) ProtoMessage() {} + +func (x *CommandAckResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandAckResponse.ProtoReflect.Descriptor instead. +func (*CommandAckResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{27} +} + +func (x *CommandAckResponse) GetConsumerId() uint64 { + if x != nil && x.ConsumerId != nil { + return *x.ConsumerId + } + return 0 +} + +func (x *CommandAckResponse) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandAckResponse_TxnidLeastBits +} + +func (x *CommandAckResponse) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandAckResponse_TxnidMostBits +} + +func (x *CommandAckResponse) GetError() ServerError { + if x != nil && x.Error != nil { + return *x.Error + } + return ServerError_UnknownError +} + +func (x *CommandAckResponse) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message + } + return "" +} + +func (x *CommandAckResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +// changes on active consumer +type CommandActiveConsumerChange struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConsumerId *uint64 `protobuf:"varint,1,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"` + IsActive *bool `protobuf:"varint,2,opt,name=is_active,json=isActive,def=0" json:"is_active,omitempty"` +} + +// Default values for CommandActiveConsumerChange fields. +const ( + Default_CommandActiveConsumerChange_IsActive = bool(false) +) + +func (x *CommandActiveConsumerChange) Reset() { + *x = CommandActiveConsumerChange{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandActiveConsumerChange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandActiveConsumerChange) ProtoMessage() {} + +func (x *CommandActiveConsumerChange) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandActiveConsumerChange.ProtoReflect.Descriptor instead. +func (*CommandActiveConsumerChange) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{28} +} + +func (x *CommandActiveConsumerChange) GetConsumerId() uint64 { + if x != nil && x.ConsumerId != nil { + return *x.ConsumerId + } + return 0 +} + +func (x *CommandActiveConsumerChange) GetIsActive() bool { + if x != nil && x.IsActive != nil { + return *x.IsActive + } + return Default_CommandActiveConsumerChange_IsActive +} + +type CommandFlow struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConsumerId *uint64 `protobuf:"varint,1,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"` + // Max number of messages to prefetch, in addition + // of any number previously specified + MessagePermits *uint32 `protobuf:"varint,2,req,name=messagePermits" json:"messagePermits,omitempty"` +} + +func (x *CommandFlow) Reset() { + *x = CommandFlow{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandFlow) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandFlow) ProtoMessage() {} + +func (x *CommandFlow) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandFlow.ProtoReflect.Descriptor instead. +func (*CommandFlow) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{29} +} + +func (x *CommandFlow) GetConsumerId() uint64 { + if x != nil && x.ConsumerId != nil { + return *x.ConsumerId + } + return 0 +} + +func (x *CommandFlow) GetMessagePermits() uint32 { + if x != nil && x.MessagePermits != nil { + return *x.MessagePermits + } + return 0 +} + +type CommandUnsubscribe struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConsumerId *uint64 `protobuf:"varint,1,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"` + RequestId *uint64 `protobuf:"varint,2,req,name=request_id,json=requestId" json:"request_id,omitempty"` +} + +func (x *CommandUnsubscribe) Reset() { + *x = CommandUnsubscribe{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandUnsubscribe) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandUnsubscribe) ProtoMessage() {} + +func (x *CommandUnsubscribe) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandUnsubscribe.ProtoReflect.Descriptor instead. +func (*CommandUnsubscribe) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{30} +} + +func (x *CommandUnsubscribe) GetConsumerId() uint64 { + if x != nil && x.ConsumerId != nil { + return *x.ConsumerId + } + return 0 +} + +func (x *CommandUnsubscribe) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +// Reset an existing consumer to a particular message id +type CommandSeek struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConsumerId *uint64 `protobuf:"varint,1,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"` + RequestId *uint64 `protobuf:"varint,2,req,name=request_id,json=requestId" json:"request_id,omitempty"` + MessageId *MessageIdData `protobuf:"bytes,3,opt,name=message_id,json=messageId" json:"message_id,omitempty"` + MessagePublishTime *uint64 `protobuf:"varint,4,opt,name=message_publish_time,json=messagePublishTime" json:"message_publish_time,omitempty"` +} + +func (x *CommandSeek) Reset() { + *x = CommandSeek{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandSeek) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandSeek) ProtoMessage() {} + +func (x *CommandSeek) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandSeek.ProtoReflect.Descriptor instead. +func (*CommandSeek) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{31} +} + +func (x *CommandSeek) GetConsumerId() uint64 { + if x != nil && x.ConsumerId != nil { + return *x.ConsumerId + } + return 0 +} + +func (x *CommandSeek) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandSeek) GetMessageId() *MessageIdData { + if x != nil { + return x.MessageId + } + return nil +} + +func (x *CommandSeek) GetMessagePublishTime() uint64 { + if x != nil && x.MessagePublishTime != nil { + return *x.MessagePublishTime + } + return 0 +} + +// Message sent by broker to client when a topic +// has been forcefully terminated and there are no more +// messages left to consume +type CommandReachedEndOfTopic struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConsumerId *uint64 `protobuf:"varint,1,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"` +} + +func (x *CommandReachedEndOfTopic) Reset() { + *x = CommandReachedEndOfTopic{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandReachedEndOfTopic) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandReachedEndOfTopic) ProtoMessage() {} + +func (x *CommandReachedEndOfTopic) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandReachedEndOfTopic.ProtoReflect.Descriptor instead. +func (*CommandReachedEndOfTopic) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{32} +} + +func (x *CommandReachedEndOfTopic) GetConsumerId() uint64 { + if x != nil && x.ConsumerId != nil { + return *x.ConsumerId + } + return 0 +} + +type CommandCloseProducer struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProducerId *uint64 `protobuf:"varint,1,req,name=producer_id,json=producerId" json:"producer_id,omitempty"` + RequestId *uint64 `protobuf:"varint,2,req,name=request_id,json=requestId" json:"request_id,omitempty"` +} + +func (x *CommandCloseProducer) Reset() { + *x = CommandCloseProducer{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandCloseProducer) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandCloseProducer) ProtoMessage() {} + +func (x *CommandCloseProducer) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandCloseProducer.ProtoReflect.Descriptor instead. +func (*CommandCloseProducer) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{33} +} + +func (x *CommandCloseProducer) GetProducerId() uint64 { + if x != nil && x.ProducerId != nil { + return *x.ProducerId + } + return 0 +} + +func (x *CommandCloseProducer) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +type CommandCloseConsumer struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConsumerId *uint64 `protobuf:"varint,1,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"` + RequestId *uint64 `protobuf:"varint,2,req,name=request_id,json=requestId" json:"request_id,omitempty"` +} + +func (x *CommandCloseConsumer) Reset() { + *x = CommandCloseConsumer{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandCloseConsumer) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandCloseConsumer) ProtoMessage() {} + +func (x *CommandCloseConsumer) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandCloseConsumer.ProtoReflect.Descriptor instead. +func (*CommandCloseConsumer) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{34} +} + +func (x *CommandCloseConsumer) GetConsumerId() uint64 { + if x != nil && x.ConsumerId != nil { + return *x.ConsumerId + } + return 0 +} + +func (x *CommandCloseConsumer) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +type CommandRedeliverUnacknowledgedMessages struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConsumerId *uint64 `protobuf:"varint,1,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"` + MessageIds []*MessageIdData `protobuf:"bytes,2,rep,name=message_ids,json=messageIds" json:"message_ids,omitempty"` + ConsumerEpoch *uint64 `protobuf:"varint,3,opt,name=consumer_epoch,json=consumerEpoch" json:"consumer_epoch,omitempty"` +} + +func (x *CommandRedeliverUnacknowledgedMessages) Reset() { + *x = CommandRedeliverUnacknowledgedMessages{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandRedeliverUnacknowledgedMessages) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandRedeliverUnacknowledgedMessages) ProtoMessage() {} + +func (x *CommandRedeliverUnacknowledgedMessages) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandRedeliverUnacknowledgedMessages.ProtoReflect.Descriptor instead. +func (*CommandRedeliverUnacknowledgedMessages) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{35} +} + +func (x *CommandRedeliverUnacknowledgedMessages) GetConsumerId() uint64 { + if x != nil && x.ConsumerId != nil { + return *x.ConsumerId + } + return 0 +} + +func (x *CommandRedeliverUnacknowledgedMessages) GetMessageIds() []*MessageIdData { + if x != nil { + return x.MessageIds + } + return nil +} + +func (x *CommandRedeliverUnacknowledgedMessages) GetConsumerEpoch() uint64 { + if x != nil && x.ConsumerEpoch != nil { + return *x.ConsumerEpoch + } + return 0 +} + +type CommandSuccess struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + Schema *Schema `protobuf:"bytes,2,opt,name=schema" json:"schema,omitempty"` +} + +func (x *CommandSuccess) Reset() { + *x = CommandSuccess{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandSuccess) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandSuccess) ProtoMessage() {} + +func (x *CommandSuccess) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandSuccess.ProtoReflect.Descriptor instead. +func (*CommandSuccess) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{36} +} + +func (x *CommandSuccess) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandSuccess) GetSchema() *Schema { + if x != nil { + return x.Schema + } + return nil +} + +/// Response from CommandProducer +type CommandProducerSuccess struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + ProducerName *string `protobuf:"bytes,2,req,name=producer_name,json=producerName" json:"producer_name,omitempty"` + // The last sequence id that was stored by this producer in the previous session + // This will only be meaningful if deduplication has been enabled. + LastSequenceId *int64 `protobuf:"varint,3,opt,name=last_sequence_id,json=lastSequenceId,def=-1" json:"last_sequence_id,omitempty"` + SchemaVersion []byte `protobuf:"bytes,4,opt,name=schema_version,json=schemaVersion" json:"schema_version,omitempty"` + // The topic epoch assigned by the broker. This field will only be set if we + // were requiring exclusive access when creating the producer. + TopicEpoch *uint64 `protobuf:"varint,5,opt,name=topic_epoch,json=topicEpoch" json:"topic_epoch,omitempty"` + // If producer is not "ready", the client will avoid to timeout the request + // for creating the producer. Instead it will wait indefinitely until it gets + // a subsequent `CommandProducerSuccess` with `producer_ready==true`. + ProducerReady *bool `protobuf:"varint,6,opt,name=producer_ready,json=producerReady,def=1" json:"producer_ready,omitempty"` +} + +// Default values for CommandProducerSuccess fields. +const ( + Default_CommandProducerSuccess_LastSequenceId = int64(-1) + Default_CommandProducerSuccess_ProducerReady = bool(true) +) + +func (x *CommandProducerSuccess) Reset() { + *x = CommandProducerSuccess{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandProducerSuccess) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandProducerSuccess) ProtoMessage() {} + +func (x *CommandProducerSuccess) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[37] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandProducerSuccess.ProtoReflect.Descriptor instead. +func (*CommandProducerSuccess) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{37} +} + +func (x *CommandProducerSuccess) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandProducerSuccess) GetProducerName() string { + if x != nil && x.ProducerName != nil { + return *x.ProducerName + } + return "" +} + +func (x *CommandProducerSuccess) GetLastSequenceId() int64 { + if x != nil && x.LastSequenceId != nil { + return *x.LastSequenceId + } + return Default_CommandProducerSuccess_LastSequenceId +} + +func (x *CommandProducerSuccess) GetSchemaVersion() []byte { + if x != nil { + return x.SchemaVersion + } + return nil +} + +func (x *CommandProducerSuccess) GetTopicEpoch() uint64 { + if x != nil && x.TopicEpoch != nil { + return *x.TopicEpoch + } + return 0 +} + +func (x *CommandProducerSuccess) GetProducerReady() bool { + if x != nil && x.ProducerReady != nil { + return *x.ProducerReady + } + return Default_CommandProducerSuccess_ProducerReady +} + +type CommandError struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + Error *ServerError `protobuf:"varint,2,req,name=error,enum=pulsar.proto.ServerError" json:"error,omitempty"` + Message *string `protobuf:"bytes,3,req,name=message" json:"message,omitempty"` +} + +func (x *CommandError) Reset() { + *x = CommandError{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandError) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandError) ProtoMessage() {} + +func (x *CommandError) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[38] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandError.ProtoReflect.Descriptor instead. +func (*CommandError) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{38} +} + +func (x *CommandError) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandError) GetError() ServerError { + if x != nil && x.Error != nil { + return *x.Error + } + return ServerError_UnknownError +} + +func (x *CommandError) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message + } + return "" +} + +// Commands to probe the state of connection. +// When either client or broker doesn't receive commands for certain +// amount of time, they will send a Ping probe. +type CommandPing struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CommandPing) Reset() { + *x = CommandPing{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandPing) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandPing) ProtoMessage() {} + +func (x *CommandPing) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[39] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandPing.ProtoReflect.Descriptor instead. +func (*CommandPing) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{39} +} + +type CommandPong struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CommandPong) Reset() { + *x = CommandPong{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandPong) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandPong) ProtoMessage() {} + +func (x *CommandPong) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[40] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandPong.ProtoReflect.Descriptor instead. +func (*CommandPong) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{40} +} + +type CommandConsumerStats struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + // required string topic_name = 2; + // required string subscription_name = 3; + ConsumerId *uint64 `protobuf:"varint,4,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"` +} + +func (x *CommandConsumerStats) Reset() { + *x = CommandConsumerStats{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandConsumerStats) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandConsumerStats) ProtoMessage() {} + +func (x *CommandConsumerStats) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[41] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandConsumerStats.ProtoReflect.Descriptor instead. +func (*CommandConsumerStats) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{41} +} + +func (x *CommandConsumerStats) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandConsumerStats) GetConsumerId() uint64 { + if x != nil && x.ConsumerId != nil { + return *x.ConsumerId + } + return 0 +} + +type CommandConsumerStatsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + ErrorCode *ServerError `protobuf:"varint,2,opt,name=error_code,json=errorCode,enum=pulsar.proto.ServerError" json:"error_code,omitempty"` + ErrorMessage *string `protobuf:"bytes,3,opt,name=error_message,json=errorMessage" json:"error_message,omitempty"` + /// Total rate of messages delivered to the consumer. msg/s + MsgRateOut *float64 `protobuf:"fixed64,4,opt,name=msgRateOut" json:"msgRateOut,omitempty"` + /// Total throughput delivered to the consumer. bytes/s + MsgThroughputOut *float64 `protobuf:"fixed64,5,opt,name=msgThroughputOut" json:"msgThroughputOut,omitempty"` + /// Total rate of messages redelivered by this consumer. msg/s + MsgRateRedeliver *float64 `protobuf:"fixed64,6,opt,name=msgRateRedeliver" json:"msgRateRedeliver,omitempty"` + /// Name of the consumer + ConsumerName *string `protobuf:"bytes,7,opt,name=consumerName" json:"consumerName,omitempty"` + /// Number of available message permits for the consumer + AvailablePermits *uint64 `protobuf:"varint,8,opt,name=availablePermits" json:"availablePermits,omitempty"` + /// Number of unacknowledged messages for the consumer + UnackedMessages *uint64 `protobuf:"varint,9,opt,name=unackedMessages" json:"unackedMessages,omitempty"` + /// Flag to verify if consumer is blocked due to reaching threshold of unacked messages + BlockedConsumerOnUnackedMsgs *bool `protobuf:"varint,10,opt,name=blockedConsumerOnUnackedMsgs" json:"blockedConsumerOnUnackedMsgs,omitempty"` + /// Address of this consumer + Address *string `protobuf:"bytes,11,opt,name=address" json:"address,omitempty"` + /// Timestamp of connection + ConnectedSince *string `protobuf:"bytes,12,opt,name=connectedSince" json:"connectedSince,omitempty"` + /// Whether this subscription is Exclusive or Shared or Failover + Type *string `protobuf:"bytes,13,opt,name=type" json:"type,omitempty"` + /// Total rate of messages expired on this subscription. msg/s + MsgRateExpired *float64 `protobuf:"fixed64,14,opt,name=msgRateExpired" json:"msgRateExpired,omitempty"` + /// Number of messages in the subscription backlog + MsgBacklog *uint64 `protobuf:"varint,15,opt,name=msgBacklog" json:"msgBacklog,omitempty"` + /// Total rate of messages ack. msg/s + MessageAckRate *float64 `protobuf:"fixed64,16,opt,name=messageAckRate" json:"messageAckRate,omitempty"` +} + +func (x *CommandConsumerStatsResponse) Reset() { + *x = CommandConsumerStatsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandConsumerStatsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandConsumerStatsResponse) ProtoMessage() {} + +func (x *CommandConsumerStatsResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[42] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandConsumerStatsResponse.ProtoReflect.Descriptor instead. +func (*CommandConsumerStatsResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{42} +} + +func (x *CommandConsumerStatsResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandConsumerStatsResponse) GetErrorCode() ServerError { + if x != nil && x.ErrorCode != nil { + return *x.ErrorCode + } + return ServerError_UnknownError +} + +func (x *CommandConsumerStatsResponse) GetErrorMessage() string { + if x != nil && x.ErrorMessage != nil { + return *x.ErrorMessage + } + return "" +} + +func (x *CommandConsumerStatsResponse) GetMsgRateOut() float64 { + if x != nil && x.MsgRateOut != nil { + return *x.MsgRateOut + } + return 0 +} + +func (x *CommandConsumerStatsResponse) GetMsgThroughputOut() float64 { + if x != nil && x.MsgThroughputOut != nil { + return *x.MsgThroughputOut + } + return 0 +} + +func (x *CommandConsumerStatsResponse) GetMsgRateRedeliver() float64 { + if x != nil && x.MsgRateRedeliver != nil { + return *x.MsgRateRedeliver + } + return 0 +} + +func (x *CommandConsumerStatsResponse) GetConsumerName() string { + if x != nil && x.ConsumerName != nil { + return *x.ConsumerName + } + return "" +} + +func (x *CommandConsumerStatsResponse) GetAvailablePermits() uint64 { + if x != nil && x.AvailablePermits != nil { + return *x.AvailablePermits + } + return 0 +} + +func (x *CommandConsumerStatsResponse) GetUnackedMessages() uint64 { + if x != nil && x.UnackedMessages != nil { + return *x.UnackedMessages + } + return 0 +} + +func (x *CommandConsumerStatsResponse) GetBlockedConsumerOnUnackedMsgs() bool { + if x != nil && x.BlockedConsumerOnUnackedMsgs != nil { + return *x.BlockedConsumerOnUnackedMsgs + } + return false +} + +func (x *CommandConsumerStatsResponse) GetAddress() string { + if x != nil && x.Address != nil { + return *x.Address + } + return "" +} + +func (x *CommandConsumerStatsResponse) GetConnectedSince() string { + if x != nil && x.ConnectedSince != nil { + return *x.ConnectedSince + } + return "" +} + +func (x *CommandConsumerStatsResponse) GetType() string { + if x != nil && x.Type != nil { + return *x.Type + } + return "" +} + +func (x *CommandConsumerStatsResponse) GetMsgRateExpired() float64 { + if x != nil && x.MsgRateExpired != nil { + return *x.MsgRateExpired + } + return 0 +} + +func (x *CommandConsumerStatsResponse) GetMsgBacklog() uint64 { + if x != nil && x.MsgBacklog != nil { + return *x.MsgBacklog + } + return 0 +} + +func (x *CommandConsumerStatsResponse) GetMessageAckRate() float64 { + if x != nil && x.MessageAckRate != nil { + return *x.MessageAckRate + } + return 0 +} + +type CommandGetLastMessageId struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConsumerId *uint64 `protobuf:"varint,1,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"` + RequestId *uint64 `protobuf:"varint,2,req,name=request_id,json=requestId" json:"request_id,omitempty"` +} + +func (x *CommandGetLastMessageId) Reset() { + *x = CommandGetLastMessageId{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandGetLastMessageId) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandGetLastMessageId) ProtoMessage() {} + +func (x *CommandGetLastMessageId) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[43] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandGetLastMessageId.ProtoReflect.Descriptor instead. +func (*CommandGetLastMessageId) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{43} +} + +func (x *CommandGetLastMessageId) GetConsumerId() uint64 { + if x != nil && x.ConsumerId != nil { + return *x.ConsumerId + } + return 0 +} + +func (x *CommandGetLastMessageId) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +type CommandGetLastMessageIdResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LastMessageId *MessageIdData `protobuf:"bytes,1,req,name=last_message_id,json=lastMessageId" json:"last_message_id,omitempty"` + RequestId *uint64 `protobuf:"varint,2,req,name=request_id,json=requestId" json:"request_id,omitempty"` + ConsumerMarkDeletePosition *MessageIdData `protobuf:"bytes,3,opt,name=consumer_mark_delete_position,json=consumerMarkDeletePosition" json:"consumer_mark_delete_position,omitempty"` +} + +func (x *CommandGetLastMessageIdResponse) Reset() { + *x = CommandGetLastMessageIdResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandGetLastMessageIdResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandGetLastMessageIdResponse) ProtoMessage() {} + +func (x *CommandGetLastMessageIdResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[44] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandGetLastMessageIdResponse.ProtoReflect.Descriptor instead. +func (*CommandGetLastMessageIdResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{44} +} + +func (x *CommandGetLastMessageIdResponse) GetLastMessageId() *MessageIdData { + if x != nil { + return x.LastMessageId + } + return nil +} + +func (x *CommandGetLastMessageIdResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandGetLastMessageIdResponse) GetConsumerMarkDeletePosition() *MessageIdData { + if x != nil { + return x.ConsumerMarkDeletePosition + } + return nil +} + +type CommandGetTopicsOfNamespace struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + Namespace *string `protobuf:"bytes,2,req,name=namespace" json:"namespace,omitempty"` + Mode *CommandGetTopicsOfNamespace_Mode `protobuf:"varint,3,opt,name=mode,enum=pulsar.proto.CommandGetTopicsOfNamespace_Mode,def=0" json:"mode,omitempty"` + TopicsPattern *string `protobuf:"bytes,4,opt,name=topics_pattern,json=topicsPattern" json:"topics_pattern,omitempty"` + TopicsHash *string `protobuf:"bytes,5,opt,name=topics_hash,json=topicsHash" json:"topics_hash,omitempty"` +} + +// Default values for CommandGetTopicsOfNamespace fields. +const ( + Default_CommandGetTopicsOfNamespace_Mode = CommandGetTopicsOfNamespace_PERSISTENT +) + +func (x *CommandGetTopicsOfNamespace) Reset() { + *x = CommandGetTopicsOfNamespace{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandGetTopicsOfNamespace) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandGetTopicsOfNamespace) ProtoMessage() {} + +func (x *CommandGetTopicsOfNamespace) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[45] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandGetTopicsOfNamespace.ProtoReflect.Descriptor instead. +func (*CommandGetTopicsOfNamespace) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{45} +} + +func (x *CommandGetTopicsOfNamespace) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandGetTopicsOfNamespace) GetNamespace() string { + if x != nil && x.Namespace != nil { + return *x.Namespace + } + return "" +} + +func (x *CommandGetTopicsOfNamespace) GetMode() CommandGetTopicsOfNamespace_Mode { + if x != nil && x.Mode != nil { + return *x.Mode + } + return Default_CommandGetTopicsOfNamespace_Mode +} + +func (x *CommandGetTopicsOfNamespace) GetTopicsPattern() string { + if x != nil && x.TopicsPattern != nil { + return *x.TopicsPattern + } + return "" +} + +func (x *CommandGetTopicsOfNamespace) GetTopicsHash() string { + if x != nil && x.TopicsHash != nil { + return *x.TopicsHash + } + return "" +} + +type CommandGetTopicsOfNamespaceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + Topics []string `protobuf:"bytes,2,rep,name=topics" json:"topics,omitempty"` + // true iff the topic list was filtered by the pattern supplied by the client + Filtered *bool `protobuf:"varint,3,opt,name=filtered,def=0" json:"filtered,omitempty"` + // hash computed from the names of matching topics + TopicsHash *string `protobuf:"bytes,4,opt,name=topics_hash,json=topicsHash" json:"topics_hash,omitempty"` + // if false, topics is empty and the list of matching topics has not changed + Changed *bool `protobuf:"varint,5,opt,name=changed,def=1" json:"changed,omitempty"` +} + +// Default values for CommandGetTopicsOfNamespaceResponse fields. +const ( + Default_CommandGetTopicsOfNamespaceResponse_Filtered = bool(false) + Default_CommandGetTopicsOfNamespaceResponse_Changed = bool(true) +) + +func (x *CommandGetTopicsOfNamespaceResponse) Reset() { + *x = CommandGetTopicsOfNamespaceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandGetTopicsOfNamespaceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandGetTopicsOfNamespaceResponse) ProtoMessage() {} + +func (x *CommandGetTopicsOfNamespaceResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[46] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandGetTopicsOfNamespaceResponse.ProtoReflect.Descriptor instead. +func (*CommandGetTopicsOfNamespaceResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{46} +} + +func (x *CommandGetTopicsOfNamespaceResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandGetTopicsOfNamespaceResponse) GetTopics() []string { + if x != nil { + return x.Topics + } + return nil +} + +func (x *CommandGetTopicsOfNamespaceResponse) GetFiltered() bool { + if x != nil && x.Filtered != nil { + return *x.Filtered + } + return Default_CommandGetTopicsOfNamespaceResponse_Filtered +} + +func (x *CommandGetTopicsOfNamespaceResponse) GetTopicsHash() string { + if x != nil && x.TopicsHash != nil { + return *x.TopicsHash + } + return "" +} + +func (x *CommandGetTopicsOfNamespaceResponse) GetChanged() bool { + if x != nil && x.Changed != nil { + return *x.Changed + } + return Default_CommandGetTopicsOfNamespaceResponse_Changed +} + +type CommandWatchTopicList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + WatcherId *uint64 `protobuf:"varint,2,req,name=watcher_id,json=watcherId" json:"watcher_id,omitempty"` + Namespace *string `protobuf:"bytes,3,req,name=namespace" json:"namespace,omitempty"` + TopicsPattern *string `protobuf:"bytes,4,req,name=topics_pattern,json=topicsPattern" json:"topics_pattern,omitempty"` + // Only present when the client reconnects: + TopicsHash *string `protobuf:"bytes,5,opt,name=topics_hash,json=topicsHash" json:"topics_hash,omitempty"` +} + +func (x *CommandWatchTopicList) Reset() { + *x = CommandWatchTopicList{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandWatchTopicList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandWatchTopicList) ProtoMessage() {} + +func (x *CommandWatchTopicList) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[47] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandWatchTopicList.ProtoReflect.Descriptor instead. +func (*CommandWatchTopicList) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{47} +} + +func (x *CommandWatchTopicList) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandWatchTopicList) GetWatcherId() uint64 { + if x != nil && x.WatcherId != nil { + return *x.WatcherId + } + return 0 +} + +func (x *CommandWatchTopicList) GetNamespace() string { + if x != nil && x.Namespace != nil { + return *x.Namespace + } + return "" +} + +func (x *CommandWatchTopicList) GetTopicsPattern() string { + if x != nil && x.TopicsPattern != nil { + return *x.TopicsPattern + } + return "" +} + +func (x *CommandWatchTopicList) GetTopicsHash() string { + if x != nil && x.TopicsHash != nil { + return *x.TopicsHash + } + return "" +} + +type CommandWatchTopicListSuccess struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + WatcherId *uint64 `protobuf:"varint,2,req,name=watcher_id,json=watcherId" json:"watcher_id,omitempty"` + Topic []string `protobuf:"bytes,3,rep,name=topic" json:"topic,omitempty"` + TopicsHash *string `protobuf:"bytes,4,req,name=topics_hash,json=topicsHash" json:"topics_hash,omitempty"` +} + +func (x *CommandWatchTopicListSuccess) Reset() { + *x = CommandWatchTopicListSuccess{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandWatchTopicListSuccess) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandWatchTopicListSuccess) ProtoMessage() {} + +func (x *CommandWatchTopicListSuccess) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[48] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandWatchTopicListSuccess.ProtoReflect.Descriptor instead. +func (*CommandWatchTopicListSuccess) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{48} +} + +func (x *CommandWatchTopicListSuccess) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandWatchTopicListSuccess) GetWatcherId() uint64 { + if x != nil && x.WatcherId != nil { + return *x.WatcherId + } + return 0 +} + +func (x *CommandWatchTopicListSuccess) GetTopic() []string { + if x != nil { + return x.Topic + } + return nil +} + +func (x *CommandWatchTopicListSuccess) GetTopicsHash() string { + if x != nil && x.TopicsHash != nil { + return *x.TopicsHash + } + return "" +} + +type CommandWatchTopicUpdate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WatcherId *uint64 `protobuf:"varint,1,req,name=watcher_id,json=watcherId" json:"watcher_id,omitempty"` + NewTopics []string `protobuf:"bytes,2,rep,name=new_topics,json=newTopics" json:"new_topics,omitempty"` + DeletedTopics []string `protobuf:"bytes,3,rep,name=deleted_topics,json=deletedTopics" json:"deleted_topics,omitempty"` + TopicsHash *string `protobuf:"bytes,4,req,name=topics_hash,json=topicsHash" json:"topics_hash,omitempty"` +} + +func (x *CommandWatchTopicUpdate) Reset() { + *x = CommandWatchTopicUpdate{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandWatchTopicUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandWatchTopicUpdate) ProtoMessage() {} + +func (x *CommandWatchTopicUpdate) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[49] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandWatchTopicUpdate.ProtoReflect.Descriptor instead. +func (*CommandWatchTopicUpdate) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{49} +} + +func (x *CommandWatchTopicUpdate) GetWatcherId() uint64 { + if x != nil && x.WatcherId != nil { + return *x.WatcherId + } + return 0 +} + +func (x *CommandWatchTopicUpdate) GetNewTopics() []string { + if x != nil { + return x.NewTopics + } + return nil +} + +func (x *CommandWatchTopicUpdate) GetDeletedTopics() []string { + if x != nil { + return x.DeletedTopics + } + return nil +} + +func (x *CommandWatchTopicUpdate) GetTopicsHash() string { + if x != nil && x.TopicsHash != nil { + return *x.TopicsHash + } + return "" +} + +type CommandWatchTopicListClose struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + WatcherId *uint64 `protobuf:"varint,2,req,name=watcher_id,json=watcherId" json:"watcher_id,omitempty"` +} + +func (x *CommandWatchTopicListClose) Reset() { + *x = CommandWatchTopicListClose{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandWatchTopicListClose) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandWatchTopicListClose) ProtoMessage() {} + +func (x *CommandWatchTopicListClose) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[50] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandWatchTopicListClose.ProtoReflect.Descriptor instead. +func (*CommandWatchTopicListClose) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{50} +} + +func (x *CommandWatchTopicListClose) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandWatchTopicListClose) GetWatcherId() uint64 { + if x != nil && x.WatcherId != nil { + return *x.WatcherId + } + return 0 +} + +type CommandGetSchema struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + Topic *string `protobuf:"bytes,2,req,name=topic" json:"topic,omitempty"` + SchemaVersion []byte `protobuf:"bytes,3,opt,name=schema_version,json=schemaVersion" json:"schema_version,omitempty"` +} + +func (x *CommandGetSchema) Reset() { + *x = CommandGetSchema{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandGetSchema) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandGetSchema) ProtoMessage() {} + +func (x *CommandGetSchema) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[51] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandGetSchema.ProtoReflect.Descriptor instead. +func (*CommandGetSchema) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{51} +} + +func (x *CommandGetSchema) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandGetSchema) GetTopic() string { + if x != nil && x.Topic != nil { + return *x.Topic + } + return "" +} + +func (x *CommandGetSchema) GetSchemaVersion() []byte { + if x != nil { + return x.SchemaVersion + } + return nil +} + +type CommandGetSchemaResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + ErrorCode *ServerError `protobuf:"varint,2,opt,name=error_code,json=errorCode,enum=pulsar.proto.ServerError" json:"error_code,omitempty"` + ErrorMessage *string `protobuf:"bytes,3,opt,name=error_message,json=errorMessage" json:"error_message,omitempty"` + Schema *Schema `protobuf:"bytes,4,opt,name=schema" json:"schema,omitempty"` + SchemaVersion []byte `protobuf:"bytes,5,opt,name=schema_version,json=schemaVersion" json:"schema_version,omitempty"` +} + +func (x *CommandGetSchemaResponse) Reset() { + *x = CommandGetSchemaResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandGetSchemaResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandGetSchemaResponse) ProtoMessage() {} + +func (x *CommandGetSchemaResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[52] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandGetSchemaResponse.ProtoReflect.Descriptor instead. +func (*CommandGetSchemaResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{52} +} + +func (x *CommandGetSchemaResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandGetSchemaResponse) GetErrorCode() ServerError { + if x != nil && x.ErrorCode != nil { + return *x.ErrorCode + } + return ServerError_UnknownError +} + +func (x *CommandGetSchemaResponse) GetErrorMessage() string { + if x != nil && x.ErrorMessage != nil { + return *x.ErrorMessage + } + return "" +} + +func (x *CommandGetSchemaResponse) GetSchema() *Schema { + if x != nil { + return x.Schema + } + return nil +} + +func (x *CommandGetSchemaResponse) GetSchemaVersion() []byte { + if x != nil { + return x.SchemaVersion + } + return nil +} + +type CommandGetOrCreateSchema struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + Topic *string `protobuf:"bytes,2,req,name=topic" json:"topic,omitempty"` + Schema *Schema `protobuf:"bytes,3,req,name=schema" json:"schema,omitempty"` +} + +func (x *CommandGetOrCreateSchema) Reset() { + *x = CommandGetOrCreateSchema{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[53] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandGetOrCreateSchema) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandGetOrCreateSchema) ProtoMessage() {} + +func (x *CommandGetOrCreateSchema) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[53] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandGetOrCreateSchema.ProtoReflect.Descriptor instead. +func (*CommandGetOrCreateSchema) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{53} +} + +func (x *CommandGetOrCreateSchema) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandGetOrCreateSchema) GetTopic() string { + if x != nil && x.Topic != nil { + return *x.Topic + } + return "" +} + +func (x *CommandGetOrCreateSchema) GetSchema() *Schema { + if x != nil { + return x.Schema + } + return nil +} + +type CommandGetOrCreateSchemaResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + ErrorCode *ServerError `protobuf:"varint,2,opt,name=error_code,json=errorCode,enum=pulsar.proto.ServerError" json:"error_code,omitempty"` + ErrorMessage *string `protobuf:"bytes,3,opt,name=error_message,json=errorMessage" json:"error_message,omitempty"` + SchemaVersion []byte `protobuf:"bytes,4,opt,name=schema_version,json=schemaVersion" json:"schema_version,omitempty"` +} + +func (x *CommandGetOrCreateSchemaResponse) Reset() { + *x = CommandGetOrCreateSchemaResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandGetOrCreateSchemaResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandGetOrCreateSchemaResponse) ProtoMessage() {} + +func (x *CommandGetOrCreateSchemaResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[54] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandGetOrCreateSchemaResponse.ProtoReflect.Descriptor instead. +func (*CommandGetOrCreateSchemaResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{54} +} + +func (x *CommandGetOrCreateSchemaResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandGetOrCreateSchemaResponse) GetErrorCode() ServerError { + if x != nil && x.ErrorCode != nil { + return *x.ErrorCode + } + return ServerError_UnknownError +} + +func (x *CommandGetOrCreateSchemaResponse) GetErrorMessage() string { + if x != nil && x.ErrorMessage != nil { + return *x.ErrorMessage + } + return "" +} + +func (x *CommandGetOrCreateSchemaResponse) GetSchemaVersion() []byte { + if x != nil { + return x.SchemaVersion + } + return nil +} + +type CommandTcClientConnectRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + TcId *uint64 `protobuf:"varint,2,req,name=tc_id,json=tcId,def=0" json:"tc_id,omitempty"` +} + +// Default values for CommandTcClientConnectRequest fields. +const ( + Default_CommandTcClientConnectRequest_TcId = uint64(0) +) + +func (x *CommandTcClientConnectRequest) Reset() { + *x = CommandTcClientConnectRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[55] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandTcClientConnectRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandTcClientConnectRequest) ProtoMessage() {} + +func (x *CommandTcClientConnectRequest) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[55] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandTcClientConnectRequest.ProtoReflect.Descriptor instead. +func (*CommandTcClientConnectRequest) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{55} +} + +func (x *CommandTcClientConnectRequest) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandTcClientConnectRequest) GetTcId() uint64 { + if x != nil && x.TcId != nil { + return *x.TcId + } + return Default_CommandTcClientConnectRequest_TcId +} + +type CommandTcClientConnectResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + Error *ServerError `protobuf:"varint,2,opt,name=error,enum=pulsar.proto.ServerError" json:"error,omitempty"` + Message *string `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` +} + +func (x *CommandTcClientConnectResponse) Reset() { + *x = CommandTcClientConnectResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[56] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandTcClientConnectResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandTcClientConnectResponse) ProtoMessage() {} + +func (x *CommandTcClientConnectResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[56] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandTcClientConnectResponse.ProtoReflect.Descriptor instead. +func (*CommandTcClientConnectResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{56} +} + +func (x *CommandTcClientConnectResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandTcClientConnectResponse) GetError() ServerError { + if x != nil && x.Error != nil { + return *x.Error + } + return ServerError_UnknownError +} + +func (x *CommandTcClientConnectResponse) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message + } + return "" +} + +type CommandNewTxn struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + TxnTtlSeconds *uint64 `protobuf:"varint,2,opt,name=txn_ttl_seconds,json=txnTtlSeconds,def=0" json:"txn_ttl_seconds,omitempty"` + TcId *uint64 `protobuf:"varint,3,opt,name=tc_id,json=tcId,def=0" json:"tc_id,omitempty"` +} + +// Default values for CommandNewTxn fields. +const ( + Default_CommandNewTxn_TxnTtlSeconds = uint64(0) + Default_CommandNewTxn_TcId = uint64(0) +) + +func (x *CommandNewTxn) Reset() { + *x = CommandNewTxn{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandNewTxn) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandNewTxn) ProtoMessage() {} + +func (x *CommandNewTxn) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[57] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandNewTxn.ProtoReflect.Descriptor instead. +func (*CommandNewTxn) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{57} +} + +func (x *CommandNewTxn) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandNewTxn) GetTxnTtlSeconds() uint64 { + if x != nil && x.TxnTtlSeconds != nil { + return *x.TxnTtlSeconds + } + return Default_CommandNewTxn_TxnTtlSeconds +} + +func (x *CommandNewTxn) GetTcId() uint64 { + if x != nil && x.TcId != nil { + return *x.TcId + } + return Default_CommandNewTxn_TcId +} + +type CommandNewTxnResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,2,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,3,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + Error *ServerError `protobuf:"varint,4,opt,name=error,enum=pulsar.proto.ServerError" json:"error,omitempty"` + Message *string `protobuf:"bytes,5,opt,name=message" json:"message,omitempty"` +} + +// Default values for CommandNewTxnResponse fields. +const ( + Default_CommandNewTxnResponse_TxnidLeastBits = uint64(0) + Default_CommandNewTxnResponse_TxnidMostBits = uint64(0) +) + +func (x *CommandNewTxnResponse) Reset() { + *x = CommandNewTxnResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandNewTxnResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandNewTxnResponse) ProtoMessage() {} + +func (x *CommandNewTxnResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[58] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandNewTxnResponse.ProtoReflect.Descriptor instead. +func (*CommandNewTxnResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{58} +} + +func (x *CommandNewTxnResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandNewTxnResponse) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandNewTxnResponse_TxnidLeastBits +} + +func (x *CommandNewTxnResponse) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandNewTxnResponse_TxnidMostBits +} + +func (x *CommandNewTxnResponse) GetError() ServerError { + if x != nil && x.Error != nil { + return *x.Error + } + return ServerError_UnknownError +} + +func (x *CommandNewTxnResponse) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message + } + return "" +} + +type CommandAddPartitionToTxn struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,2,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,3,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + Partitions []string `protobuf:"bytes,4,rep,name=partitions" json:"partitions,omitempty"` +} + +// Default values for CommandAddPartitionToTxn fields. +const ( + Default_CommandAddPartitionToTxn_TxnidLeastBits = uint64(0) + Default_CommandAddPartitionToTxn_TxnidMostBits = uint64(0) +) + +func (x *CommandAddPartitionToTxn) Reset() { + *x = CommandAddPartitionToTxn{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[59] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandAddPartitionToTxn) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandAddPartitionToTxn) ProtoMessage() {} + +func (x *CommandAddPartitionToTxn) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[59] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandAddPartitionToTxn.ProtoReflect.Descriptor instead. +func (*CommandAddPartitionToTxn) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{59} +} + +func (x *CommandAddPartitionToTxn) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandAddPartitionToTxn) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandAddPartitionToTxn_TxnidLeastBits +} + +func (x *CommandAddPartitionToTxn) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandAddPartitionToTxn_TxnidMostBits +} + +func (x *CommandAddPartitionToTxn) GetPartitions() []string { + if x != nil { + return x.Partitions + } + return nil +} + +type CommandAddPartitionToTxnResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,2,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,3,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + Error *ServerError `protobuf:"varint,4,opt,name=error,enum=pulsar.proto.ServerError" json:"error,omitempty"` + Message *string `protobuf:"bytes,5,opt,name=message" json:"message,omitempty"` +} + +// Default values for CommandAddPartitionToTxnResponse fields. +const ( + Default_CommandAddPartitionToTxnResponse_TxnidLeastBits = uint64(0) + Default_CommandAddPartitionToTxnResponse_TxnidMostBits = uint64(0) +) + +func (x *CommandAddPartitionToTxnResponse) Reset() { + *x = CommandAddPartitionToTxnResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[60] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandAddPartitionToTxnResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandAddPartitionToTxnResponse) ProtoMessage() {} + +func (x *CommandAddPartitionToTxnResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[60] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandAddPartitionToTxnResponse.ProtoReflect.Descriptor instead. +func (*CommandAddPartitionToTxnResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{60} +} + +func (x *CommandAddPartitionToTxnResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandAddPartitionToTxnResponse) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandAddPartitionToTxnResponse_TxnidLeastBits +} + +func (x *CommandAddPartitionToTxnResponse) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandAddPartitionToTxnResponse_TxnidMostBits +} + +func (x *CommandAddPartitionToTxnResponse) GetError() ServerError { + if x != nil && x.Error != nil { + return *x.Error + } + return ServerError_UnknownError +} + +func (x *CommandAddPartitionToTxnResponse) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message + } + return "" +} + +type Subscription struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Topic *string `protobuf:"bytes,1,req,name=topic" json:"topic,omitempty"` + Subscription *string `protobuf:"bytes,2,req,name=subscription" json:"subscription,omitempty"` +} + +func (x *Subscription) Reset() { + *x = Subscription{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[61] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Subscription) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Subscription) ProtoMessage() {} + +func (x *Subscription) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[61] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Subscription.ProtoReflect.Descriptor instead. +func (*Subscription) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{61} +} + +func (x *Subscription) GetTopic() string { + if x != nil && x.Topic != nil { + return *x.Topic + } + return "" +} + +func (x *Subscription) GetSubscription() string { + if x != nil && x.Subscription != nil { + return *x.Subscription + } + return "" +} + +type CommandAddSubscriptionToTxn struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,2,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,3,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + Subscription []*Subscription `protobuf:"bytes,4,rep,name=subscription" json:"subscription,omitempty"` +} + +// Default values for CommandAddSubscriptionToTxn fields. +const ( + Default_CommandAddSubscriptionToTxn_TxnidLeastBits = uint64(0) + Default_CommandAddSubscriptionToTxn_TxnidMostBits = uint64(0) +) + +func (x *CommandAddSubscriptionToTxn) Reset() { + *x = CommandAddSubscriptionToTxn{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[62] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandAddSubscriptionToTxn) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandAddSubscriptionToTxn) ProtoMessage() {} + +func (x *CommandAddSubscriptionToTxn) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[62] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandAddSubscriptionToTxn.ProtoReflect.Descriptor instead. +func (*CommandAddSubscriptionToTxn) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{62} +} + +func (x *CommandAddSubscriptionToTxn) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandAddSubscriptionToTxn) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandAddSubscriptionToTxn_TxnidLeastBits +} + +func (x *CommandAddSubscriptionToTxn) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandAddSubscriptionToTxn_TxnidMostBits +} + +func (x *CommandAddSubscriptionToTxn) GetSubscription() []*Subscription { + if x != nil { + return x.Subscription + } + return nil +} + +type CommandAddSubscriptionToTxnResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,2,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,3,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + Error *ServerError `protobuf:"varint,4,opt,name=error,enum=pulsar.proto.ServerError" json:"error,omitempty"` + Message *string `protobuf:"bytes,5,opt,name=message" json:"message,omitempty"` +} + +// Default values for CommandAddSubscriptionToTxnResponse fields. +const ( + Default_CommandAddSubscriptionToTxnResponse_TxnidLeastBits = uint64(0) + Default_CommandAddSubscriptionToTxnResponse_TxnidMostBits = uint64(0) +) + +func (x *CommandAddSubscriptionToTxnResponse) Reset() { + *x = CommandAddSubscriptionToTxnResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[63] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandAddSubscriptionToTxnResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandAddSubscriptionToTxnResponse) ProtoMessage() {} + +func (x *CommandAddSubscriptionToTxnResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[63] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandAddSubscriptionToTxnResponse.ProtoReflect.Descriptor instead. +func (*CommandAddSubscriptionToTxnResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{63} +} + +func (x *CommandAddSubscriptionToTxnResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandAddSubscriptionToTxnResponse) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandAddSubscriptionToTxnResponse_TxnidLeastBits +} + +func (x *CommandAddSubscriptionToTxnResponse) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandAddSubscriptionToTxnResponse_TxnidMostBits +} + +func (x *CommandAddSubscriptionToTxnResponse) GetError() ServerError { + if x != nil && x.Error != nil { + return *x.Error + } + return ServerError_UnknownError +} + +func (x *CommandAddSubscriptionToTxnResponse) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message + } + return "" +} + +type CommandEndTxn struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,2,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,3,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + TxnAction *TxnAction `protobuf:"varint,4,opt,name=txn_action,json=txnAction,enum=pulsar.proto.TxnAction" json:"txn_action,omitempty"` +} + +// Default values for CommandEndTxn fields. +const ( + Default_CommandEndTxn_TxnidLeastBits = uint64(0) + Default_CommandEndTxn_TxnidMostBits = uint64(0) +) + +func (x *CommandEndTxn) Reset() { + *x = CommandEndTxn{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[64] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandEndTxn) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandEndTxn) ProtoMessage() {} + +func (x *CommandEndTxn) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[64] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandEndTxn.ProtoReflect.Descriptor instead. +func (*CommandEndTxn) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{64} +} + +func (x *CommandEndTxn) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandEndTxn) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandEndTxn_TxnidLeastBits +} + +func (x *CommandEndTxn) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandEndTxn_TxnidMostBits +} + +func (x *CommandEndTxn) GetTxnAction() TxnAction { + if x != nil && x.TxnAction != nil { + return *x.TxnAction + } + return TxnAction_COMMIT +} + +type CommandEndTxnResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,2,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,3,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + Error *ServerError `protobuf:"varint,4,opt,name=error,enum=pulsar.proto.ServerError" json:"error,omitempty"` + Message *string `protobuf:"bytes,5,opt,name=message" json:"message,omitempty"` +} + +// Default values for CommandEndTxnResponse fields. +const ( + Default_CommandEndTxnResponse_TxnidLeastBits = uint64(0) + Default_CommandEndTxnResponse_TxnidMostBits = uint64(0) +) + +func (x *CommandEndTxnResponse) Reset() { + *x = CommandEndTxnResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[65] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandEndTxnResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandEndTxnResponse) ProtoMessage() {} + +func (x *CommandEndTxnResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[65] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandEndTxnResponse.ProtoReflect.Descriptor instead. +func (*CommandEndTxnResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{65} +} + +func (x *CommandEndTxnResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandEndTxnResponse) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandEndTxnResponse_TxnidLeastBits +} + +func (x *CommandEndTxnResponse) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandEndTxnResponse_TxnidMostBits +} + +func (x *CommandEndTxnResponse) GetError() ServerError { + if x != nil && x.Error != nil { + return *x.Error + } + return ServerError_UnknownError +} + +func (x *CommandEndTxnResponse) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message + } + return "" +} + +type CommandEndTxnOnPartition struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,2,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,3,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + Topic *string `protobuf:"bytes,4,opt,name=topic" json:"topic,omitempty"` + TxnAction *TxnAction `protobuf:"varint,5,opt,name=txn_action,json=txnAction,enum=pulsar.proto.TxnAction" json:"txn_action,omitempty"` + TxnidLeastBitsOfLowWatermark *uint64 `protobuf:"varint,6,opt,name=txnid_least_bits_of_low_watermark,json=txnidLeastBitsOfLowWatermark" json:"txnid_least_bits_of_low_watermark,omitempty"` +} + +// Default values for CommandEndTxnOnPartition fields. +const ( + Default_CommandEndTxnOnPartition_TxnidLeastBits = uint64(0) + Default_CommandEndTxnOnPartition_TxnidMostBits = uint64(0) +) + +func (x *CommandEndTxnOnPartition) Reset() { + *x = CommandEndTxnOnPartition{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[66] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandEndTxnOnPartition) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandEndTxnOnPartition) ProtoMessage() {} + +func (x *CommandEndTxnOnPartition) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[66] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandEndTxnOnPartition.ProtoReflect.Descriptor instead. +func (*CommandEndTxnOnPartition) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{66} +} + +func (x *CommandEndTxnOnPartition) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandEndTxnOnPartition) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandEndTxnOnPartition_TxnidLeastBits +} + +func (x *CommandEndTxnOnPartition) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandEndTxnOnPartition_TxnidMostBits +} + +func (x *CommandEndTxnOnPartition) GetTopic() string { + if x != nil && x.Topic != nil { + return *x.Topic + } + return "" +} + +func (x *CommandEndTxnOnPartition) GetTxnAction() TxnAction { + if x != nil && x.TxnAction != nil { + return *x.TxnAction + } + return TxnAction_COMMIT +} + +func (x *CommandEndTxnOnPartition) GetTxnidLeastBitsOfLowWatermark() uint64 { + if x != nil && x.TxnidLeastBitsOfLowWatermark != nil { + return *x.TxnidLeastBitsOfLowWatermark + } + return 0 +} + +type CommandEndTxnOnPartitionResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,2,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,3,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + Error *ServerError `protobuf:"varint,4,opt,name=error,enum=pulsar.proto.ServerError" json:"error,omitempty"` + Message *string `protobuf:"bytes,5,opt,name=message" json:"message,omitempty"` +} + +// Default values for CommandEndTxnOnPartitionResponse fields. +const ( + Default_CommandEndTxnOnPartitionResponse_TxnidLeastBits = uint64(0) + Default_CommandEndTxnOnPartitionResponse_TxnidMostBits = uint64(0) +) + +func (x *CommandEndTxnOnPartitionResponse) Reset() { + *x = CommandEndTxnOnPartitionResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[67] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandEndTxnOnPartitionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandEndTxnOnPartitionResponse) ProtoMessage() {} + +func (x *CommandEndTxnOnPartitionResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[67] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandEndTxnOnPartitionResponse.ProtoReflect.Descriptor instead. +func (*CommandEndTxnOnPartitionResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{67} +} + +func (x *CommandEndTxnOnPartitionResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandEndTxnOnPartitionResponse) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandEndTxnOnPartitionResponse_TxnidLeastBits +} + +func (x *CommandEndTxnOnPartitionResponse) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandEndTxnOnPartitionResponse_TxnidMostBits +} + +func (x *CommandEndTxnOnPartitionResponse) GetError() ServerError { + if x != nil && x.Error != nil { + return *x.Error + } + return ServerError_UnknownError +} + +func (x *CommandEndTxnOnPartitionResponse) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message + } + return "" +} + +type CommandEndTxnOnSubscription struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,2,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,3,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + Subscription *Subscription `protobuf:"bytes,4,opt,name=subscription" json:"subscription,omitempty"` + TxnAction *TxnAction `protobuf:"varint,5,opt,name=txn_action,json=txnAction,enum=pulsar.proto.TxnAction" json:"txn_action,omitempty"` + TxnidLeastBitsOfLowWatermark *uint64 `protobuf:"varint,6,opt,name=txnid_least_bits_of_low_watermark,json=txnidLeastBitsOfLowWatermark" json:"txnid_least_bits_of_low_watermark,omitempty"` +} + +// Default values for CommandEndTxnOnSubscription fields. +const ( + Default_CommandEndTxnOnSubscription_TxnidLeastBits = uint64(0) + Default_CommandEndTxnOnSubscription_TxnidMostBits = uint64(0) +) + +func (x *CommandEndTxnOnSubscription) Reset() { + *x = CommandEndTxnOnSubscription{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[68] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandEndTxnOnSubscription) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandEndTxnOnSubscription) ProtoMessage() {} + +func (x *CommandEndTxnOnSubscription) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[68] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandEndTxnOnSubscription.ProtoReflect.Descriptor instead. +func (*CommandEndTxnOnSubscription) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{68} +} + +func (x *CommandEndTxnOnSubscription) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandEndTxnOnSubscription) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandEndTxnOnSubscription_TxnidLeastBits +} + +func (x *CommandEndTxnOnSubscription) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandEndTxnOnSubscription_TxnidMostBits +} + +func (x *CommandEndTxnOnSubscription) GetSubscription() *Subscription { + if x != nil { + return x.Subscription + } + return nil +} + +func (x *CommandEndTxnOnSubscription) GetTxnAction() TxnAction { + if x != nil && x.TxnAction != nil { + return *x.TxnAction + } + return TxnAction_COMMIT +} + +func (x *CommandEndTxnOnSubscription) GetTxnidLeastBitsOfLowWatermark() uint64 { + if x != nil && x.TxnidLeastBitsOfLowWatermark != nil { + return *x.TxnidLeastBitsOfLowWatermark + } + return 0 +} + +type CommandEndTxnOnSubscriptionResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId *uint64 `protobuf:"varint,1,req,name=request_id,json=requestId" json:"request_id,omitempty"` + TxnidLeastBits *uint64 `protobuf:"varint,2,opt,name=txnid_least_bits,json=txnidLeastBits,def=0" json:"txnid_least_bits,omitempty"` + TxnidMostBits *uint64 `protobuf:"varint,3,opt,name=txnid_most_bits,json=txnidMostBits,def=0" json:"txnid_most_bits,omitempty"` + Error *ServerError `protobuf:"varint,4,opt,name=error,enum=pulsar.proto.ServerError" json:"error,omitempty"` + Message *string `protobuf:"bytes,5,opt,name=message" json:"message,omitempty"` +} + +// Default values for CommandEndTxnOnSubscriptionResponse fields. +const ( + Default_CommandEndTxnOnSubscriptionResponse_TxnidLeastBits = uint64(0) + Default_CommandEndTxnOnSubscriptionResponse_TxnidMostBits = uint64(0) +) + +func (x *CommandEndTxnOnSubscriptionResponse) Reset() { + *x = CommandEndTxnOnSubscriptionResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[69] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommandEndTxnOnSubscriptionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandEndTxnOnSubscriptionResponse) ProtoMessage() {} + +func (x *CommandEndTxnOnSubscriptionResponse) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[69] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandEndTxnOnSubscriptionResponse.ProtoReflect.Descriptor instead. +func (*CommandEndTxnOnSubscriptionResponse) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{69} +} + +func (x *CommandEndTxnOnSubscriptionResponse) GetRequestId() uint64 { + if x != nil && x.RequestId != nil { + return *x.RequestId + } + return 0 +} + +func (x *CommandEndTxnOnSubscriptionResponse) GetTxnidLeastBits() uint64 { + if x != nil && x.TxnidLeastBits != nil { + return *x.TxnidLeastBits + } + return Default_CommandEndTxnOnSubscriptionResponse_TxnidLeastBits +} + +func (x *CommandEndTxnOnSubscriptionResponse) GetTxnidMostBits() uint64 { + if x != nil && x.TxnidMostBits != nil { + return *x.TxnidMostBits + } + return Default_CommandEndTxnOnSubscriptionResponse_TxnidMostBits +} + +func (x *CommandEndTxnOnSubscriptionResponse) GetError() ServerError { + if x != nil && x.Error != nil { + return *x.Error + } + return ServerError_UnknownError +} + +func (x *CommandEndTxnOnSubscriptionResponse) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message + } + return "" +} + +type BaseCommand struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type *BaseCommand_Type `protobuf:"varint,1,req,name=type,enum=pulsar.proto.BaseCommand_Type" json:"type,omitempty"` + Connect *CommandConnect `protobuf:"bytes,2,opt,name=connect" json:"connect,omitempty"` + Connected *CommandConnected `protobuf:"bytes,3,opt,name=connected" json:"connected,omitempty"` + Subscribe *CommandSubscribe `protobuf:"bytes,4,opt,name=subscribe" json:"subscribe,omitempty"` + Producer *CommandProducer `protobuf:"bytes,5,opt,name=producer" json:"producer,omitempty"` + Send *CommandSend `protobuf:"bytes,6,opt,name=send" json:"send,omitempty"` + SendReceipt *CommandSendReceipt `protobuf:"bytes,7,opt,name=send_receipt,json=sendReceipt" json:"send_receipt,omitempty"` + SendError *CommandSendError `protobuf:"bytes,8,opt,name=send_error,json=sendError" json:"send_error,omitempty"` + Message *CommandMessage `protobuf:"bytes,9,opt,name=message" json:"message,omitempty"` + Ack *CommandAck `protobuf:"bytes,10,opt,name=ack" json:"ack,omitempty"` + Flow *CommandFlow `protobuf:"bytes,11,opt,name=flow" json:"flow,omitempty"` + Unsubscribe *CommandUnsubscribe `protobuf:"bytes,12,opt,name=unsubscribe" json:"unsubscribe,omitempty"` + Success *CommandSuccess `protobuf:"bytes,13,opt,name=success" json:"success,omitempty"` + Error *CommandError `protobuf:"bytes,14,opt,name=error" json:"error,omitempty"` + CloseProducer *CommandCloseProducer `protobuf:"bytes,15,opt,name=close_producer,json=closeProducer" json:"close_producer,omitempty"` + CloseConsumer *CommandCloseConsumer `protobuf:"bytes,16,opt,name=close_consumer,json=closeConsumer" json:"close_consumer,omitempty"` + ProducerSuccess *CommandProducerSuccess `protobuf:"bytes,17,opt,name=producer_success,json=producerSuccess" json:"producer_success,omitempty"` + Ping *CommandPing `protobuf:"bytes,18,opt,name=ping" json:"ping,omitempty"` + Pong *CommandPong `protobuf:"bytes,19,opt,name=pong" json:"pong,omitempty"` + RedeliverUnacknowledgedMessages *CommandRedeliverUnacknowledgedMessages `protobuf:"bytes,20,opt,name=redeliverUnacknowledgedMessages" json:"redeliverUnacknowledgedMessages,omitempty"` + PartitionMetadata *CommandPartitionedTopicMetadata `protobuf:"bytes,21,opt,name=partitionMetadata" json:"partitionMetadata,omitempty"` + PartitionMetadataResponse *CommandPartitionedTopicMetadataResponse `protobuf:"bytes,22,opt,name=partitionMetadataResponse" json:"partitionMetadataResponse,omitempty"` + LookupTopic *CommandLookupTopic `protobuf:"bytes,23,opt,name=lookupTopic" json:"lookupTopic,omitempty"` + LookupTopicResponse *CommandLookupTopicResponse `protobuf:"bytes,24,opt,name=lookupTopicResponse" json:"lookupTopicResponse,omitempty"` + ConsumerStats *CommandConsumerStats `protobuf:"bytes,25,opt,name=consumerStats" json:"consumerStats,omitempty"` + ConsumerStatsResponse *CommandConsumerStatsResponse `protobuf:"bytes,26,opt,name=consumerStatsResponse" json:"consumerStatsResponse,omitempty"` + ReachedEndOfTopic *CommandReachedEndOfTopic `protobuf:"bytes,27,opt,name=reachedEndOfTopic" json:"reachedEndOfTopic,omitempty"` + Seek *CommandSeek `protobuf:"bytes,28,opt,name=seek" json:"seek,omitempty"` + GetLastMessageId *CommandGetLastMessageId `protobuf:"bytes,29,opt,name=getLastMessageId" json:"getLastMessageId,omitempty"` + GetLastMessageIdResponse *CommandGetLastMessageIdResponse `protobuf:"bytes,30,opt,name=getLastMessageIdResponse" json:"getLastMessageIdResponse,omitempty"` + ActiveConsumerChange *CommandActiveConsumerChange `protobuf:"bytes,31,opt,name=active_consumer_change,json=activeConsumerChange" json:"active_consumer_change,omitempty"` + GetTopicsOfNamespace *CommandGetTopicsOfNamespace `protobuf:"bytes,32,opt,name=getTopicsOfNamespace" json:"getTopicsOfNamespace,omitempty"` + GetTopicsOfNamespaceResponse *CommandGetTopicsOfNamespaceResponse `protobuf:"bytes,33,opt,name=getTopicsOfNamespaceResponse" json:"getTopicsOfNamespaceResponse,omitempty"` + GetSchema *CommandGetSchema `protobuf:"bytes,34,opt,name=getSchema" json:"getSchema,omitempty"` + GetSchemaResponse *CommandGetSchemaResponse `protobuf:"bytes,35,opt,name=getSchemaResponse" json:"getSchemaResponse,omitempty"` + AuthChallenge *CommandAuthChallenge `protobuf:"bytes,36,opt,name=authChallenge" json:"authChallenge,omitempty"` + AuthResponse *CommandAuthResponse `protobuf:"bytes,37,opt,name=authResponse" json:"authResponse,omitempty"` + AckResponse *CommandAckResponse `protobuf:"bytes,38,opt,name=ackResponse" json:"ackResponse,omitempty"` + GetOrCreateSchema *CommandGetOrCreateSchema `protobuf:"bytes,39,opt,name=getOrCreateSchema" json:"getOrCreateSchema,omitempty"` + GetOrCreateSchemaResponse *CommandGetOrCreateSchemaResponse `protobuf:"bytes,40,opt,name=getOrCreateSchemaResponse" json:"getOrCreateSchemaResponse,omitempty"` + // transaction related + NewTxn *CommandNewTxn `protobuf:"bytes,50,opt,name=newTxn" json:"newTxn,omitempty"` + NewTxnResponse *CommandNewTxnResponse `protobuf:"bytes,51,opt,name=newTxnResponse" json:"newTxnResponse,omitempty"` + AddPartitionToTxn *CommandAddPartitionToTxn `protobuf:"bytes,52,opt,name=addPartitionToTxn" json:"addPartitionToTxn,omitempty"` + AddPartitionToTxnResponse *CommandAddPartitionToTxnResponse `protobuf:"bytes,53,opt,name=addPartitionToTxnResponse" json:"addPartitionToTxnResponse,omitempty"` + AddSubscriptionToTxn *CommandAddSubscriptionToTxn `protobuf:"bytes,54,opt,name=addSubscriptionToTxn" json:"addSubscriptionToTxn,omitempty"` + AddSubscriptionToTxnResponse *CommandAddSubscriptionToTxnResponse `protobuf:"bytes,55,opt,name=addSubscriptionToTxnResponse" json:"addSubscriptionToTxnResponse,omitempty"` + EndTxn *CommandEndTxn `protobuf:"bytes,56,opt,name=endTxn" json:"endTxn,omitempty"` + EndTxnResponse *CommandEndTxnResponse `protobuf:"bytes,57,opt,name=endTxnResponse" json:"endTxnResponse,omitempty"` + EndTxnOnPartition *CommandEndTxnOnPartition `protobuf:"bytes,58,opt,name=endTxnOnPartition" json:"endTxnOnPartition,omitempty"` + EndTxnOnPartitionResponse *CommandEndTxnOnPartitionResponse `protobuf:"bytes,59,opt,name=endTxnOnPartitionResponse" json:"endTxnOnPartitionResponse,omitempty"` + EndTxnOnSubscription *CommandEndTxnOnSubscription `protobuf:"bytes,60,opt,name=endTxnOnSubscription" json:"endTxnOnSubscription,omitempty"` + EndTxnOnSubscriptionResponse *CommandEndTxnOnSubscriptionResponse `protobuf:"bytes,61,opt,name=endTxnOnSubscriptionResponse" json:"endTxnOnSubscriptionResponse,omitempty"` + TcClientConnectRequest *CommandTcClientConnectRequest `protobuf:"bytes,62,opt,name=tcClientConnectRequest" json:"tcClientConnectRequest,omitempty"` + TcClientConnectResponse *CommandTcClientConnectResponse `protobuf:"bytes,63,opt,name=tcClientConnectResponse" json:"tcClientConnectResponse,omitempty"` + WatchTopicList *CommandWatchTopicList `protobuf:"bytes,64,opt,name=watchTopicList" json:"watchTopicList,omitempty"` + WatchTopicListSuccess *CommandWatchTopicListSuccess `protobuf:"bytes,65,opt,name=watchTopicListSuccess" json:"watchTopicListSuccess,omitempty"` + WatchTopicUpdate *CommandWatchTopicUpdate `protobuf:"bytes,66,opt,name=watchTopicUpdate" json:"watchTopicUpdate,omitempty"` + WatchTopicListClose *CommandWatchTopicListClose `protobuf:"bytes,67,opt,name=watchTopicListClose" json:"watchTopicListClose,omitempty"` +} + +func (x *BaseCommand) Reset() { + *x = BaseCommand{} + if protoimpl.UnsafeEnabled { + mi := &file_PulsarApi_proto_msgTypes[70] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BaseCommand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BaseCommand) ProtoMessage() {} + +func (x *BaseCommand) ProtoReflect() protoreflect.Message { + mi := &file_PulsarApi_proto_msgTypes[70] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BaseCommand.ProtoReflect.Descriptor instead. +func (*BaseCommand) Descriptor() ([]byte, []int) { + return file_PulsarApi_proto_rawDescGZIP(), []int{70} +} + +func (x *BaseCommand) GetType() BaseCommand_Type { + if x != nil && x.Type != nil { + return *x.Type + } + return BaseCommand_CONNECT +} + +func (x *BaseCommand) GetConnect() *CommandConnect { + if x != nil { + return x.Connect + } + return nil +} + +func (x *BaseCommand) GetConnected() *CommandConnected { + if x != nil { + return x.Connected + } + return nil +} + +func (x *BaseCommand) GetSubscribe() *CommandSubscribe { + if x != nil { + return x.Subscribe + } + return nil +} + +func (x *BaseCommand) GetProducer() *CommandProducer { + if x != nil { + return x.Producer + } + return nil +} + +func (x *BaseCommand) GetSend() *CommandSend { + if x != nil { + return x.Send + } + return nil +} + +func (x *BaseCommand) GetSendReceipt() *CommandSendReceipt { + if x != nil { + return x.SendReceipt + } + return nil +} + +func (x *BaseCommand) GetSendError() *CommandSendError { + if x != nil { + return x.SendError + } + return nil +} + +func (x *BaseCommand) GetMessage() *CommandMessage { + if x != nil { + return x.Message + } + return nil +} + +func (x *BaseCommand) GetAck() *CommandAck { + if x != nil { + return x.Ack + } + return nil +} + +func (x *BaseCommand) GetFlow() *CommandFlow { + if x != nil { + return x.Flow + } + return nil +} + +func (x *BaseCommand) GetUnsubscribe() *CommandUnsubscribe { + if x != nil { + return x.Unsubscribe + } + return nil +} + +func (x *BaseCommand) GetSuccess() *CommandSuccess { + if x != nil { + return x.Success + } + return nil +} + +func (x *BaseCommand) GetError() *CommandError { + if x != nil { + return x.Error + } + return nil +} + +func (x *BaseCommand) GetCloseProducer() *CommandCloseProducer { + if x != nil { + return x.CloseProducer + } + return nil +} + +func (x *BaseCommand) GetCloseConsumer() *CommandCloseConsumer { + if x != nil { + return x.CloseConsumer + } + return nil +} + +func (x *BaseCommand) GetProducerSuccess() *CommandProducerSuccess { + if x != nil { + return x.ProducerSuccess + } + return nil +} + +func (x *BaseCommand) GetPing() *CommandPing { + if x != nil { + return x.Ping + } + return nil +} + +func (x *BaseCommand) GetPong() *CommandPong { + if x != nil { + return x.Pong + } + return nil +} + +func (x *BaseCommand) GetRedeliverUnacknowledgedMessages() *CommandRedeliverUnacknowledgedMessages { + if x != nil { + return x.RedeliverUnacknowledgedMessages + } + return nil +} + +func (x *BaseCommand) GetPartitionMetadata() *CommandPartitionedTopicMetadata { + if x != nil { + return x.PartitionMetadata + } + return nil +} + +func (x *BaseCommand) GetPartitionMetadataResponse() *CommandPartitionedTopicMetadataResponse { + if x != nil { + return x.PartitionMetadataResponse + } + return nil +} + +func (x *BaseCommand) GetLookupTopic() *CommandLookupTopic { + if x != nil { + return x.LookupTopic + } + return nil +} + +func (x *BaseCommand) GetLookupTopicResponse() *CommandLookupTopicResponse { + if x != nil { + return x.LookupTopicResponse + } + return nil +} + +func (x *BaseCommand) GetConsumerStats() *CommandConsumerStats { + if x != nil { + return x.ConsumerStats + } + return nil +} + +func (x *BaseCommand) GetConsumerStatsResponse() *CommandConsumerStatsResponse { + if x != nil { + return x.ConsumerStatsResponse + } + return nil +} + +func (x *BaseCommand) GetReachedEndOfTopic() *CommandReachedEndOfTopic { + if x != nil { + return x.ReachedEndOfTopic + } + return nil +} + +func (x *BaseCommand) GetSeek() *CommandSeek { + if x != nil { + return x.Seek + } + return nil +} + +func (x *BaseCommand) GetGetLastMessageId() *CommandGetLastMessageId { + if x != nil { + return x.GetLastMessageId + } + return nil +} + +func (x *BaseCommand) GetGetLastMessageIdResponse() *CommandGetLastMessageIdResponse { + if x != nil { + return x.GetLastMessageIdResponse + } + return nil +} + +func (x *BaseCommand) GetActiveConsumerChange() *CommandActiveConsumerChange { + if x != nil { + return x.ActiveConsumerChange + } + return nil +} + +func (x *BaseCommand) GetGetTopicsOfNamespace() *CommandGetTopicsOfNamespace { + if x != nil { + return x.GetTopicsOfNamespace + } + return nil +} + +func (x *BaseCommand) GetGetTopicsOfNamespaceResponse() *CommandGetTopicsOfNamespaceResponse { + if x != nil { + return x.GetTopicsOfNamespaceResponse + } + return nil +} + +func (x *BaseCommand) GetGetSchema() *CommandGetSchema { + if x != nil { + return x.GetSchema + } + return nil +} + +func (x *BaseCommand) GetGetSchemaResponse() *CommandGetSchemaResponse { + if x != nil { + return x.GetSchemaResponse + } + return nil +} + +func (x *BaseCommand) GetAuthChallenge() *CommandAuthChallenge { + if x != nil { + return x.AuthChallenge + } + return nil +} + +func (x *BaseCommand) GetAuthResponse() *CommandAuthResponse { + if x != nil { + return x.AuthResponse + } + return nil +} + +func (x *BaseCommand) GetAckResponse() *CommandAckResponse { + if x != nil { + return x.AckResponse + } + return nil +} + +func (x *BaseCommand) GetGetOrCreateSchema() *CommandGetOrCreateSchema { + if x != nil { + return x.GetOrCreateSchema + } + return nil +} + +func (x *BaseCommand) GetGetOrCreateSchemaResponse() *CommandGetOrCreateSchemaResponse { + if x != nil { + return x.GetOrCreateSchemaResponse + } + return nil +} + +func (x *BaseCommand) GetNewTxn() *CommandNewTxn { + if x != nil { + return x.NewTxn + } + return nil +} + +func (x *BaseCommand) GetNewTxnResponse() *CommandNewTxnResponse { + if x != nil { + return x.NewTxnResponse + } + return nil +} + +func (x *BaseCommand) GetAddPartitionToTxn() *CommandAddPartitionToTxn { + if x != nil { + return x.AddPartitionToTxn + } + return nil +} + +func (x *BaseCommand) GetAddPartitionToTxnResponse() *CommandAddPartitionToTxnResponse { + if x != nil { + return x.AddPartitionToTxnResponse + } + return nil +} + +func (x *BaseCommand) GetAddSubscriptionToTxn() *CommandAddSubscriptionToTxn { + if x != nil { + return x.AddSubscriptionToTxn + } + return nil +} + +func (x *BaseCommand) GetAddSubscriptionToTxnResponse() *CommandAddSubscriptionToTxnResponse { + if x != nil { + return x.AddSubscriptionToTxnResponse + } + return nil +} + +func (x *BaseCommand) GetEndTxn() *CommandEndTxn { + if x != nil { + return x.EndTxn + } + return nil +} + +func (x *BaseCommand) GetEndTxnResponse() *CommandEndTxnResponse { + if x != nil { + return x.EndTxnResponse + } + return nil +} + +func (x *BaseCommand) GetEndTxnOnPartition() *CommandEndTxnOnPartition { + if x != nil { + return x.EndTxnOnPartition + } + return nil +} + +func (x *BaseCommand) GetEndTxnOnPartitionResponse() *CommandEndTxnOnPartitionResponse { + if x != nil { + return x.EndTxnOnPartitionResponse + } + return nil +} + +func (x *BaseCommand) GetEndTxnOnSubscription() *CommandEndTxnOnSubscription { + if x != nil { + return x.EndTxnOnSubscription + } + return nil +} + +func (x *BaseCommand) GetEndTxnOnSubscriptionResponse() *CommandEndTxnOnSubscriptionResponse { + if x != nil { + return x.EndTxnOnSubscriptionResponse + } + return nil +} + +func (x *BaseCommand) GetTcClientConnectRequest() *CommandTcClientConnectRequest { + if x != nil { + return x.TcClientConnectRequest + } + return nil +} + +func (x *BaseCommand) GetTcClientConnectResponse() *CommandTcClientConnectResponse { + if x != nil { + return x.TcClientConnectResponse + } + return nil +} + +func (x *BaseCommand) GetWatchTopicList() *CommandWatchTopicList { + if x != nil { + return x.WatchTopicList + } + return nil +} + +func (x *BaseCommand) GetWatchTopicListSuccess() *CommandWatchTopicListSuccess { + if x != nil { + return x.WatchTopicListSuccess + } + return nil +} + +func (x *BaseCommand) GetWatchTopicUpdate() *CommandWatchTopicUpdate { + if x != nil { + return x.WatchTopicUpdate + } + return nil +} + +func (x *BaseCommand) GetWatchTopicListClose() *CommandWatchTopicListClose { + if x != nil { + return x.WatchTopicListClose + } + return nil +} + +var File_PulsarApi_proto protoreflect.FileDescriptor + +var file_PulsarApi_proto_rawDesc = []byte{ + 0x0a, 0x0f, 0x50, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x41, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x0c, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0xb4, 0x03, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, + 0x02, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x44, 0x61, 0x74, 0x61, 0x12, + 0x2d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x19, 0x2e, + 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x36, + 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x8d, 0x02, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4a, 0x73, 0x6f, 0x6e, 0x10, 0x02, 0x12, + 0x0c, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x10, 0x03, 0x12, 0x08, 0x0a, + 0x04, 0x41, 0x76, 0x72, 0x6f, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x6f, 0x6f, 0x6c, 0x10, + 0x05, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x6e, 0x74, 0x38, 0x10, 0x06, 0x12, 0x09, 0x0a, 0x05, 0x49, + 0x6e, 0x74, 0x31, 0x36, 0x10, 0x07, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x10, + 0x08, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x10, 0x09, 0x12, 0x09, 0x0a, 0x05, + 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x10, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x6f, 0x75, 0x62, 0x6c, + 0x65, 0x10, 0x0b, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x65, 0x10, 0x0c, 0x12, 0x08, 0x0a, + 0x04, 0x54, 0x69, 0x6d, 0x65, 0x10, 0x0d, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x10, 0x0e, 0x12, 0x0c, 0x0a, 0x08, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x10, 0x0f, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x10, + 0x10, 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x44, 0x61, 0x74, 0x65, 0x10, 0x11, + 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x10, 0x12, 0x12, + 0x11, 0x0a, 0x0d, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, + 0x10, 0x13, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x4e, 0x61, + 0x74, 0x69, 0x76, 0x65, 0x10, 0x14, 0x22, 0x96, 0x02, 0x0a, 0x0d, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x49, 0x64, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x65, 0x64, 0x67, + 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x08, 0x6c, 0x65, 0x64, 0x67, + 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x49, 0x64, 0x18, + 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x49, 0x64, 0x12, 0x20, + 0x0a, 0x09, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x05, 0x3a, 0x02, 0x2d, 0x31, 0x52, 0x09, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x23, 0x0a, 0x0b, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x02, 0x2d, 0x31, 0x52, 0x0a, 0x62, 0x61, 0x74, 0x63, 0x68, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x63, 0x6b, 0x5f, 0x73, 0x65, 0x74, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x03, 0x52, 0x06, 0x61, 0x63, 0x6b, 0x53, 0x65, 0x74, 0x12, 0x1d, + 0x0a, 0x0a, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x09, 0x62, 0x61, 0x74, 0x63, 0x68, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x50, 0x0a, + 0x16, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x13, 0x66, 0x69, 0x72, 0x73, + 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x22, + 0x32, 0x0a, 0x08, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x22, 0x36, 0x0a, 0x0c, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x6e, 0x67, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x02, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x32, 0x0a, 0x08, 0x49, + 0x6e, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x18, 0x01, 0x20, 0x02, 0x28, 0x05, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, + 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x05, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, + 0x6c, 0x0a, 0x0e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, + 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x02, + 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x75, + 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xd1, 0x09, + 0x0a, 0x0f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, + 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, 0x73, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x73, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0b, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4b, 0x65, + 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x23, 0x0a, 0x0d, 0x70, + 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, + 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x6f, + 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x54, 0x6f, 0x12, 0x45, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x52, 0x0b, 0x63, + 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x11, 0x75, 0x6e, + 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x0d, 0x3a, 0x01, 0x30, 0x52, 0x10, 0x75, 0x6e, 0x63, 0x6f, 0x6d, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x6e, 0x75, + 0x6d, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x5f, 0x69, 0x6e, 0x5f, 0x62, 0x61, + 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x01, 0x31, 0x52, 0x12, 0x6e, 0x75, + 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, + 0x12, 0x20, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x45, 0x0a, 0x0f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x75, + 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x0e, 0x65, 0x6e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x6e, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x18, 0x0e, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x6c, + 0x67, 0x6f, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x6e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x12, 0x25, 0x0a, + 0x0e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x10, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x19, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x62, 0x36, 0x34, 0x5f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, + 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x16, + 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x42, 0x36, 0x34, 0x45, + 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0f, 0x64, 0x65, 0x6c, + 0x69, 0x76, 0x65, 0x72, 0x5f, 0x61, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x13, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x41, 0x74, 0x54, 0x69, 0x6d, + 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6c, 0x65, 0x61, 0x73, + 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x78, + 0x6e, 0x69, 0x64, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x26, 0x0a, 0x0f, + 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6d, 0x6f, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, + 0x17, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4d, 0x6f, 0x73, 0x74, + 0x42, 0x69, 0x74, 0x73, 0x12, 0x31, 0x0a, 0x13, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x5f, + 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, + 0x04, 0x3a, 0x01, 0x30, 0x52, 0x11, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x53, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0a, 0x6e, 0x75, 0x6c, 0x6c, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, + 0x73, 0x65, 0x52, 0x09, 0x6e, 0x75, 0x6c, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, + 0x64, 0x12, 0x2d, 0x0a, 0x13, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x5f, + 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, + 0x6e, 0x75, 0x6d, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x4d, 0x73, 0x67, + 0x12, 0x2f, 0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, + 0x6d, 0x73, 0x67, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x4d, 0x73, 0x67, 0x53, 0x69, 0x7a, + 0x65, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x1d, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x07, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x49, 0x64, 0x12, 0x33, 0x0a, 0x12, + 0x6e, 0x75, 0x6c, 0x6c, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, + 0x10, 0x6e, 0x75, 0x6c, 0x6c, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, + 0x79, 0x22, 0xc6, 0x03, 0x0a, 0x15, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x36, 0x0a, 0x0a, 0x70, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4b, + 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, + 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x74, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x02, 0x28, 0x05, 0x52, 0x0b, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x2a, 0x0a, 0x0d, 0x63, + 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x63, 0x74, 0x65, 0x64, 0x4f, 0x75, 0x74, 0x12, 0x20, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x09, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x19, 0x70, 0x61, 0x72, + 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x62, 0x36, 0x34, 0x5f, 0x65, + 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, + 0x6c, 0x73, 0x65, 0x52, 0x16, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, + 0x79, 0x42, 0x36, 0x34, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6f, + 0x72, 0x64, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0b, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x1f, + 0x0a, 0x0b, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0a, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, + 0x24, 0x0a, 0x0a, 0x6e, 0x75, 0x6c, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x09, 0x6e, 0x75, 0x6c, 0x6c, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x33, 0x0a, 0x12, 0x6e, 0x75, 0x6c, 0x6c, 0x5f, 0x70, 0x61, + 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x10, 0x6e, 0x75, 0x6c, 0x6c, 0x50, 0x61, + 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x22, 0x56, 0x0a, 0x13, 0x42, 0x72, + 0x6f, 0x6b, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x29, 0x0a, 0x10, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x62, 0x72, 0x6f, + 0x6b, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x14, 0x0a, 0x05, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x22, 0xe6, 0x03, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x0d, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0b, + 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x18, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x0a, 0x61, 0x75, 0x74, + 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x61, 0x75, 0x74, 0x68, 0x5f, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2c, + 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x01, 0x30, 0x52, 0x0f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x13, + 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x74, 0x6f, 0x5f, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x5f, + 0x75, 0x72, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x78, 0x79, + 0x54, 0x6f, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x2d, 0x0a, 0x12, 0x6f, + 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, + 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, + 0x6c, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x2c, 0x0a, 0x12, 0x6f, 0x72, + 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, + 0x41, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x12, 0x30, 0x0a, 0x14, 0x6f, 0x72, 0x69, 0x67, + 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, + 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x3f, 0x0a, 0x0d, 0x66, 0x65, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x52, 0x0c, 0x66, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x22, 0x97, 0x02, 0x0a, 0x0c, + 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x39, 0x0a, 0x15, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x72, 0x65, + 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, + 0x73, 0x65, 0x52, 0x13, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x41, 0x75, 0x74, 0x68, + 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x4a, 0x0a, 0x1e, 0x73, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x73, 0x5f, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x3a, + 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x1b, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, + 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x19, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, + 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x17, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x17, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x73, 0x5f, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x5f, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, + 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x15, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x57, 0x61, 0x74, + 0x63, 0x68, 0x65, 0x72, 0x73, 0x22, 0xd2, 0x01, 0x0a, 0x10, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x02, + 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x2c, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x01, 0x30, 0x52, 0x0f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, + 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x66, 0x65, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x52, 0x0c, 0x66, 0x65, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x22, 0x9e, 0x01, 0x0a, 0x13, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x08, 0x72, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x75, + 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x44, + 0x61, 0x74, 0x61, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, + 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x01, 0x30, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xa1, 0x01, 0x0a, 0x14, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x75, 0x74, 0x68, 0x43, 0x68, 0x61, 0x6c, 0x6c, + 0x65, 0x6e, 0x67, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x09, 0x63, + 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x75, + 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, + 0x65, 0x12, 0x2c, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x01, 0x30, 0x52, 0x0f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, + 0x51, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x12, 0x28, 0x0a, 0x10, 0x61, + 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, + 0x74, 0x61, 0x22, 0xcb, 0x01, 0x0a, 0x0d, 0x4b, 0x65, 0x79, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, + 0x4d, 0x65, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x0d, 0x6b, 0x65, 0x79, 0x53, 0x68, 0x61, 0x72, 0x65, + 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x70, 0x75, + 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4b, 0x65, 0x79, 0x53, 0x68, + 0x61, 0x72, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0d, 0x6b, 0x65, 0x79, 0x53, 0x68, 0x61, + 0x72, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x36, 0x0a, 0x0a, 0x68, 0x61, 0x73, 0x68, 0x52, + 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x75, + 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x61, + 0x6e, 0x67, 0x65, 0x52, 0x0a, 0x68, 0x61, 0x73, 0x68, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, + 0x3f, 0x0a, 0x17, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4f, 0x75, 0x74, 0x4f, 0x66, 0x4f, 0x72, 0x64, + 0x65, 0x72, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x17, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4f, 0x75, + 0x74, 0x4f, 0x66, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, + 0x22, 0xe3, 0x08, 0x0a, 0x10, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x01, + 0x20, 0x02, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x22, 0x0a, 0x0c, 0x73, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x02, 0x28, + 0x09, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x40, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x02, 0x28, 0x0e, + 0x32, 0x26, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x2e, 0x53, 0x75, 0x62, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x73, 0x75, 0x62, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x04, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x05, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, + 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, + 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1e, 0x0a, + 0x07, 0x64, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x04, + 0x74, 0x72, 0x75, 0x65, 0x52, 0x07, 0x64, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x45, 0x0a, + 0x10, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, + 0x44, 0x61, 0x74, 0x61, 0x52, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x61, 0x64, + 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0d, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x65, 0x64, 0x12, + 0x2c, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x60, 0x0a, + 0x0f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x6f, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x06, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x52, 0x0f, + 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x40, 0x0a, 0x1c, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, + 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x36, 0x0a, 0x14, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x6f, 0x70, 0x69, 0x63, + 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x3a, + 0x04, 0x74, 0x72, 0x75, 0x65, 0x52, 0x12, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x54, 0x6f, 0x70, 0x69, + 0x63, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4f, 0x0a, 0x23, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x72, 0x6f, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x63, + 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x1f, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x44, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x12, 0x41, 0x0a, 0x0d, 0x6b, 0x65, + 0x79, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x11, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x4b, 0x65, 0x79, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x0d, + 0x6b, 0x65, 0x79, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x4f, 0x0a, + 0x17, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4b, 0x65, + 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x25, + 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, + 0x18, 0x13, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, + 0x45, 0x70, 0x6f, 0x63, 0x68, 0x22, 0x42, 0x0a, 0x07, 0x53, 0x75, 0x62, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x0d, 0x0a, 0x09, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x10, 0x00, 0x12, + 0x0a, 0x0a, 0x06, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x46, + 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x4b, 0x65, 0x79, + 0x5f, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x10, 0x03, 0x22, 0x2b, 0x0a, 0x0f, 0x49, 0x6e, 0x69, + 0x74, 0x69, 0x61, 0x6c, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, + 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x61, 0x72, 0x6c, + 0x69, 0x65, 0x73, 0x74, 0x10, 0x01, 0x22, 0xe5, 0x01, 0x0a, 0x1f, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x54, 0x6f, 0x70, + 0x69, 0x63, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, + 0x70, 0x69, 0x63, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, + 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, + 0x2d, 0x0a, 0x12, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x69, 0x6e, + 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f, 0x72, 0x69, + 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x2c, + 0x0a, 0x12, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x72, 0x69, 0x67, + 0x69, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x12, 0x30, 0x0a, 0x14, + 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6f, 0x72, 0x69, 0x67, + 0x69, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x22, 0xb8, + 0x02, 0x0a, 0x27, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, + 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, + 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x5c, 0x0a, 0x08, 0x72, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x40, 0x2e, 0x70, 0x75, + 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x54, 0x6f, 0x70, + 0x69, 0x63, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x72, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x25, 0x0a, 0x0a, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, + 0x06, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x10, 0x01, 0x22, 0xbf, 0x02, 0x0a, 0x12, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x54, 0x6f, 0x70, 0x69, 0x63, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, + 0x6c, 0x73, 0x65, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x70, + 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, + 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, + 0x6c, 0x12, 0x2c, 0x0a, 0x12, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, + 0x74, 0x68, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, + 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x12, + 0x30, 0x0a, 0x14, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, + 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6f, + 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x12, 0x38, 0x0a, 0x18, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x5f, + 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x16, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x4c, + 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xd9, 0x03, 0x0a, 0x1a, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x54, 0x6f, 0x70, + 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x62, 0x72, + 0x6f, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x72, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x30, 0x0a, 0x13, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x72, 0x6c, 0x54, 0x6c, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x13, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x55, 0x72, 0x6c, 0x54, 0x6c, 0x73, 0x12, 0x4f, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x70, 0x75, 0x6c, + 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x3a, + 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x40, 0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, + 0x68, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x16, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x54, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, + 0x72, 0x6c, 0x22, 0x33, 0x0a, 0x0a, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, 0x00, 0x12, 0x0b, + 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x46, + 0x61, 0x69, 0x6c, 0x65, 0x64, 0x10, 0x02, 0x22, 0xd2, 0x04, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x6f, 0x70, 0x69, 0x63, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, + 0x63, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x03, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, + 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x09, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, + 0x52, 0x09, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x12, 0x32, 0x0a, 0x08, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4b, 0x65, 0x79, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, + 0x2c, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x17, 0x0a, + 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, + 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x43, 0x0a, 0x1b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x04, 0x74, 0x72, 0x75, + 0x65, 0x52, 0x18, 0x75, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x50, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x5a, 0x0a, 0x14, 0x70, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6d, + 0x6f, 0x64, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x70, 0x75, 0x6c, 0x73, + 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, + 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x06, 0x53, 0x68, 0x61, + 0x72, 0x65, 0x64, 0x52, 0x12, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x70, 0x69, 0x63, + 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, + 0x70, 0x69, 0x63, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x26, 0x0a, 0x0b, 0x74, 0x78, 0x6e, 0x5f, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, + 0x61, 0x6c, 0x73, 0x65, 0x52, 0x0a, 0x74, 0x78, 0x6e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x12, 0x3a, 0x0a, 0x19, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x17, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xfd, 0x02, 0x0a, + 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x1f, 0x0a, 0x0b, + 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, + 0x04, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, + 0x0b, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x02, + 0x28, 0x04, 0x52, 0x0a, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x24, + 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x3a, 0x01, 0x31, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x10, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6c, 0x65, + 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, + 0x30, 0x52, 0x0e, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x42, 0x69, 0x74, + 0x73, 0x12, 0x29, 0x0a, 0x0f, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6d, 0x6f, 0x73, 0x74, 0x5f, + 0x62, 0x69, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0d, 0x74, + 0x78, 0x6e, 0x69, 0x64, 0x4d, 0x6f, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x31, 0x0a, 0x13, + 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x11, 0x68, 0x69, + 0x67, 0x68, 0x65, 0x73, 0x74, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, + 0x20, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x07, 0x69, 0x73, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x12, 0x1d, 0x0a, 0x06, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x06, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x72, + 0x12, 0x3a, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x44, 0x61, 0x74, + 0x61, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x22, 0xc5, 0x01, 0x0a, + 0x12, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x63, 0x65, + 0x69, 0x70, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, + 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, 0x73, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x3a, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x75, 0x6c, 0x73, + 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x49, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, + 0x64, 0x12, 0x31, 0x0a, 0x13, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, + 0x30, 0x52, 0x11, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x65, 0x49, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x10, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x53, 0x65, 0x6e, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, + 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, + 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, + 0x0a, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, + 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x02, 0x28, 0x09, 0x52, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xdb, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, + 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x49, 0x64, 0x12, 0x3a, 0x0a, 0x0a, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x09, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x10, 0x72, 0x65, 0x64, 0x65, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x3a, 0x01, 0x30, 0x52, 0x0f, 0x72, 0x65, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x63, 0x6b, 0x5f, 0x73, 0x65, 0x74, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x03, 0x52, 0x06, 0x61, 0x63, 0x6b, 0x53, 0x65, 0x74, 0x12, 0x25, 0x0a, + 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x45, + 0x70, 0x6f, 0x63, 0x68, 0x22, 0xeb, 0x04, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x41, 0x63, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, + 0x65, 0x72, 0x49, 0x64, 0x12, 0x3b, 0x0a, 0x08, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x02, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x63, 0x6b, + 0x2e, 0x41, 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x61, 0x63, 0x6b, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x3a, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x44, 0x61, + 0x74, 0x61, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x53, 0x0a, + 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x63, + 0x6b, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x52, 0x0f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x6e, 0x67, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x2b, + 0x0a, 0x10, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, + 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0e, 0x74, 0x78, 0x6e, + 0x69, 0x64, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x29, 0x0a, 0x0f, 0x74, + 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6d, 0x6f, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0d, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4d, 0x6f, + 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x29, 0x0a, 0x07, 0x41, 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x6e, 0x64, 0x69, 0x76, 0x69, 0x64, 0x75, 0x61, 0x6c, 0x10, 0x00, + 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x10, 0x01, + 0x22, 0x8f, 0x01, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1e, 0x0a, 0x1a, 0x55, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x72, 0x72, 0x75, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x65, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x4d, 0x69, 0x73, 0x6d, 0x61, 0x74, 0x63, 0x68, + 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x42, 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x03, 0x12, 0x13, 0x0a, + 0x0f, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x10, 0x04, 0x22, 0xf7, 0x01, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x63, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, + 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x10, 0x74, 0x78, + 0x6e, 0x69, 0x64, 0x5f, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0e, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4c, 0x65, + 0x61, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x29, 0x0a, 0x0f, 0x74, 0x78, 0x6e, 0x69, 0x64, + 0x5f, 0x6d, 0x6f, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, + 0x3a, 0x01, 0x30, 0x52, 0x0d, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4d, 0x6f, 0x73, 0x74, 0x42, 0x69, + 0x74, 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x62, 0x0a, 0x1b, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x6e, + 0x73, 0x75, 0x6d, 0x65, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, + 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x09, + 0x69, 0x73, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x3a, + 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x08, 0x69, 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x22, 0x56, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x46, 0x6c, 0x6f, 0x77, 0x12, + 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x49, 0x64, + 0x12, 0x26, 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x02, 0x28, 0x0d, 0x52, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x73, 0x22, 0x54, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x02, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x49, 0x64, 0x12, + 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0xbb, + 0x01, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x65, 0x65, 0x6b, 0x12, 0x1f, + 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x02, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x49, 0x64, 0x12, + 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x3a, + 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x3b, 0x0a, 0x18, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x61, 0x63, 0x68, 0x65, 0x64, 0x45, 0x6e, + 0x64, 0x4f, 0x66, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x49, 0x64, 0x22, 0x56, 0x0a, 0x14, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, + 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x64, 0x22, 0x56, 0x0a, 0x14, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x43, 0x6c, 0x6f, 0x73, + 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, + 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0xae, 0x01, 0x0a, 0x26, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x55, 0x6e, + 0x61, 0x63, 0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6d, 0x65, 0x72, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x0b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x75, 0x6c, + 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x49, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x49, 0x64, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, + 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x63, 0x6f, 0x6e, + 0x73, 0x75, 0x6d, 0x65, 0x72, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x22, 0x5d, 0x0a, 0x0e, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, + 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x06, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x75, + 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, 0xff, 0x01, 0x0a, 0x16, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x53, 0x75, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, + 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x03, 0x3a, 0x02, 0x2d, 0x31, 0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, + 0x0b, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x2b, + 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x79, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x04, 0x74, 0x72, 0x75, 0x65, 0x52, 0x0d, 0x70, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x52, 0x65, 0x61, 0x64, 0x79, 0x22, 0x78, 0x0a, 0x0c, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, + 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, + 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x02, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x0d, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x50, 0x69, 0x6e, 0x67, 0x22, 0x0d, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, + 0x6f, 0x6e, 0x67, 0x22, 0x56, 0x0a, 0x14, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x43, 0x6f, + 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, + 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, + 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x02, 0x28, 0x04, 0x52, + 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x49, 0x64, 0x22, 0x98, 0x05, 0x0a, 0x1c, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, + 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x0a, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x73, + 0x67, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, + 0x6d, 0x73, 0x67, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x75, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x6d, 0x73, + 0x67, 0x54, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x70, 0x75, 0x74, 0x4f, 0x75, 0x74, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x01, 0x52, 0x10, 0x6d, 0x73, 0x67, 0x54, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, + 0x70, 0x75, 0x74, 0x4f, 0x75, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x6d, 0x73, 0x67, 0x52, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x01, + 0x52, 0x10, 0x6d, 0x73, 0x67, 0x52, 0x61, 0x74, 0x65, 0x52, 0x65, 0x64, 0x65, 0x6c, 0x69, 0x76, + 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, + 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, + 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x10, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, + 0x74, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x75, 0x6e, 0x61, + 0x63, 0x6b, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x1c, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x4f, + 0x6e, 0x55, 0x6e, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x1c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x73, 0x75, + 0x6d, 0x65, 0x72, 0x4f, 0x6e, 0x55, 0x6e, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x73, + 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6e, 0x63, 0x65, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6e, + 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x6d, 0x73, 0x67, 0x52, 0x61, 0x74, + 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0e, + 0x6d, 0x73, 0x67, 0x52, 0x61, 0x74, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x12, 0x1e, + 0x0a, 0x0a, 0x6d, 0x73, 0x67, 0x42, 0x61, 0x63, 0x6b, 0x6c, 0x6f, 0x67, 0x18, 0x0f, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0a, 0x6d, 0x73, 0x67, 0x42, 0x61, 0x63, 0x6b, 0x6c, 0x6f, 0x67, 0x12, 0x26, + 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x41, 0x63, 0x6b, 0x52, 0x61, 0x74, 0x65, + 0x18, 0x10, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x41, + 0x63, 0x6b, 0x52, 0x61, 0x74, 0x65, 0x22, 0x59, 0x0a, 0x17, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, + 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x64, 0x22, 0xe5, 0x01, 0x0a, 0x1f, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x47, 0x65, 0x74, + 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x6c, 0x61, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x5e, 0x0a, 0x1d, 0x63, 0x6f, 0x6e, + 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x1a, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x4d, 0x61, 0x72, 0x6b, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa7, 0x02, 0x0a, 0x1b, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x4f, 0x66, + 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x4e, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x54, 0x6f, + 0x70, 0x69, 0x63, 0x73, 0x4f, 0x66, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, + 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x0a, 0x50, 0x45, 0x52, 0x53, 0x49, 0x53, 0x54, 0x45, 0x4e, 0x54, + 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, + 0x5f, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x1f, 0x0a, + 0x0b, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x48, 0x61, 0x73, 0x68, 0x22, 0x33, + 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x45, 0x52, 0x53, 0x49, 0x53, + 0x54, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4e, 0x4f, 0x4e, 0x5f, 0x50, 0x45, + 0x52, 0x53, 0x49, 0x53, 0x54, 0x45, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4c, + 0x4c, 0x10, 0x02, 0x22, 0xc0, 0x01, 0x0a, 0x23, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x47, + 0x65, 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x4f, 0x66, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, + 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6f, + 0x70, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6f, 0x70, 0x69, + 0x63, 0x73, 0x12, 0x21, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x08, 0x66, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x5f, + 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x70, 0x69, + 0x63, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1e, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x04, 0x74, 0x72, 0x75, 0x65, 0x52, 0x07, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x22, 0xbb, 0x01, 0x0a, 0x15, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x57, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, + 0x1d, 0x0a, 0x0a, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x02, 0x28, 0x04, 0x52, 0x09, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, + 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x02, 0x28, + 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, + 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x04, + 0x20, 0x02, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x50, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x5f, 0x68, 0x61, + 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, + 0x48, 0x61, 0x73, 0x68, 0x22, 0x93, 0x01, 0x0a, 0x1c, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x57, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x70, + 0x69, 0x63, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x02, 0x28, 0x09, 0x52, 0x0a, + 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x48, 0x61, 0x73, 0x68, 0x22, 0x9f, 0x01, 0x0a, 0x17, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x57, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, 0x69, 0x63, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x77, 0x61, 0x74, 0x63, + 0x68, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x77, 0x5f, 0x74, 0x6f, 0x70, + 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x77, 0x54, 0x6f, + 0x70, 0x69, 0x63, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, + 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, + 0x6f, 0x70, 0x69, 0x63, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x02, 0x28, 0x09, + 0x52, 0x0a, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x48, 0x61, 0x73, 0x68, 0x22, 0x5a, 0x0a, 0x1a, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x57, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, 0x69, + 0x63, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x77, 0x61, 0x74, + 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x77, + 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x49, 0x64, 0x22, 0x6e, 0x0a, 0x10, 0x43, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x1d, 0x0a, 0x0a, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, + 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x6f, 0x70, 0x69, 0x63, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, + 0x63, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x73, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xed, 0x01, 0x0a, 0x18, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, + 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, + 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x73, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x7d, 0x0a, 0x18, 0x43, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x02, 0x20, 0x02, + 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x2c, 0x0a, 0x06, 0x73, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x18, 0x03, 0x20, 0x02, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x75, 0x6c, 0x73, + 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, + 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, 0xc7, 0x01, 0x0a, 0x20, 0x43, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, + 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x0a, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0d, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x22, 0x56, 0x0a, 0x1d, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x54, 0x63, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x64, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, + 0x3a, 0x01, 0x30, 0x52, 0x04, 0x74, 0x63, 0x49, 0x64, 0x22, 0x8a, 0x01, 0x0a, 0x1e, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x54, 0x63, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, + 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, + 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x71, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x4e, 0x65, 0x77, 0x54, 0x78, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x0f, 0x74, 0x78, 0x6e, 0x5f, 0x74, 0x74, + 0x6c, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x3a, + 0x01, 0x30, 0x52, 0x0d, 0x74, 0x78, 0x6e, 0x54, 0x74, 0x6c, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x73, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, + 0x3a, 0x01, 0x30, 0x52, 0x04, 0x74, 0x63, 0x49, 0x64, 0x22, 0xd9, 0x01, 0x0a, 0x15, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4e, 0x65, 0x77, 0x54, 0x78, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x10, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6c, 0x65, 0x61, 0x73, + 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, + 0x0e, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, + 0x29, 0x0a, 0x0f, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6d, 0x6f, 0x73, 0x74, 0x5f, 0x62, 0x69, + 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0d, 0x74, 0x78, 0x6e, + 0x69, 0x64, 0x4d, 0x6f, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, + 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb1, 0x01, 0x0a, 0x18, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x41, 0x64, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x54, + 0x78, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x64, 0x12, 0x2b, 0x0a, 0x10, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6c, 0x65, 0x61, 0x73, 0x74, + 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0e, + 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x29, + 0x0a, 0x0f, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6d, 0x6f, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0d, 0x74, 0x78, 0x6e, 0x69, + 0x64, 0x4d, 0x6f, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x72, + 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x70, + 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe4, 0x01, 0x0a, 0x20, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x54, 0x6f, 0x54, 0x78, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, + 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, + 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2b, 0x0a, + 0x10, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0e, 0x74, 0x78, 0x6e, 0x69, + 0x64, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x29, 0x0a, 0x0f, 0x74, 0x78, + 0x6e, 0x69, 0x64, 0x5f, 0x6d, 0x6f, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0d, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4d, 0x6f, 0x73, + 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0x48, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xd4, 0x01, 0x0a, 0x1b, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x54, 0x78, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x10, 0x74, 0x78, 0x6e, + 0x69, 0x64, 0x5f, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0e, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4c, 0x65, 0x61, + 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x29, 0x0a, 0x0f, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, + 0x6d, 0x6f, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x3a, + 0x01, 0x30, 0x52, 0x0d, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4d, 0x6f, 0x73, 0x74, 0x42, 0x69, 0x74, + 0x73, 0x12, 0x3e, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0xe7, 0x01, 0x0a, 0x23, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x64, 0x64, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x54, 0x78, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x10, 0x74, 0x78, 0x6e, 0x69, + 0x64, 0x5f, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0e, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4c, 0x65, 0x61, 0x73, + 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x29, 0x0a, 0x0f, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6d, + 0x6f, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, + 0x30, 0x52, 0x0d, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4d, 0x6f, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, + 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xbe, 0x01, 0x0a, 0x0d, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x12, 0x1d, 0x0a, + 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, + 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x10, + 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0e, 0x74, 0x78, 0x6e, 0x69, 0x64, + 0x4c, 0x65, 0x61, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x29, 0x0a, 0x0f, 0x74, 0x78, 0x6e, + 0x69, 0x64, 0x5f, 0x6d, 0x6f, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0d, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4d, 0x6f, 0x73, 0x74, + 0x42, 0x69, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x0a, 0x74, 0x78, 0x6e, 0x5f, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x78, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x09, 0x74, 0x78, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xd9, 0x01, 0x0a, + 0x15, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x10, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6c, + 0x65, 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x3a, + 0x01, 0x30, 0x52, 0x0e, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x42, 0x69, + 0x74, 0x73, 0x12, 0x29, 0x0a, 0x0f, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6d, 0x6f, 0x73, 0x74, + 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0d, + 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4d, 0x6f, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x2f, 0x0a, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, + 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, + 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa8, 0x02, 0x0a, 0x18, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x50, 0x61, 0x72, 0x74, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x10, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6c, 0x65, + 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, + 0x30, 0x52, 0x0e, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x42, 0x69, 0x74, + 0x73, 0x12, 0x29, 0x0a, 0x0f, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6d, 0x6f, 0x73, 0x74, 0x5f, + 0x62, 0x69, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0d, 0x74, + 0x78, 0x6e, 0x69, 0x64, 0x4d, 0x6f, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, + 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, + 0x69, 0x63, 0x12, 0x36, 0x0a, 0x0a, 0x74, 0x78, 0x6e, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x78, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x09, 0x74, 0x78, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x21, 0x74, 0x78, + 0x6e, 0x69, 0x64, 0x5f, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x5f, 0x6f, + 0x66, 0x5f, 0x6c, 0x6f, 0x77, 0x5f, 0x77, 0x61, 0x74, 0x65, 0x72, 0x6d, 0x61, 0x72, 0x6b, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1c, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4c, 0x65, 0x61, 0x73, + 0x74, 0x42, 0x69, 0x74, 0x73, 0x4f, 0x66, 0x4c, 0x6f, 0x77, 0x57, 0x61, 0x74, 0x65, 0x72, 0x6d, + 0x61, 0x72, 0x6b, 0x22, 0xe4, 0x01, 0x0a, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, + 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x10, 0x74, 0x78, 0x6e, 0x69, 0x64, + 0x5f, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0e, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4c, 0x65, 0x61, 0x73, 0x74, + 0x42, 0x69, 0x74, 0x73, 0x12, 0x29, 0x0a, 0x0f, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, 0x6d, 0x6f, + 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, + 0x52, 0x0d, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4d, 0x6f, 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, + 0x2f, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, + 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xd5, 0x02, 0x0a, 0x1b, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x53, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x10, 0x74, 0x78, 0x6e, + 0x69, 0x64, 0x5f, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0e, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4c, 0x65, 0x61, + 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x29, 0x0a, 0x0f, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, + 0x6d, 0x6f, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x3a, + 0x01, 0x30, 0x52, 0x0d, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4d, 0x6f, 0x73, 0x74, 0x42, 0x69, 0x74, + 0x73, 0x12, 0x3e, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x36, 0x0a, 0x0a, 0x74, 0x78, 0x6e, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x78, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, + 0x74, 0x78, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x21, 0x74, 0x78, 0x6e, + 0x69, 0x64, 0x5f, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x5f, 0x6f, 0x66, + 0x5f, 0x6c, 0x6f, 0x77, 0x5f, 0x77, 0x61, 0x74, 0x65, 0x72, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x1c, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4c, 0x65, 0x61, 0x73, 0x74, + 0x42, 0x69, 0x74, 0x73, 0x4f, 0x66, 0x4c, 0x6f, 0x77, 0x57, 0x61, 0x74, 0x65, 0x72, 0x6d, 0x61, + 0x72, 0x6b, 0x22, 0xe7, 0x01, 0x0a, 0x23, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x6e, + 0x64, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x09, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x10, 0x74, 0x78, 0x6e, + 0x69, 0x64, 0x5f, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x3a, 0x01, 0x30, 0x52, 0x0e, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4c, 0x65, 0x61, + 0x73, 0x74, 0x42, 0x69, 0x74, 0x73, 0x12, 0x29, 0x0a, 0x0f, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x5f, + 0x6d, 0x6f, 0x73, 0x74, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x3a, + 0x01, 0x30, 0x52, 0x0d, 0x74, 0x78, 0x6e, 0x69, 0x64, 0x4d, 0x6f, 0x73, 0x74, 0x42, 0x69, 0x74, + 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x9a, 0x2e, 0x0a, + 0x0b, 0x42, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x32, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x70, 0x75, 0x6c, + 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x36, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, + 0x07, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x3c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x75, + 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x52, 0x09, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x3c, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x75, 0x6c, 0x73, + 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x09, 0x73, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x12, 0x39, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x65, 0x72, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x12, + 0x2d, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x04, 0x73, 0x65, 0x6e, 0x64, 0x12, 0x43, + 0x0a, 0x0c, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x52, + 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x52, 0x0b, 0x73, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x63, 0x65, + 0x69, 0x70, 0x74, 0x12, 0x3d, 0x0a, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x65, + 0x6e, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x12, 0x36, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x61, 0x63, + 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x63, + 0x6b, 0x52, 0x03, 0x61, 0x63, 0x6b, 0x12, 0x2d, 0x0a, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x46, 0x6c, 0x6f, 0x77, 0x52, + 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x42, 0x0a, 0x0b, 0x75, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x75, 0x6c, + 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x0b, 0x75, 0x6e, + 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x36, 0x0a, 0x07, 0x73, 0x75, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x75, 0x6c, + 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x12, 0x30, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x12, 0x49, 0x0a, 0x0e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x70, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x65, 0x72, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x75, + 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x52, + 0x0d, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x12, 0x49, + 0x0a, 0x0e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, + 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x43, 0x6c, 0x6f, + 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x0d, 0x63, 0x6c, 0x6f, 0x73, + 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x12, 0x4f, 0x0a, 0x10, 0x70, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x11, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, + 0x65, 0x72, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x64, 0x75, + 0x63, 0x65, 0x72, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x2d, 0x0a, 0x04, 0x70, 0x69, + 0x6e, 0x67, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, + 0x69, 0x6e, 0x67, 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x2d, 0x0a, 0x04, 0x70, 0x6f, 0x6e, + 0x67, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x6f, + 0x6e, 0x67, 0x52, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 0x65, 0x64, 0x65, + 0x6c, 0x69, 0x76, 0x65, 0x72, 0x55, 0x6e, 0x61, 0x63, 0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65, 0x64, + 0x67, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x34, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, + 0x72, 0x55, 0x6e, 0x61, 0x63, 0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x64, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x1f, 0x72, 0x65, 0x64, 0x65, 0x6c, 0x69, 0x76, + 0x65, 0x72, 0x55, 0x6e, 0x61, 0x63, 0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x64, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x5b, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x74, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x15, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x52, 0x11, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x73, 0x0a, 0x19, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, + 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, + 0x19, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x0b, 0x6c, 0x6f, + 0x6f, 0x6b, 0x75, 0x70, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x54, 0x6f, 0x70, 0x69, + 0x63, 0x52, 0x0b, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x5a, + 0x0a, 0x13, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x75, + 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x13, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x54, 0x6f, 0x70, + 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0d, 0x63, 0x6f, + 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, + 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x12, 0x60, 0x0a, 0x15, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, + 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x1a, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, + 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, + 0x15, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x72, 0x65, 0x61, 0x63, 0x68, 0x65, + 0x64, 0x45, 0x6e, 0x64, 0x4f, 0x66, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x1b, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x61, 0x63, 0x68, 0x65, 0x64, 0x45, + 0x6e, 0x64, 0x4f, 0x66, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x52, 0x11, 0x72, 0x65, 0x61, 0x63, 0x68, + 0x65, 0x64, 0x45, 0x6e, 0x64, 0x4f, 0x66, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x2d, 0x0a, 0x04, + 0x73, 0x65, 0x65, 0x6b, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x6c, + 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x53, 0x65, 0x65, 0x6b, 0x52, 0x04, 0x73, 0x65, 0x65, 0x6b, 0x12, 0x51, 0x0a, 0x10, 0x67, + 0x65, 0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x18, + 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x4c, + 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x52, 0x10, 0x67, 0x65, + 0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x69, + 0x0a, 0x18, 0x67, 0x65, 0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2d, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, + 0x18, 0x67, 0x65, 0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x16, 0x61, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x75, 0x6c, 0x73, + 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x52, 0x14, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x73, + 0x75, 0x6d, 0x65, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, + 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x4f, 0x66, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x47, + 0x65, 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x4f, 0x66, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x52, 0x14, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x4f, 0x66, + 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x75, 0x0a, 0x1c, 0x67, 0x65, 0x74, + 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x4f, 0x66, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x31, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x4f, + 0x66, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x4f, 0x66, 0x4e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x3c, 0x0a, 0x09, 0x67, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x22, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x52, 0x09, 0x67, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x54, + 0x0a, 0x11, 0x67, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x75, 0x6c, 0x73, + 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x52, 0x11, 0x67, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x43, 0x68, 0x61, 0x6c, + 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x18, 0x24, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x75, + 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x41, 0x75, 0x74, 0x68, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x52, + 0x0d, 0x61, 0x75, 0x74, 0x68, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x12, 0x45, + 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x25, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x75, 0x74, 0x68, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0c, 0x61, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x0b, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x26, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x75, 0x6c, + 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x41, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0b, 0x61, 0x63, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, + 0x4f, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x27, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x4f, 0x72, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x11, 0x67, 0x65, + 0x74, 0x4f, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, + 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4f, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x28, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4f, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, + 0x06, 0x6e, 0x65, 0x77, 0x54, 0x78, 0x6e, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x4e, 0x65, 0x77, 0x54, 0x78, 0x6e, 0x52, 0x06, 0x6e, 0x65, 0x77, 0x54, + 0x78, 0x6e, 0x12, 0x4b, 0x0a, 0x0e, 0x6e, 0x65, 0x77, 0x54, 0x78, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x33, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x75, 0x6c, + 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x4e, 0x65, 0x77, 0x54, 0x78, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, + 0x0e, 0x6e, 0x65, 0x77, 0x54, 0x78, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x54, 0x0a, 0x11, 0x61, 0x64, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x54, + 0x6f, 0x54, 0x78, 0x6e, 0x18, 0x34, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x75, 0x6c, + 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x41, 0x64, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x54, + 0x78, 0x6e, 0x52, 0x11, 0x61, 0x64, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x54, 0x6f, 0x54, 0x78, 0x6e, 0x12, 0x6c, 0x0a, 0x19, 0x61, 0x64, 0x64, 0x50, 0x61, 0x72, 0x74, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x54, 0x78, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x18, 0x35, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, + 0x64, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x54, 0x78, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x19, 0x61, 0x64, 0x64, 0x50, 0x61, 0x72, + 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x54, 0x78, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x61, 0x64, 0x64, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x54, 0x78, 0x6e, 0x18, 0x36, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x54, 0x78, 0x6e, 0x52, 0x14, 0x61, 0x64, + 0x64, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x54, + 0x78, 0x6e, 0x12, 0x75, 0x0a, 0x1c, 0x61, 0x64, 0x64, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x54, 0x78, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x18, 0x37, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, + 0x64, 0x64, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, + 0x54, 0x78, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x1c, 0x61, 0x64, 0x64, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x54, 0x78, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x65, 0x6e, 0x64, + 0x54, 0x78, 0x6e, 0x18, 0x38, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x75, 0x6c, 0x73, + 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x45, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x52, 0x06, 0x65, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x12, 0x4b, + 0x0a, 0x0e, 0x65, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0x39, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x6e, 0x64, + 0x54, 0x78, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0e, 0x65, 0x6e, 0x64, + 0x54, 0x78, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x65, + 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x3a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x6e, 0x64, + 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, + 0x65, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x6c, 0x0a, 0x19, 0x65, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x50, 0x61, 0x72, + 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x3b, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x54, 0x78, + 0x6e, 0x4f, 0x6e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x19, 0x65, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x50, 0x61, + 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x5d, 0x0a, 0x14, 0x65, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x14, 0x65, 0x6e, 0x64, 0x54, 0x78, 0x6e, + 0x4f, 0x6e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x75, + 0x0a, 0x1c, 0x65, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x3d, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x54, 0x78, + 0x6e, 0x4f, 0x6e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x1c, 0x65, 0x6e, 0x64, 0x54, 0x78, 0x6e, 0x4f, + 0x6e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x74, 0x63, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x3e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x54, 0x63, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x52, 0x16, 0x74, 0x63, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x74, 0x63, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x3f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x75, + 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x54, 0x63, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x17, 0x74, 0x63, 0x43, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x77, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, 0x69, 0x63, + 0x4c, 0x69, 0x73, 0x74, 0x18, 0x40, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x75, 0x6c, + 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x57, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x0e, 0x77, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x4c, 0x69, 0x73, 0x74, 0x12, + 0x60, 0x0a, 0x15, 0x77, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x4c, 0x69, 0x73, + 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x41, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, + 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x57, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x15, 0x77, 0x61, 0x74, 0x63, + 0x68, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x12, 0x51, 0x0a, 0x10, 0x77, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x42, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x75, + 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x57, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x52, 0x10, 0x77, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x12, 0x5a, 0x0a, 0x13, 0x77, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, + 0x69, 0x63, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x43, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x57, 0x61, 0x74, 0x63, 0x68, 0x54, 0x6f, 0x70, + 0x69, 0x63, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x13, 0x77, 0x61, 0x74, + 0x63, 0x68, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x6f, 0x73, 0x65, + 0x22, 0x86, 0x0a, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4f, 0x4e, + 0x4e, 0x45, 0x43, 0x54, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, + 0x54, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, + 0x42, 0x45, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x45, 0x52, + 0x10, 0x05, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x45, 0x4e, 0x44, 0x10, 0x06, 0x12, 0x10, 0x0a, 0x0c, + 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x52, 0x45, 0x43, 0x45, 0x49, 0x50, 0x54, 0x10, 0x07, 0x12, 0x0e, + 0x0a, 0x0a, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x08, 0x12, 0x0b, + 0x0a, 0x07, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x09, 0x12, 0x07, 0x0a, 0x03, 0x41, + 0x43, 0x4b, 0x10, 0x0a, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x4c, 0x4f, 0x57, 0x10, 0x0b, 0x12, 0x0f, + 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x10, 0x0c, 0x12, + 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x0d, 0x12, 0x09, 0x0a, 0x05, + 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x0e, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4c, 0x4f, 0x53, 0x45, + 0x5f, 0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x45, 0x52, 0x10, 0x0f, 0x12, 0x12, 0x0a, 0x0e, 0x43, + 0x4c, 0x4f, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x55, 0x4d, 0x45, 0x52, 0x10, 0x10, 0x12, + 0x14, 0x0a, 0x10, 0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x45, 0x52, 0x5f, 0x53, 0x55, 0x43, 0x43, + 0x45, 0x53, 0x53, 0x10, 0x11, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x49, 0x4e, 0x47, 0x10, 0x12, 0x12, + 0x08, 0x0a, 0x04, 0x50, 0x4f, 0x4e, 0x47, 0x10, 0x13, 0x12, 0x25, 0x0a, 0x21, 0x52, 0x45, 0x44, + 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x41, 0x43, 0x4b, 0x4e, 0x4f, 0x57, 0x4c, + 0x45, 0x44, 0x47, 0x45, 0x44, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x53, 0x10, 0x14, + 0x12, 0x18, 0x0a, 0x14, 0x50, 0x41, 0x52, 0x54, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x45, 0x44, 0x5f, + 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x10, 0x15, 0x12, 0x21, 0x0a, 0x1d, 0x50, 0x41, + 0x52, 0x54, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x45, 0x44, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, + 0x54, 0x41, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x16, 0x12, 0x0a, 0x0a, + 0x06, 0x4c, 0x4f, 0x4f, 0x4b, 0x55, 0x50, 0x10, 0x17, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x4f, + 0x4b, 0x55, 0x50, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x18, 0x12, 0x12, + 0x0a, 0x0e, 0x43, 0x4f, 0x4e, 0x53, 0x55, 0x4d, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x53, + 0x10, 0x19, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4e, 0x53, 0x55, 0x4d, 0x45, 0x52, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x53, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x1a, 0x12, + 0x18, 0x0a, 0x14, 0x52, 0x45, 0x41, 0x43, 0x48, 0x45, 0x44, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x4f, + 0x46, 0x5f, 0x54, 0x4f, 0x50, 0x49, 0x43, 0x10, 0x1b, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x45, 0x45, + 0x4b, 0x10, 0x1c, 0x12, 0x17, 0x0a, 0x13, 0x47, 0x45, 0x54, 0x5f, 0x4c, 0x41, 0x53, 0x54, 0x5f, + 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x49, 0x44, 0x10, 0x1d, 0x12, 0x20, 0x0a, 0x1c, + 0x47, 0x45, 0x54, 0x5f, 0x4c, 0x41, 0x53, 0x54, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, + 0x5f, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x1e, 0x12, 0x1a, + 0x0a, 0x16, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x55, 0x4d, 0x45, + 0x52, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x1f, 0x12, 0x1b, 0x0a, 0x17, 0x47, 0x45, + 0x54, 0x5f, 0x54, 0x4f, 0x50, 0x49, 0x43, 0x53, 0x5f, 0x4f, 0x46, 0x5f, 0x4e, 0x41, 0x4d, 0x45, + 0x53, 0x50, 0x41, 0x43, 0x45, 0x10, 0x20, 0x12, 0x24, 0x0a, 0x20, 0x47, 0x45, 0x54, 0x5f, 0x54, + 0x4f, 0x50, 0x49, 0x43, 0x53, 0x5f, 0x4f, 0x46, 0x5f, 0x4e, 0x41, 0x4d, 0x45, 0x53, 0x50, 0x41, + 0x43, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x21, 0x12, 0x0e, 0x0a, + 0x0a, 0x47, 0x45, 0x54, 0x5f, 0x53, 0x43, 0x48, 0x45, 0x4d, 0x41, 0x10, 0x22, 0x12, 0x17, 0x0a, + 0x13, 0x47, 0x45, 0x54, 0x5f, 0x53, 0x43, 0x48, 0x45, 0x4d, 0x41, 0x5f, 0x52, 0x45, 0x53, 0x50, + 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x23, 0x12, 0x12, 0x0a, 0x0e, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x43, + 0x48, 0x41, 0x4c, 0x4c, 0x45, 0x4e, 0x47, 0x45, 0x10, 0x24, 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x55, + 0x54, 0x48, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x25, 0x12, 0x10, 0x0a, + 0x0c, 0x41, 0x43, 0x4b, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x26, 0x12, + 0x18, 0x0a, 0x14, 0x47, 0x45, 0x54, 0x5f, 0x4f, 0x52, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, + 0x5f, 0x53, 0x43, 0x48, 0x45, 0x4d, 0x41, 0x10, 0x27, 0x12, 0x21, 0x0a, 0x1d, 0x47, 0x45, 0x54, + 0x5f, 0x4f, 0x52, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x5f, 0x53, 0x43, 0x48, 0x45, 0x4d, + 0x41, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x28, 0x12, 0x0b, 0x0a, 0x07, + 0x4e, 0x45, 0x57, 0x5f, 0x54, 0x58, 0x4e, 0x10, 0x32, 0x12, 0x14, 0x0a, 0x10, 0x4e, 0x45, 0x57, + 0x5f, 0x54, 0x58, 0x4e, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x33, 0x12, + 0x18, 0x0a, 0x14, 0x41, 0x44, 0x44, 0x5f, 0x50, 0x41, 0x52, 0x54, 0x49, 0x54, 0x49, 0x4f, 0x4e, + 0x5f, 0x54, 0x4f, 0x5f, 0x54, 0x58, 0x4e, 0x10, 0x34, 0x12, 0x21, 0x0a, 0x1d, 0x41, 0x44, 0x44, + 0x5f, 0x50, 0x41, 0x52, 0x54, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x4f, 0x5f, 0x54, 0x58, + 0x4e, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x35, 0x12, 0x1b, 0x0a, 0x17, + 0x41, 0x44, 0x44, 0x5f, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, + 0x5f, 0x54, 0x4f, 0x5f, 0x54, 0x58, 0x4e, 0x10, 0x36, 0x12, 0x24, 0x0a, 0x20, 0x41, 0x44, 0x44, + 0x5f, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x4f, + 0x5f, 0x54, 0x58, 0x4e, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x37, 0x12, + 0x0b, 0x0a, 0x07, 0x45, 0x4e, 0x44, 0x5f, 0x54, 0x58, 0x4e, 0x10, 0x38, 0x12, 0x14, 0x0a, 0x10, + 0x45, 0x4e, 0x44, 0x5f, 0x54, 0x58, 0x4e, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, + 0x10, 0x39, 0x12, 0x18, 0x0a, 0x14, 0x45, 0x4e, 0x44, 0x5f, 0x54, 0x58, 0x4e, 0x5f, 0x4f, 0x4e, + 0x5f, 0x50, 0x41, 0x52, 0x54, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x3a, 0x12, 0x21, 0x0a, 0x1d, + 0x45, 0x4e, 0x44, 0x5f, 0x54, 0x58, 0x4e, 0x5f, 0x4f, 0x4e, 0x5f, 0x50, 0x41, 0x52, 0x54, 0x49, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x3b, 0x12, + 0x1b, 0x0a, 0x17, 0x45, 0x4e, 0x44, 0x5f, 0x54, 0x58, 0x4e, 0x5f, 0x4f, 0x4e, 0x5f, 0x53, 0x55, + 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x3c, 0x12, 0x24, 0x0a, 0x20, + 0x45, 0x4e, 0x44, 0x5f, 0x54, 0x58, 0x4e, 0x5f, 0x4f, 0x4e, 0x5f, 0x53, 0x55, 0x42, 0x53, 0x43, + 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, + 0x10, 0x3d, 0x12, 0x1d, 0x0a, 0x19, 0x54, 0x43, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, + 0x3e, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x43, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x43, + 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, + 0x3f, 0x12, 0x14, 0x0a, 0x10, 0x57, 0x41, 0x54, 0x43, 0x48, 0x5f, 0x54, 0x4f, 0x50, 0x49, 0x43, + 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x40, 0x12, 0x1c, 0x0a, 0x18, 0x57, 0x41, 0x54, 0x43, 0x48, + 0x5f, 0x54, 0x4f, 0x50, 0x49, 0x43, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x53, 0x55, 0x43, 0x43, + 0x45, 0x53, 0x53, 0x10, 0x41, 0x12, 0x16, 0x0a, 0x12, 0x57, 0x41, 0x54, 0x43, 0x48, 0x5f, 0x54, + 0x4f, 0x50, 0x49, 0x43, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x42, 0x12, 0x1a, 0x0a, + 0x16, 0x57, 0x41, 0x54, 0x43, 0x48, 0x5f, 0x54, 0x4f, 0x50, 0x49, 0x43, 0x5f, 0x4c, 0x49, 0x53, + 0x54, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x43, 0x2a, 0x44, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, + 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x5a, 0x34, 0x10, 0x01, 0x12, + 0x08, 0x0a, 0x04, 0x5a, 0x4c, 0x49, 0x42, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x5a, 0x53, 0x54, + 0x44, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x4e, 0x41, 0x50, 0x50, 0x59, 0x10, 0x04, 0x2a, + 0x5f, 0x0a, 0x12, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x10, + 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x10, 0x01, + 0x12, 0x14, 0x0a, 0x10, 0x57, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x45, 0x78, 0x63, 0x6c, 0x75, + 0x73, 0x69, 0x76, 0x65, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x73, + 0x69, 0x76, 0x65, 0x57, 0x69, 0x74, 0x68, 0x46, 0x65, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x10, 0x03, + 0x2a, 0x82, 0x05, 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, + 0x65, 0x6e, 0x63, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x41, + 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, + 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x42, 0x75, 0x73, 0x79, 0x10, 0x05, 0x12, 0x13, + 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x6f, 0x74, 0x52, 0x65, 0x61, 0x64, + 0x79, 0x10, 0x06, 0x12, 0x25, 0x0a, 0x21, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x45, 0x78, 0x63, 0x65, 0x65, + 0x64, 0x65, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x07, 0x12, 0x29, 0x0a, 0x25, 0x50, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x51, 0x75, 0x6f, + 0x74, 0x61, 0x45, 0x78, 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x45, 0x78, 0x63, 0x65, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x10, 0x08, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, + 0x6d, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x09, 0x12, 0x1b, 0x0a, 0x17, 0x55, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x10, 0x0a, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x4e, 0x6f, + 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x10, 0x0b, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, + 0x10, 0x0c, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x4e, 0x6f, + 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x10, 0x0d, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x6f, 0x6f, 0x4d, + 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x10, 0x0e, 0x12, 0x18, 0x0a, + 0x14, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x0f, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x64, 0x75, + 0x63, 0x65, 0x72, 0x42, 0x75, 0x73, 0x79, 0x10, 0x10, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x6e, 0x76, + 0x61, 0x6c, 0x69, 0x64, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x4e, 0x61, 0x6d, 0x65, 0x10, 0x11, 0x12, + 0x16, 0x0a, 0x12, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x53, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x10, 0x12, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x73, 0x75, + 0x6d, 0x65, 0x72, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x13, + 0x12, 0x22, 0x0a, 0x1e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, + 0x6e, 0x64, 0x10, 0x14, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x54, + 0x78, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x10, 0x15, 0x12, 0x13, 0x0a, 0x0f, 0x4e, 0x6f, + 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x16, 0x12, + 0x17, 0x0a, 0x13, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x10, 0x17, 0x12, 0x17, 0x0a, 0x13, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x10, + 0x18, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x46, 0x65, 0x6e, + 0x63, 0x65, 0x64, 0x10, 0x19, 0x2a, 0x4b, 0x0a, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x12, 0x12, 0x0a, 0x0e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x75, 0x74, 0x68, 0x4d, + 0x65, 0x74, 0x68, 0x6f, 0x64, 0x59, 0x63, 0x61, 0x56, 0x31, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, + 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x74, 0x68, 0x65, 0x6e, 0x73, + 0x10, 0x02, 0x2a, 0xbb, 0x01, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x06, 0x0a, 0x02, 0x76, 0x30, 0x10, 0x00, 0x12, 0x06, + 0x0a, 0x02, 0x76, 0x31, 0x10, 0x01, 0x12, 0x06, 0x0a, 0x02, 0x76, 0x32, 0x10, 0x02, 0x12, 0x06, + 0x0a, 0x02, 0x76, 0x33, 0x10, 0x03, 0x12, 0x06, 0x0a, 0x02, 0x76, 0x34, 0x10, 0x04, 0x12, 0x06, + 0x0a, 0x02, 0x76, 0x35, 0x10, 0x05, 0x12, 0x06, 0x0a, 0x02, 0x76, 0x36, 0x10, 0x06, 0x12, 0x06, + 0x0a, 0x02, 0x76, 0x37, 0x10, 0x07, 0x12, 0x06, 0x0a, 0x02, 0x76, 0x38, 0x10, 0x08, 0x12, 0x06, + 0x0a, 0x02, 0x76, 0x39, 0x10, 0x09, 0x12, 0x07, 0x0a, 0x03, 0x76, 0x31, 0x30, 0x10, 0x0a, 0x12, + 0x07, 0x0a, 0x03, 0x76, 0x31, 0x31, 0x10, 0x0b, 0x12, 0x07, 0x0a, 0x03, 0x76, 0x31, 0x32, 0x10, + 0x0c, 0x12, 0x07, 0x0a, 0x03, 0x76, 0x31, 0x33, 0x10, 0x0d, 0x12, 0x07, 0x0a, 0x03, 0x76, 0x31, + 0x34, 0x10, 0x0e, 0x12, 0x07, 0x0a, 0x03, 0x76, 0x31, 0x35, 0x10, 0x0f, 0x12, 0x07, 0x0a, 0x03, + 0x76, 0x31, 0x36, 0x10, 0x10, 0x12, 0x07, 0x0a, 0x03, 0x76, 0x31, 0x37, 0x10, 0x11, 0x12, 0x07, + 0x0a, 0x03, 0x76, 0x31, 0x38, 0x10, 0x12, 0x12, 0x07, 0x0a, 0x03, 0x76, 0x31, 0x39, 0x10, 0x13, + 0x2a, 0x2b, 0x0a, 0x0d, 0x4b, 0x65, 0x79, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4d, 0x6f, 0x64, + 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x53, 0x50, 0x4c, 0x49, 0x54, 0x10, + 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x49, 0x43, 0x4b, 0x59, 0x10, 0x01, 0x2a, 0x22, 0x0a, + 0x09, 0x54, 0x78, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, + 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x42, 0x4f, 0x52, 0x54, 0x10, + 0x01, 0x42, 0x2f, 0x0a, 0x22, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, + 0x70, 0x75, 0x6c, 0x73, 0x61, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x03, 0x5a, 0x07, 0x2e, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, +} + +var ( + file_PulsarApi_proto_rawDescOnce sync.Once + file_PulsarApi_proto_rawDescData = file_PulsarApi_proto_rawDesc +) + +func file_PulsarApi_proto_rawDescGZIP() []byte { + file_PulsarApi_proto_rawDescOnce.Do(func() { + file_PulsarApi_proto_rawDescData = protoimpl.X.CompressGZIP(file_PulsarApi_proto_rawDescData) + }) + return file_PulsarApi_proto_rawDescData +} + +var file_PulsarApi_proto_enumTypes = make([]protoimpl.EnumInfo, 16) +var file_PulsarApi_proto_msgTypes = make([]protoimpl.MessageInfo, 71) +var file_PulsarApi_proto_goTypes = []interface{}{ + (CompressionType)(0), // 0: pulsar.proto.CompressionType + (ProducerAccessMode)(0), // 1: pulsar.proto.ProducerAccessMode + (ServerError)(0), // 2: pulsar.proto.ServerError + (AuthMethod)(0), // 3: pulsar.proto.AuthMethod + (ProtocolVersion)(0), // 4: pulsar.proto.ProtocolVersion + (KeySharedMode)(0), // 5: pulsar.proto.KeySharedMode + (TxnAction)(0), // 6: pulsar.proto.TxnAction + (Schema_Type)(0), // 7: pulsar.proto.Schema.Type + (CommandSubscribe_SubType)(0), // 8: pulsar.proto.CommandSubscribe.SubType + (CommandSubscribe_InitialPosition)(0), // 9: pulsar.proto.CommandSubscribe.InitialPosition + (CommandPartitionedTopicMetadataResponse_LookupType)(0), // 10: pulsar.proto.CommandPartitionedTopicMetadataResponse.LookupType + (CommandLookupTopicResponse_LookupType)(0), // 11: pulsar.proto.CommandLookupTopicResponse.LookupType + (CommandAck_AckType)(0), // 12: pulsar.proto.CommandAck.AckType + (CommandAck_ValidationError)(0), // 13: pulsar.proto.CommandAck.ValidationError + (CommandGetTopicsOfNamespace_Mode)(0), // 14: pulsar.proto.CommandGetTopicsOfNamespace.Mode + (BaseCommand_Type)(0), // 15: pulsar.proto.BaseCommand.Type + (*Schema)(nil), // 16: pulsar.proto.Schema + (*MessageIdData)(nil), // 17: pulsar.proto.MessageIdData + (*KeyValue)(nil), // 18: pulsar.proto.KeyValue + (*KeyLongValue)(nil), // 19: pulsar.proto.KeyLongValue + (*IntRange)(nil), // 20: pulsar.proto.IntRange + (*EncryptionKeys)(nil), // 21: pulsar.proto.EncryptionKeys + (*MessageMetadata)(nil), // 22: pulsar.proto.MessageMetadata + (*SingleMessageMetadata)(nil), // 23: pulsar.proto.SingleMessageMetadata + (*BrokerEntryMetadata)(nil), // 24: pulsar.proto.BrokerEntryMetadata + (*CommandConnect)(nil), // 25: pulsar.proto.CommandConnect + (*FeatureFlags)(nil), // 26: pulsar.proto.FeatureFlags + (*CommandConnected)(nil), // 27: pulsar.proto.CommandConnected + (*CommandAuthResponse)(nil), // 28: pulsar.proto.CommandAuthResponse + (*CommandAuthChallenge)(nil), // 29: pulsar.proto.CommandAuthChallenge + (*AuthData)(nil), // 30: pulsar.proto.AuthData + (*KeySharedMeta)(nil), // 31: pulsar.proto.KeySharedMeta + (*CommandSubscribe)(nil), // 32: pulsar.proto.CommandSubscribe + (*CommandPartitionedTopicMetadata)(nil), // 33: pulsar.proto.CommandPartitionedTopicMetadata + (*CommandPartitionedTopicMetadataResponse)(nil), // 34: pulsar.proto.CommandPartitionedTopicMetadataResponse + (*CommandLookupTopic)(nil), // 35: pulsar.proto.CommandLookupTopic + (*CommandLookupTopicResponse)(nil), // 36: pulsar.proto.CommandLookupTopicResponse + (*CommandProducer)(nil), // 37: pulsar.proto.CommandProducer + (*CommandSend)(nil), // 38: pulsar.proto.CommandSend + (*CommandSendReceipt)(nil), // 39: pulsar.proto.CommandSendReceipt + (*CommandSendError)(nil), // 40: pulsar.proto.CommandSendError + (*CommandMessage)(nil), // 41: pulsar.proto.CommandMessage + (*CommandAck)(nil), // 42: pulsar.proto.CommandAck + (*CommandAckResponse)(nil), // 43: pulsar.proto.CommandAckResponse + (*CommandActiveConsumerChange)(nil), // 44: pulsar.proto.CommandActiveConsumerChange + (*CommandFlow)(nil), // 45: pulsar.proto.CommandFlow + (*CommandUnsubscribe)(nil), // 46: pulsar.proto.CommandUnsubscribe + (*CommandSeek)(nil), // 47: pulsar.proto.CommandSeek + (*CommandReachedEndOfTopic)(nil), // 48: pulsar.proto.CommandReachedEndOfTopic + (*CommandCloseProducer)(nil), // 49: pulsar.proto.CommandCloseProducer + (*CommandCloseConsumer)(nil), // 50: pulsar.proto.CommandCloseConsumer + (*CommandRedeliverUnacknowledgedMessages)(nil), // 51: pulsar.proto.CommandRedeliverUnacknowledgedMessages + (*CommandSuccess)(nil), // 52: pulsar.proto.CommandSuccess + (*CommandProducerSuccess)(nil), // 53: pulsar.proto.CommandProducerSuccess + (*CommandError)(nil), // 54: pulsar.proto.CommandError + (*CommandPing)(nil), // 55: pulsar.proto.CommandPing + (*CommandPong)(nil), // 56: pulsar.proto.CommandPong + (*CommandConsumerStats)(nil), // 57: pulsar.proto.CommandConsumerStats + (*CommandConsumerStatsResponse)(nil), // 58: pulsar.proto.CommandConsumerStatsResponse + (*CommandGetLastMessageId)(nil), // 59: pulsar.proto.CommandGetLastMessageId + (*CommandGetLastMessageIdResponse)(nil), // 60: pulsar.proto.CommandGetLastMessageIdResponse + (*CommandGetTopicsOfNamespace)(nil), // 61: pulsar.proto.CommandGetTopicsOfNamespace + (*CommandGetTopicsOfNamespaceResponse)(nil), // 62: pulsar.proto.CommandGetTopicsOfNamespaceResponse + (*CommandWatchTopicList)(nil), // 63: pulsar.proto.CommandWatchTopicList + (*CommandWatchTopicListSuccess)(nil), // 64: pulsar.proto.CommandWatchTopicListSuccess + (*CommandWatchTopicUpdate)(nil), // 65: pulsar.proto.CommandWatchTopicUpdate + (*CommandWatchTopicListClose)(nil), // 66: pulsar.proto.CommandWatchTopicListClose + (*CommandGetSchema)(nil), // 67: pulsar.proto.CommandGetSchema + (*CommandGetSchemaResponse)(nil), // 68: pulsar.proto.CommandGetSchemaResponse + (*CommandGetOrCreateSchema)(nil), // 69: pulsar.proto.CommandGetOrCreateSchema + (*CommandGetOrCreateSchemaResponse)(nil), // 70: pulsar.proto.CommandGetOrCreateSchemaResponse + (*CommandTcClientConnectRequest)(nil), // 71: pulsar.proto.CommandTcClientConnectRequest + (*CommandTcClientConnectResponse)(nil), // 72: pulsar.proto.CommandTcClientConnectResponse + (*CommandNewTxn)(nil), // 73: pulsar.proto.CommandNewTxn + (*CommandNewTxnResponse)(nil), // 74: pulsar.proto.CommandNewTxnResponse + (*CommandAddPartitionToTxn)(nil), // 75: pulsar.proto.CommandAddPartitionToTxn + (*CommandAddPartitionToTxnResponse)(nil), // 76: pulsar.proto.CommandAddPartitionToTxnResponse + (*Subscription)(nil), // 77: pulsar.proto.Subscription + (*CommandAddSubscriptionToTxn)(nil), // 78: pulsar.proto.CommandAddSubscriptionToTxn + (*CommandAddSubscriptionToTxnResponse)(nil), // 79: pulsar.proto.CommandAddSubscriptionToTxnResponse + (*CommandEndTxn)(nil), // 80: pulsar.proto.CommandEndTxn + (*CommandEndTxnResponse)(nil), // 81: pulsar.proto.CommandEndTxnResponse + (*CommandEndTxnOnPartition)(nil), // 82: pulsar.proto.CommandEndTxnOnPartition + (*CommandEndTxnOnPartitionResponse)(nil), // 83: pulsar.proto.CommandEndTxnOnPartitionResponse + (*CommandEndTxnOnSubscription)(nil), // 84: pulsar.proto.CommandEndTxnOnSubscription + (*CommandEndTxnOnSubscriptionResponse)(nil), // 85: pulsar.proto.CommandEndTxnOnSubscriptionResponse + (*BaseCommand)(nil), // 86: pulsar.proto.BaseCommand +} +var file_PulsarApi_proto_depIdxs = []int32{ + 7, // 0: pulsar.proto.Schema.type:type_name -> pulsar.proto.Schema.Type + 18, // 1: pulsar.proto.Schema.properties:type_name -> pulsar.proto.KeyValue + 17, // 2: pulsar.proto.MessageIdData.first_chunk_message_id:type_name -> pulsar.proto.MessageIdData + 18, // 3: pulsar.proto.EncryptionKeys.metadata:type_name -> pulsar.proto.KeyValue + 18, // 4: pulsar.proto.MessageMetadata.properties:type_name -> pulsar.proto.KeyValue + 0, // 5: pulsar.proto.MessageMetadata.compression:type_name -> pulsar.proto.CompressionType + 21, // 6: pulsar.proto.MessageMetadata.encryption_keys:type_name -> pulsar.proto.EncryptionKeys + 18, // 7: pulsar.proto.SingleMessageMetadata.properties:type_name -> pulsar.proto.KeyValue + 3, // 8: pulsar.proto.CommandConnect.auth_method:type_name -> pulsar.proto.AuthMethod + 26, // 9: pulsar.proto.CommandConnect.feature_flags:type_name -> pulsar.proto.FeatureFlags + 26, // 10: pulsar.proto.CommandConnected.feature_flags:type_name -> pulsar.proto.FeatureFlags + 30, // 11: pulsar.proto.CommandAuthResponse.response:type_name -> pulsar.proto.AuthData + 30, // 12: pulsar.proto.CommandAuthChallenge.challenge:type_name -> pulsar.proto.AuthData + 5, // 13: pulsar.proto.KeySharedMeta.keySharedMode:type_name -> pulsar.proto.KeySharedMode + 20, // 14: pulsar.proto.KeySharedMeta.hashRanges:type_name -> pulsar.proto.IntRange + 8, // 15: pulsar.proto.CommandSubscribe.subType:type_name -> pulsar.proto.CommandSubscribe.SubType + 17, // 16: pulsar.proto.CommandSubscribe.start_message_id:type_name -> pulsar.proto.MessageIdData + 18, // 17: pulsar.proto.CommandSubscribe.metadata:type_name -> pulsar.proto.KeyValue + 16, // 18: pulsar.proto.CommandSubscribe.schema:type_name -> pulsar.proto.Schema + 9, // 19: pulsar.proto.CommandSubscribe.initialPosition:type_name -> pulsar.proto.CommandSubscribe.InitialPosition + 31, // 20: pulsar.proto.CommandSubscribe.keySharedMeta:type_name -> pulsar.proto.KeySharedMeta + 18, // 21: pulsar.proto.CommandSubscribe.subscription_properties:type_name -> pulsar.proto.KeyValue + 10, // 22: pulsar.proto.CommandPartitionedTopicMetadataResponse.response:type_name -> pulsar.proto.CommandPartitionedTopicMetadataResponse.LookupType + 2, // 23: pulsar.proto.CommandPartitionedTopicMetadataResponse.error:type_name -> pulsar.proto.ServerError + 11, // 24: pulsar.proto.CommandLookupTopicResponse.response:type_name -> pulsar.proto.CommandLookupTopicResponse.LookupType + 2, // 25: pulsar.proto.CommandLookupTopicResponse.error:type_name -> pulsar.proto.ServerError + 18, // 26: pulsar.proto.CommandProducer.metadata:type_name -> pulsar.proto.KeyValue + 16, // 27: pulsar.proto.CommandProducer.schema:type_name -> pulsar.proto.Schema + 1, // 28: pulsar.proto.CommandProducer.producer_access_mode:type_name -> pulsar.proto.ProducerAccessMode + 17, // 29: pulsar.proto.CommandSend.message_id:type_name -> pulsar.proto.MessageIdData + 17, // 30: pulsar.proto.CommandSendReceipt.message_id:type_name -> pulsar.proto.MessageIdData + 2, // 31: pulsar.proto.CommandSendError.error:type_name -> pulsar.proto.ServerError + 17, // 32: pulsar.proto.CommandMessage.message_id:type_name -> pulsar.proto.MessageIdData + 12, // 33: pulsar.proto.CommandAck.ack_type:type_name -> pulsar.proto.CommandAck.AckType + 17, // 34: pulsar.proto.CommandAck.message_id:type_name -> pulsar.proto.MessageIdData + 13, // 35: pulsar.proto.CommandAck.validation_error:type_name -> pulsar.proto.CommandAck.ValidationError + 19, // 36: pulsar.proto.CommandAck.properties:type_name -> pulsar.proto.KeyLongValue + 2, // 37: pulsar.proto.CommandAckResponse.error:type_name -> pulsar.proto.ServerError + 17, // 38: pulsar.proto.CommandSeek.message_id:type_name -> pulsar.proto.MessageIdData + 17, // 39: pulsar.proto.CommandRedeliverUnacknowledgedMessages.message_ids:type_name -> pulsar.proto.MessageIdData + 16, // 40: pulsar.proto.CommandSuccess.schema:type_name -> pulsar.proto.Schema + 2, // 41: pulsar.proto.CommandError.error:type_name -> pulsar.proto.ServerError + 2, // 42: pulsar.proto.CommandConsumerStatsResponse.error_code:type_name -> pulsar.proto.ServerError + 17, // 43: pulsar.proto.CommandGetLastMessageIdResponse.last_message_id:type_name -> pulsar.proto.MessageIdData + 17, // 44: pulsar.proto.CommandGetLastMessageIdResponse.consumer_mark_delete_position:type_name -> pulsar.proto.MessageIdData + 14, // 45: pulsar.proto.CommandGetTopicsOfNamespace.mode:type_name -> pulsar.proto.CommandGetTopicsOfNamespace.Mode + 2, // 46: pulsar.proto.CommandGetSchemaResponse.error_code:type_name -> pulsar.proto.ServerError + 16, // 47: pulsar.proto.CommandGetSchemaResponse.schema:type_name -> pulsar.proto.Schema + 16, // 48: pulsar.proto.CommandGetOrCreateSchema.schema:type_name -> pulsar.proto.Schema + 2, // 49: pulsar.proto.CommandGetOrCreateSchemaResponse.error_code:type_name -> pulsar.proto.ServerError + 2, // 50: pulsar.proto.CommandTcClientConnectResponse.error:type_name -> pulsar.proto.ServerError + 2, // 51: pulsar.proto.CommandNewTxnResponse.error:type_name -> pulsar.proto.ServerError + 2, // 52: pulsar.proto.CommandAddPartitionToTxnResponse.error:type_name -> pulsar.proto.ServerError + 77, // 53: pulsar.proto.CommandAddSubscriptionToTxn.subscription:type_name -> pulsar.proto.Subscription + 2, // 54: pulsar.proto.CommandAddSubscriptionToTxnResponse.error:type_name -> pulsar.proto.ServerError + 6, // 55: pulsar.proto.CommandEndTxn.txn_action:type_name -> pulsar.proto.TxnAction + 2, // 56: pulsar.proto.CommandEndTxnResponse.error:type_name -> pulsar.proto.ServerError + 6, // 57: pulsar.proto.CommandEndTxnOnPartition.txn_action:type_name -> pulsar.proto.TxnAction + 2, // 58: pulsar.proto.CommandEndTxnOnPartitionResponse.error:type_name -> pulsar.proto.ServerError + 77, // 59: pulsar.proto.CommandEndTxnOnSubscription.subscription:type_name -> pulsar.proto.Subscription + 6, // 60: pulsar.proto.CommandEndTxnOnSubscription.txn_action:type_name -> pulsar.proto.TxnAction + 2, // 61: pulsar.proto.CommandEndTxnOnSubscriptionResponse.error:type_name -> pulsar.proto.ServerError + 15, // 62: pulsar.proto.BaseCommand.type:type_name -> pulsar.proto.BaseCommand.Type + 25, // 63: pulsar.proto.BaseCommand.connect:type_name -> pulsar.proto.CommandConnect + 27, // 64: pulsar.proto.BaseCommand.connected:type_name -> pulsar.proto.CommandConnected + 32, // 65: pulsar.proto.BaseCommand.subscribe:type_name -> pulsar.proto.CommandSubscribe + 37, // 66: pulsar.proto.BaseCommand.producer:type_name -> pulsar.proto.CommandProducer + 38, // 67: pulsar.proto.BaseCommand.send:type_name -> pulsar.proto.CommandSend + 39, // 68: pulsar.proto.BaseCommand.send_receipt:type_name -> pulsar.proto.CommandSendReceipt + 40, // 69: pulsar.proto.BaseCommand.send_error:type_name -> pulsar.proto.CommandSendError + 41, // 70: pulsar.proto.BaseCommand.message:type_name -> pulsar.proto.CommandMessage + 42, // 71: pulsar.proto.BaseCommand.ack:type_name -> pulsar.proto.CommandAck + 45, // 72: pulsar.proto.BaseCommand.flow:type_name -> pulsar.proto.CommandFlow + 46, // 73: pulsar.proto.BaseCommand.unsubscribe:type_name -> pulsar.proto.CommandUnsubscribe + 52, // 74: pulsar.proto.BaseCommand.success:type_name -> pulsar.proto.CommandSuccess + 54, // 75: pulsar.proto.BaseCommand.error:type_name -> pulsar.proto.CommandError + 49, // 76: pulsar.proto.BaseCommand.close_producer:type_name -> pulsar.proto.CommandCloseProducer + 50, // 77: pulsar.proto.BaseCommand.close_consumer:type_name -> pulsar.proto.CommandCloseConsumer + 53, // 78: pulsar.proto.BaseCommand.producer_success:type_name -> pulsar.proto.CommandProducerSuccess + 55, // 79: pulsar.proto.BaseCommand.ping:type_name -> pulsar.proto.CommandPing + 56, // 80: pulsar.proto.BaseCommand.pong:type_name -> pulsar.proto.CommandPong + 51, // 81: pulsar.proto.BaseCommand.redeliverUnacknowledgedMessages:type_name -> pulsar.proto.CommandRedeliverUnacknowledgedMessages + 33, // 82: pulsar.proto.BaseCommand.partitionMetadata:type_name -> pulsar.proto.CommandPartitionedTopicMetadata + 34, // 83: pulsar.proto.BaseCommand.partitionMetadataResponse:type_name -> pulsar.proto.CommandPartitionedTopicMetadataResponse + 35, // 84: pulsar.proto.BaseCommand.lookupTopic:type_name -> pulsar.proto.CommandLookupTopic + 36, // 85: pulsar.proto.BaseCommand.lookupTopicResponse:type_name -> pulsar.proto.CommandLookupTopicResponse + 57, // 86: pulsar.proto.BaseCommand.consumerStats:type_name -> pulsar.proto.CommandConsumerStats + 58, // 87: pulsar.proto.BaseCommand.consumerStatsResponse:type_name -> pulsar.proto.CommandConsumerStatsResponse + 48, // 88: pulsar.proto.BaseCommand.reachedEndOfTopic:type_name -> pulsar.proto.CommandReachedEndOfTopic + 47, // 89: pulsar.proto.BaseCommand.seek:type_name -> pulsar.proto.CommandSeek + 59, // 90: pulsar.proto.BaseCommand.getLastMessageId:type_name -> pulsar.proto.CommandGetLastMessageId + 60, // 91: pulsar.proto.BaseCommand.getLastMessageIdResponse:type_name -> pulsar.proto.CommandGetLastMessageIdResponse + 44, // 92: pulsar.proto.BaseCommand.active_consumer_change:type_name -> pulsar.proto.CommandActiveConsumerChange + 61, // 93: pulsar.proto.BaseCommand.getTopicsOfNamespace:type_name -> pulsar.proto.CommandGetTopicsOfNamespace + 62, // 94: pulsar.proto.BaseCommand.getTopicsOfNamespaceResponse:type_name -> pulsar.proto.CommandGetTopicsOfNamespaceResponse + 67, // 95: pulsar.proto.BaseCommand.getSchema:type_name -> pulsar.proto.CommandGetSchema + 68, // 96: pulsar.proto.BaseCommand.getSchemaResponse:type_name -> pulsar.proto.CommandGetSchemaResponse + 29, // 97: pulsar.proto.BaseCommand.authChallenge:type_name -> pulsar.proto.CommandAuthChallenge + 28, // 98: pulsar.proto.BaseCommand.authResponse:type_name -> pulsar.proto.CommandAuthResponse + 43, // 99: pulsar.proto.BaseCommand.ackResponse:type_name -> pulsar.proto.CommandAckResponse + 69, // 100: pulsar.proto.BaseCommand.getOrCreateSchema:type_name -> pulsar.proto.CommandGetOrCreateSchema + 70, // 101: pulsar.proto.BaseCommand.getOrCreateSchemaResponse:type_name -> pulsar.proto.CommandGetOrCreateSchemaResponse + 73, // 102: pulsar.proto.BaseCommand.newTxn:type_name -> pulsar.proto.CommandNewTxn + 74, // 103: pulsar.proto.BaseCommand.newTxnResponse:type_name -> pulsar.proto.CommandNewTxnResponse + 75, // 104: pulsar.proto.BaseCommand.addPartitionToTxn:type_name -> pulsar.proto.CommandAddPartitionToTxn + 76, // 105: pulsar.proto.BaseCommand.addPartitionToTxnResponse:type_name -> pulsar.proto.CommandAddPartitionToTxnResponse + 78, // 106: pulsar.proto.BaseCommand.addSubscriptionToTxn:type_name -> pulsar.proto.CommandAddSubscriptionToTxn + 79, // 107: pulsar.proto.BaseCommand.addSubscriptionToTxnResponse:type_name -> pulsar.proto.CommandAddSubscriptionToTxnResponse + 80, // 108: pulsar.proto.BaseCommand.endTxn:type_name -> pulsar.proto.CommandEndTxn + 81, // 109: pulsar.proto.BaseCommand.endTxnResponse:type_name -> pulsar.proto.CommandEndTxnResponse + 82, // 110: pulsar.proto.BaseCommand.endTxnOnPartition:type_name -> pulsar.proto.CommandEndTxnOnPartition + 83, // 111: pulsar.proto.BaseCommand.endTxnOnPartitionResponse:type_name -> pulsar.proto.CommandEndTxnOnPartitionResponse + 84, // 112: pulsar.proto.BaseCommand.endTxnOnSubscription:type_name -> pulsar.proto.CommandEndTxnOnSubscription + 85, // 113: pulsar.proto.BaseCommand.endTxnOnSubscriptionResponse:type_name -> pulsar.proto.CommandEndTxnOnSubscriptionResponse + 71, // 114: pulsar.proto.BaseCommand.tcClientConnectRequest:type_name -> pulsar.proto.CommandTcClientConnectRequest + 72, // 115: pulsar.proto.BaseCommand.tcClientConnectResponse:type_name -> pulsar.proto.CommandTcClientConnectResponse + 63, // 116: pulsar.proto.BaseCommand.watchTopicList:type_name -> pulsar.proto.CommandWatchTopicList + 64, // 117: pulsar.proto.BaseCommand.watchTopicListSuccess:type_name -> pulsar.proto.CommandWatchTopicListSuccess + 65, // 118: pulsar.proto.BaseCommand.watchTopicUpdate:type_name -> pulsar.proto.CommandWatchTopicUpdate + 66, // 119: pulsar.proto.BaseCommand.watchTopicListClose:type_name -> pulsar.proto.CommandWatchTopicListClose + 120, // [120:120] is the sub-list for method output_type + 120, // [120:120] is the sub-list for method input_type + 120, // [120:120] is the sub-list for extension type_name + 120, // [120:120] is the sub-list for extension extendee + 0, // [0:120] is the sub-list for field type_name +} + +func init() { file_PulsarApi_proto_init() } +func file_PulsarApi_proto_init() { + if File_PulsarApi_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_PulsarApi_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Schema); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MessageIdData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*KeyValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*KeyLongValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IntRange); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EncryptionKeys); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MessageMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SingleMessageMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BrokerEntryMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandConnect); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FeatureFlags); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandConnected); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandAuthResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandAuthChallenge); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AuthData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*KeySharedMeta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandSubscribe); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandPartitionedTopicMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandPartitionedTopicMetadataResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandLookupTopic); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandLookupTopicResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandProducer); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandSend); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandSendReceipt); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandSendError); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandAckResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandActiveConsumerChange); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandFlow); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandUnsubscribe); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandSeek); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandReachedEndOfTopic); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandCloseProducer); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandCloseConsumer); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandRedeliverUnacknowledgedMessages); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandSuccess); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandProducerSuccess); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandError); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandPing); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandPong); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandConsumerStats); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandConsumerStatsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandGetLastMessageId); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandGetLastMessageIdResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandGetTopicsOfNamespace); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandGetTopicsOfNamespaceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandWatchTopicList); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandWatchTopicListSuccess); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandWatchTopicUpdate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandWatchTopicListClose); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandGetSchema); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandGetSchemaResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandGetOrCreateSchema); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandGetOrCreateSchemaResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandTcClientConnectRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandTcClientConnectResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandNewTxn); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandNewTxnResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandAddPartitionToTxn); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandAddPartitionToTxnResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Subscription); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandAddSubscriptionToTxn); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandAddSubscriptionToTxnResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandEndTxn); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandEndTxnResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandEndTxnOnPartition); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandEndTxnOnPartitionResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandEndTxnOnSubscription); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommandEndTxnOnSubscriptionResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_PulsarApi_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BaseCommand); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_PulsarApi_proto_rawDesc, + NumEnums: 16, + NumMessages: 71, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_PulsarApi_proto_goTypes, + DependencyIndexes: file_PulsarApi_proto_depIdxs, + EnumInfos: file_PulsarApi_proto_enumTypes, + MessageInfos: file_PulsarApi_proto_msgTypes, + }.Build() + File_PulsarApi_proto = out.File + file_PulsarApi_proto_rawDesc = nil + file_PulsarApi_proto_goTypes = nil + file_PulsarApi_proto_depIdxs = nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto/PulsarApi.proto b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto/PulsarApi.proto new file mode 100644 index 00000000..0c72361c --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto/PulsarApi.proto @@ -0,0 +1,1110 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +syntax = "proto2"; + +package pulsar.proto; +option java_package = "org.apache.pulsar.common.api.proto"; +option go_package = "./proto"; +option optimize_for = LITE_RUNTIME; + +message Schema { + enum Type { + None = 0; + String = 1; + Json = 2; + Protobuf = 3; + Avro = 4; + Bool = 5; + Int8 = 6; + Int16 = 7; + Int32 = 8; + Int64 = 9; + Float = 10; + Double = 11; + Date = 12; + Time = 13; + Timestamp = 14; + KeyValue = 15; + Instant = 16; + LocalDate = 17; + LocalTime = 18; + LocalDateTime = 19; + ProtobufNative = 20; + } + + required string name = 1; + required bytes schema_data = 3; + required Type type = 4; + repeated KeyValue properties = 5; + +} + +message MessageIdData { + required uint64 ledgerId = 1; + required uint64 entryId = 2; + optional int32 partition = 3 [default = -1]; + optional int32 batch_index = 4 [default = -1]; + repeated int64 ack_set = 5; + optional int32 batch_size = 6; + + // For the chunk message id, we need to specify the first chunk message id. + optional MessageIdData first_chunk_message_id = 7; +} + +message KeyValue { + required string key = 1; + required string value = 2; +} + +message KeyLongValue { + required string key = 1; + required uint64 value = 2; +} + +message IntRange { + required int32 start = 1; + required int32 end = 2; +} + +message EncryptionKeys { + required string key = 1; + required bytes value = 2; + repeated KeyValue metadata = 3; +} + +enum CompressionType { + NONE = 0; + LZ4 = 1; + ZLIB = 2; + ZSTD = 3; + SNAPPY = 4; +} + +enum ProducerAccessMode { + Shared = 0; // By default multiple producers can publish on a topic + Exclusive = 1; // Require exclusive access for producer. Fail immediately if there's already a producer connected. + WaitForExclusive = 2; // Producer creation is pending until it can acquire exclusive access + ExclusiveWithFencing = 3; // Require exclusive access for producer. Fence out old producer. +} + +message MessageMetadata { + required string producer_name = 1; + required uint64 sequence_id = 2; + required uint64 publish_time = 3; + repeated KeyValue properties = 4; + + // Property set on replicated message, + // includes the source cluster name + optional string replicated_from = 5; + //key to decide partition for the msg + optional string partition_key = 6; + // Override namespace's replication + repeated string replicate_to = 7; + optional CompressionType compression = 8 [default = NONE]; + optional uint32 uncompressed_size = 9 [default = 0]; + // Removed below checksum field from Metadata as + // it should be part of send-command which keeps checksum of header + payload + //optional sfixed64 checksum = 10; + // differentiate single and batch message metadata + optional int32 num_messages_in_batch = 11 [default = 1]; + + // the timestamp that this event occurs. it is typically set by applications. + // if this field is omitted, `publish_time` can be used for the purpose of `event_time`. + optional uint64 event_time = 12 [default = 0]; + // Contains encryption key name, encrypted key and metadata to describe the key + repeated EncryptionKeys encryption_keys = 13; + // Algorithm used to encrypt data key + optional string encryption_algo = 14; + // Additional parameters required by encryption + optional bytes encryption_param = 15; + optional bytes schema_version = 16; + + optional bool partition_key_b64_encoded = 17 [ default = false ]; + // Specific a key to overwrite the message key which used for ordering dispatch in Key_Shared mode. + optional bytes ordering_key = 18; + + // Mark the message to be delivered at or after the specified timestamp + optional int64 deliver_at_time = 19; + + // Identify whether a message is a "marker" message used for + // internal metadata instead of application published data. + // Markers will generally not be propagated back to clients + optional int32 marker_type = 20; + + // transaction related message info + optional uint64 txnid_least_bits = 22; + optional uint64 txnid_most_bits = 23; + + /// Add highest sequence id to support batch message with external sequence id + optional uint64 highest_sequence_id = 24 [default = 0]; + + // Indicate if the message payload value is set + optional bool null_value = 25 [default = false]; + optional string uuid = 26; + optional int32 num_chunks_from_msg = 27; + optional int32 total_chunk_msg_size = 28; + optional int32 chunk_id = 29; + + // Indicate if the message partition key is set + optional bool null_partition_key = 30 [default = false]; +} + +message SingleMessageMetadata { + repeated KeyValue properties = 1; + optional string partition_key = 2; + required int32 payload_size = 3; + optional bool compacted_out = 4 [default = false]; + + // the timestamp that this event occurs. it is typically set by applications. + // if this field is omitted, `publish_time` can be used for the purpose of `event_time`. + optional uint64 event_time = 5 [default = 0]; + optional bool partition_key_b64_encoded = 6 [ default = false ]; + // Specific a key to overwrite the message key which used for ordering dispatch in Key_Shared mode. + optional bytes ordering_key = 7; + // Allows consumer retrieve the sequence id that the producer set. + optional uint64 sequence_id = 8; + // Indicate if the message payload value is set + optional bool null_value = 9 [ default = false ]; + // Indicate if the message partition key is set + optional bool null_partition_key = 10 [ default = false]; +} + +// metadata added for entry from broker +message BrokerEntryMetadata { + optional uint64 broker_timestamp = 1; + optional uint64 index = 2; +} + +enum ServerError { + UnknownError = 0; + MetadataError = 1; // Error with ZK/metadata + PersistenceError = 2; // Error writing reading from BK + AuthenticationError = 3; // Non valid authentication + AuthorizationError = 4; // Not authorized to use resource + + ConsumerBusy = 5; // Unable to subscribe/unsubscribe because + // other consumers are connected + ServiceNotReady = 6; // Any error that requires client retry operation with a fresh lookup + ProducerBlockedQuotaExceededError = 7; // Unable to create producer because backlog quota exceeded + ProducerBlockedQuotaExceededException = 8; // Exception while creating producer because quota exceeded + ChecksumError = 9; // Error while verifying message checksum + UnsupportedVersionError = 10; // Error when an older client/version doesn't support a required feature + TopicNotFound = 11; // Topic not found + SubscriptionNotFound = 12; // Subscription not found + ConsumerNotFound = 13; // Consumer not found + TooManyRequests = 14; // Error with too many simultaneously request + TopicTerminatedError = 15; // The topic has been terminated + + ProducerBusy = 16; // Producer with same name is already connected + InvalidTopicName = 17; // The topic name is not valid + + IncompatibleSchema = 18; // Specified schema was incompatible with topic schema + ConsumerAssignError = 19; // Dispatcher assign consumer error + + TransactionCoordinatorNotFound = 20; // Transaction coordinator not found error + InvalidTxnStatus = 21; // Invalid txn status error + NotAllowedError = 22; // Not allowed error + + TransactionConflict = 23; // Ack with transaction conflict + TransactionNotFound = 24; // Transaction not found + + ProducerFenced = 25; // When a producer asks and fail to get exclusive producer access, + // or loses the eclusive status after a reconnection, the broker will + // use this error to indicate that this producer is now permanently + // fenced. Applications are now supposed to close it and create a + // new producer +} + +enum AuthMethod { + AuthMethodNone = 0; + AuthMethodYcaV1 = 1; + AuthMethodAthens = 2; +} + +// Each protocol version identify new features that are +// incrementally added to the protocol +enum ProtocolVersion { + v0 = 0; // Initial versioning + v1 = 1; // Added application keep-alive + v2 = 2; // Added RedeliverUnacknowledgedMessages Command + v3 = 3; // Added compression with LZ4 and ZLib + v4 = 4; // Added batch message support + v5 = 5; // Added disconnect client w/o closing connection + v6 = 6; // Added checksum computation for metadata + payload + v7 = 7; // Added CommandLookupTopic - Binary Lookup + v8 = 8; // Added CommandConsumerStats - Client fetches broker side consumer stats + v9 = 9; // Added end of topic notification + v10 = 10;// Added proxy to broker + v11 = 11;// C++ consumers before this version are not correctly handling the checksum field + v12 = 12;// Added get topic's last messageId from broker + // Added CommandActiveConsumerChange + // Added CommandGetTopicsOfNamespace + v13 = 13; // Schema-registry : added avro schema format for json + v14 = 14; // Add CommandAuthChallenge and CommandAuthResponse for mutual auth + // Added Key_Shared subscription + v15 = 15; // Add CommandGetOrCreateSchema and CommandGetOrCreateSchemaResponse + v16 = 16; // Add support for broker entry metadata + v17 = 17; // Added support ack receipt + v18 = 18; // Add client support for broker entry metadata + v19 = 19; // Add CommandTcClientConnectRequest and CommandTcClientConnectResponse +} + +message CommandConnect { + required string client_version = 1; + optional AuthMethod auth_method = 2; // Deprecated. Use "auth_method_name" instead. + optional string auth_method_name = 5; + optional bytes auth_data = 3; + optional int32 protocol_version = 4 [default = 0]; + + // Client can ask to be proxyied to a specific broker + // This is only honored by a Pulsar proxy + optional string proxy_to_broker_url = 6; + + // Original principal that was verified by + // a Pulsar proxy. In this case the auth info above + // will be the auth of the proxy itself + optional string original_principal = 7; + + // Original auth role and auth Method that was passed + // to the proxy. In this case the auth info above + // will be the auth of the proxy itself + optional string original_auth_data = 8; + optional string original_auth_method = 9; + + // Feature flags + optional FeatureFlags feature_flags = 10; +} + +message FeatureFlags { + optional bool supports_auth_refresh = 1 [default = false]; + optional bool supports_broker_entry_metadata = 2 [default = false]; + optional bool supports_partial_producer = 3 [default = false]; + optional bool supports_topic_watchers = 4 [default = false]; +} + +message CommandConnected { + required string server_version = 1; + optional int32 protocol_version = 2 [default = 0]; + optional int32 max_message_size = 3; + optional FeatureFlags feature_flags = 4; +} + +message CommandAuthResponse { + optional string client_version = 1; + optional AuthData response = 2; + optional int32 protocol_version = 3 [default = 0]; +} + +message CommandAuthChallenge { + optional string server_version = 1; + optional AuthData challenge = 2; + optional int32 protocol_version = 3 [default = 0]; +} + +// To support mutual authentication type, such as Sasl, reuse this command to mutual auth. +message AuthData { + optional string auth_method_name = 1; + optional bytes auth_data = 2; +} + +enum KeySharedMode { + AUTO_SPLIT = 0; + STICKY = 1; +} + +message KeySharedMeta { + required KeySharedMode keySharedMode = 1; + repeated IntRange hashRanges = 3; + optional bool allowOutOfOrderDelivery = 4 [default = false]; +} + +message CommandSubscribe { + enum SubType { + Exclusive = 0; + Shared = 1; + Failover = 2; + Key_Shared = 3; + } + required string topic = 1; + required string subscription = 2; + required SubType subType = 3; + + required uint64 consumer_id = 4; + required uint64 request_id = 5; + optional string consumer_name = 6; + optional int32 priority_level = 7; + + // Signal wether the subscription should be backed by a + // durable cursor or not + optional bool durable = 8 [default = true]; + + // If specified, the subscription will position the cursor + // markd-delete position on the particular message id and + // will send messages from that point + optional MessageIdData start_message_id = 9; + + /// Add optional metadata key=value to this consumer + repeated KeyValue metadata = 10; + + optional bool read_compacted = 11; + + optional Schema schema = 12; + enum InitialPosition { + Latest = 0; + Earliest = 1; + } + // Signal whether the subscription will initialize on latest + // or not -- earliest + optional InitialPosition initialPosition = 13 [default = Latest]; + + // Mark the subscription as "replicated". Pulsar will make sure + // to periodically sync the state of replicated subscriptions + // across different clusters (when using geo-replication). + optional bool replicate_subscription_state = 14; + + // If true, the subscribe operation will cause a topic to be + // created if it does not exist already (and if topic auto-creation + // is allowed by broker. + // If false, the subscribe operation will fail if the topic + // does not exist. + optional bool force_topic_creation = 15 [default = true]; + + // If specified, the subscription will reset cursor's position back + // to specified seconds and will send messages from that point + optional uint64 start_message_rollback_duration_sec = 16 [default = 0]; + + optional KeySharedMeta keySharedMeta = 17; + + repeated KeyValue subscription_properties = 18; + + // The consumer epoch, when exclusive and failover consumer redeliver unack message will increase the epoch + optional uint64 consumer_epoch = 19; +} + +message CommandPartitionedTopicMetadata { + required string topic = 1; + required uint64 request_id = 2; + // TODO - Remove original_principal, original_auth_data, original_auth_method + // Original principal that was verified by + // a Pulsar proxy. + optional string original_principal = 3; + + // Original auth role and auth Method that was passed + // to the proxy. + optional string original_auth_data = 4; + optional string original_auth_method = 5; +} + +message CommandPartitionedTopicMetadataResponse { + enum LookupType { + Success = 0; + Failed = 1; + } + optional uint32 partitions = 1; // Optional in case of error + required uint64 request_id = 2; + optional LookupType response = 3; + optional ServerError error = 4; + optional string message = 5; +} + +message CommandLookupTopic { + required string topic = 1; + required uint64 request_id = 2; + optional bool authoritative = 3 [default = false]; + + // TODO - Remove original_principal, original_auth_data, original_auth_method + // Original principal that was verified by + // a Pulsar proxy. + optional string original_principal = 4; + + // Original auth role and auth Method that was passed + // to the proxy. + optional string original_auth_data = 5; + optional string original_auth_method = 6; + // + optional string advertised_listener_name = 7; +} + +message CommandLookupTopicResponse { + enum LookupType { + Redirect = 0; + Connect = 1; + Failed = 2; + } + + optional string brokerServiceUrl = 1; // Optional in case of error + optional string brokerServiceUrlTls = 2; + optional LookupType response = 3; + required uint64 request_id = 4; + optional bool authoritative = 5 [default = false]; + optional ServerError error = 6; + optional string message = 7; + + // If it's true, indicates to the client that it must + // always connect through the service url after the + // lookup has been completed. + optional bool proxy_through_service_url = 8 [default = false]; +} + +/// Create a new Producer on a topic, assigning the given producer_id, +/// all messages sent with this producer_id will be persisted on the topic +message CommandProducer { + required string topic = 1; + required uint64 producer_id = 2; + required uint64 request_id = 3; + + /// If a producer name is specified, the name will be used, + /// otherwise the broker will generate a unique name + optional string producer_name = 4; + + optional bool encrypted = 5 [default = false]; + + /// Add optional metadata key=value to this producer + repeated KeyValue metadata = 6; + + optional Schema schema = 7; + + // If producer reconnect to broker, the epoch of this producer will +1 + optional uint64 epoch = 8 [default = 0]; + + // Indicate the name of the producer is generated or user provided + // Use default true here is in order to be forward compatible with the client + optional bool user_provided_producer_name = 9 [default = true]; + + // Require that this producers will be the only producer allowed on the topic + optional ProducerAccessMode producer_access_mode = 10 [default = Shared]; + + // Topic epoch is used to fence off producers that reconnects after a new + // exclusive producer has already taken over. This id is assigned by the + // broker on the CommandProducerSuccess. The first time, the client will + // leave it empty and then it will always carry the same epoch number on + // the subsequent reconnections. + optional uint64 topic_epoch = 11; + + optional bool txn_enabled = 12 [default = false]; + + // Name of the initial subscription of the topic. + // If this field is not set, the initial subscription will not be created. + // If this field is set but the broker's `allowAutoSubscriptionCreation` + // is disabled, the producer will fail to be created. + optional string initial_subscription_name = 13; +} + +message CommandSend { + required uint64 producer_id = 1; + required uint64 sequence_id = 2; + optional int32 num_messages = 3 [default = 1]; + optional uint64 txnid_least_bits = 4 [default = 0]; + optional uint64 txnid_most_bits = 5 [default = 0]; + + /// Add highest sequence id to support batch message with external sequence id + optional uint64 highest_sequence_id = 6 [default = 0]; + optional bool is_chunk =7 [default = false]; + + // Specify if the message being published is a Pulsar marker or not + optional bool marker = 8 [default = false]; + + // Message id of this message, currently is used in replicator for shadow topic. + optional MessageIdData message_id = 9; +} + +message CommandSendReceipt { + required uint64 producer_id = 1; + required uint64 sequence_id = 2; + optional MessageIdData message_id = 3; + optional uint64 highest_sequence_id = 4 [default = 0]; +} + +message CommandSendError { + required uint64 producer_id = 1; + required uint64 sequence_id = 2; + required ServerError error = 3; + required string message = 4; +} + +message CommandMessage { + required uint64 consumer_id = 1; + required MessageIdData message_id = 2; + optional uint32 redelivery_count = 3 [default = 0]; + repeated int64 ack_set = 4; + optional uint64 consumer_epoch = 5; +} + +message CommandAck { + enum AckType { + Individual = 0; + Cumulative = 1; + } + + required uint64 consumer_id = 1; + required AckType ack_type = 2; + + // In case of individual acks, the client can pass a list of message ids + repeated MessageIdData message_id = 3; + + // Acks can contain a flag to indicate the consumer + // received an invalid message that got discarded + // before being passed on to the application. + enum ValidationError { + UncompressedSizeCorruption = 0; + DecompressionError = 1; + ChecksumMismatch = 2; + BatchDeSerializeError = 3; + DecryptionError = 4; + } + + optional ValidationError validation_error = 4; + repeated KeyLongValue properties = 5; + + optional uint64 txnid_least_bits = 6 [default = 0]; + optional uint64 txnid_most_bits = 7 [default = 0]; + optional uint64 request_id = 8; +} + +message CommandAckResponse { + required uint64 consumer_id = 1; + optional uint64 txnid_least_bits = 2 [default = 0]; + optional uint64 txnid_most_bits = 3 [default = 0]; + optional ServerError error = 4; + optional string message = 5; + optional uint64 request_id = 6; +} + +// changes on active consumer +message CommandActiveConsumerChange { + required uint64 consumer_id = 1; + optional bool is_active = 2 [default = false]; +} + +message CommandFlow { + required uint64 consumer_id = 1; + + // Max number of messages to prefetch, in addition + // of any number previously specified + required uint32 messagePermits = 2; +} + +message CommandUnsubscribe { + required uint64 consumer_id = 1; + required uint64 request_id = 2; +} + +// Reset an existing consumer to a particular message id +message CommandSeek { + required uint64 consumer_id = 1; + required uint64 request_id = 2; + + optional MessageIdData message_id = 3; + optional uint64 message_publish_time = 4; +} + +// Message sent by broker to client when a topic +// has been forcefully terminated and there are no more +// messages left to consume +message CommandReachedEndOfTopic { + required uint64 consumer_id = 1; +} + +message CommandCloseProducer { + required uint64 producer_id = 1; + required uint64 request_id = 2; +} + +message CommandCloseConsumer { + required uint64 consumer_id = 1; + required uint64 request_id = 2; +} + +message CommandRedeliverUnacknowledgedMessages { + required uint64 consumer_id = 1; + repeated MessageIdData message_ids = 2; + optional uint64 consumer_epoch = 3; +} + +message CommandSuccess { + required uint64 request_id = 1; + optional Schema schema = 2; +} + +/// Response from CommandProducer +message CommandProducerSuccess { + required uint64 request_id = 1; + required string producer_name = 2; + + // The last sequence id that was stored by this producer in the previous session + // This will only be meaningful if deduplication has been enabled. + optional int64 last_sequence_id = 3 [default = -1]; + optional bytes schema_version = 4; + + // The topic epoch assigned by the broker. This field will only be set if we + // were requiring exclusive access when creating the producer. + optional uint64 topic_epoch = 5; + + // If producer is not "ready", the client will avoid to timeout the request + // for creating the producer. Instead it will wait indefinitely until it gets + // a subsequent `CommandProducerSuccess` with `producer_ready==true`. + optional bool producer_ready = 6 [default = true]; +} + +message CommandError { + required uint64 request_id = 1; + required ServerError error = 2; + required string message = 3; +} + +// Commands to probe the state of connection. +// When either client or broker doesn't receive commands for certain +// amount of time, they will send a Ping probe. +message CommandPing { +} +message CommandPong { +} + +message CommandConsumerStats { + required uint64 request_id = 1; + // required string topic_name = 2; + // required string subscription_name = 3; + required uint64 consumer_id = 4; +} + +message CommandConsumerStatsResponse { + required uint64 request_id = 1; + optional ServerError error_code = 2; + optional string error_message = 3; + + /// Total rate of messages delivered to the consumer. msg/s + optional double msgRateOut = 4; + + /// Total throughput delivered to the consumer. bytes/s + optional double msgThroughputOut = 5; + + /// Total rate of messages redelivered by this consumer. msg/s + optional double msgRateRedeliver = 6; + + /// Name of the consumer + optional string consumerName = 7; + + /// Number of available message permits for the consumer + optional uint64 availablePermits = 8; + + /// Number of unacknowledged messages for the consumer + optional uint64 unackedMessages = 9; + + /// Flag to verify if consumer is blocked due to reaching threshold of unacked messages + optional bool blockedConsumerOnUnackedMsgs = 10; + + /// Address of this consumer + optional string address = 11; + + /// Timestamp of connection + optional string connectedSince = 12; + + /// Whether this subscription is Exclusive or Shared or Failover + optional string type = 13; + + /// Total rate of messages expired on this subscription. msg/s + optional double msgRateExpired = 14; + + /// Number of messages in the subscription backlog + optional uint64 msgBacklog = 15; + + /// Total rate of messages ack. msg/s + optional double messageAckRate = 16; +} + +message CommandGetLastMessageId { + required uint64 consumer_id = 1; + required uint64 request_id = 2; +} + +message CommandGetLastMessageIdResponse { + required MessageIdData last_message_id = 1; + required uint64 request_id = 2; + optional MessageIdData consumer_mark_delete_position = 3; +} + +message CommandGetTopicsOfNamespace { + enum Mode { + PERSISTENT = 0; + NON_PERSISTENT = 1; + ALL = 2; + } + required uint64 request_id = 1; + required string namespace = 2; + optional Mode mode = 3 [default = PERSISTENT]; + optional string topics_pattern = 4; + optional string topics_hash = 5; +} + +message CommandGetTopicsOfNamespaceResponse { + required uint64 request_id = 1; + repeated string topics = 2; + // true iff the topic list was filtered by the pattern supplied by the client + optional bool filtered = 3 [default = false]; + // hash computed from the names of matching topics + optional string topics_hash = 4; + // if false, topics is empty and the list of matching topics has not changed + optional bool changed = 5 [default = true]; +} + +message CommandWatchTopicList { + required uint64 request_id = 1; + required uint64 watcher_id = 2; + required string namespace = 3; + required string topics_pattern = 4; + // Only present when the client reconnects: + optional string topics_hash = 5; +} + +message CommandWatchTopicListSuccess { + required uint64 request_id = 1; + required uint64 watcher_id = 2; + repeated string topic = 3; + required string topics_hash = 4; +} + +message CommandWatchTopicUpdate { + required uint64 watcher_id = 1; + repeated string new_topics = 2; + repeated string deleted_topics = 3; + required string topics_hash = 4; +} + +message CommandWatchTopicListClose { + required uint64 request_id = 1; + required uint64 watcher_id = 2; +} + +message CommandGetSchema { + required uint64 request_id = 1; + required string topic = 2; + + optional bytes schema_version = 3; +} + +message CommandGetSchemaResponse { + required uint64 request_id = 1; + optional ServerError error_code = 2; + optional string error_message = 3; + + optional Schema schema = 4; + optional bytes schema_version = 5; +} + +message CommandGetOrCreateSchema { + required uint64 request_id = 1; + required string topic = 2; + required Schema schema = 3; +} + +message CommandGetOrCreateSchemaResponse { + required uint64 request_id = 1; + optional ServerError error_code = 2; + optional string error_message = 3; + + optional bytes schema_version = 4; +} + +/// --- transaction related --- + +enum TxnAction { + COMMIT = 0; + ABORT = 1; +} + +message CommandTcClientConnectRequest { + required uint64 request_id = 1; + required uint64 tc_id = 2 [default = 0]; +} + +message CommandTcClientConnectResponse { + required uint64 request_id = 1; + optional ServerError error = 2; + optional string message = 3; +} + +message CommandNewTxn { + required uint64 request_id = 1; + optional uint64 txn_ttl_seconds = 2 [default = 0]; + optional uint64 tc_id = 3 [default = 0]; +} + +message CommandNewTxnResponse { + required uint64 request_id = 1; + optional uint64 txnid_least_bits = 2 [default = 0]; + optional uint64 txnid_most_bits = 3 [default = 0]; + optional ServerError error = 4; + optional string message = 5; +} + +message CommandAddPartitionToTxn { + required uint64 request_id = 1; + optional uint64 txnid_least_bits = 2 [default = 0]; + optional uint64 txnid_most_bits = 3 [default = 0]; + repeated string partitions = 4; +} + +message CommandAddPartitionToTxnResponse { + required uint64 request_id = 1; + optional uint64 txnid_least_bits = 2 [default = 0]; + optional uint64 txnid_most_bits = 3 [default = 0]; + optional ServerError error = 4; + optional string message = 5; +} + +message Subscription { + required string topic = 1; + required string subscription = 2; +} +message CommandAddSubscriptionToTxn { + required uint64 request_id = 1; + optional uint64 txnid_least_bits = 2 [default = 0]; + optional uint64 txnid_most_bits = 3 [default = 0]; + repeated Subscription subscription = 4; +} + +message CommandAddSubscriptionToTxnResponse { + required uint64 request_id = 1; + optional uint64 txnid_least_bits = 2 [default = 0]; + optional uint64 txnid_most_bits = 3 [default = 0]; + optional ServerError error = 4; + optional string message = 5; +} + +message CommandEndTxn { + required uint64 request_id = 1; + optional uint64 txnid_least_bits = 2 [default = 0]; + optional uint64 txnid_most_bits = 3 [default = 0]; + optional TxnAction txn_action = 4; +} + +message CommandEndTxnResponse { + required uint64 request_id = 1; + optional uint64 txnid_least_bits = 2 [default = 0]; + optional uint64 txnid_most_bits = 3 [default = 0]; + optional ServerError error = 4; + optional string message = 5; +} + +message CommandEndTxnOnPartition { + required uint64 request_id = 1; + optional uint64 txnid_least_bits = 2 [default = 0]; + optional uint64 txnid_most_bits = 3 [default = 0]; + optional string topic = 4; + optional TxnAction txn_action = 5; + optional uint64 txnid_least_bits_of_low_watermark = 6; +} + +message CommandEndTxnOnPartitionResponse { + required uint64 request_id = 1; + optional uint64 txnid_least_bits = 2 [default = 0]; + optional uint64 txnid_most_bits = 3 [default = 0]; + optional ServerError error = 4; + optional string message = 5; +} + +message CommandEndTxnOnSubscription { + required uint64 request_id = 1; + optional uint64 txnid_least_bits = 2 [default = 0]; + optional uint64 txnid_most_bits = 3 [default = 0]; + optional Subscription subscription= 4; + optional TxnAction txn_action = 5; + optional uint64 txnid_least_bits_of_low_watermark = 6; +} + +message CommandEndTxnOnSubscriptionResponse { + required uint64 request_id = 1; + optional uint64 txnid_least_bits = 2 [default = 0]; + optional uint64 txnid_most_bits = 3 [default = 0]; + optional ServerError error = 4; + optional string message = 5; +} + +message BaseCommand { + enum Type { + CONNECT = 2; + CONNECTED = 3; + SUBSCRIBE = 4; + + PRODUCER = 5; + + SEND = 6; + SEND_RECEIPT= 7; + SEND_ERROR = 8; + + MESSAGE = 9; + ACK = 10; + FLOW = 11; + + UNSUBSCRIBE = 12; + + SUCCESS = 13; + ERROR = 14; + + CLOSE_PRODUCER = 15; + CLOSE_CONSUMER = 16; + + PRODUCER_SUCCESS = 17; + + PING = 18; + PONG = 19; + + REDELIVER_UNACKNOWLEDGED_MESSAGES = 20; + + PARTITIONED_METADATA = 21; + PARTITIONED_METADATA_RESPONSE = 22; + + LOOKUP = 23; + LOOKUP_RESPONSE = 24; + + CONSUMER_STATS = 25; + CONSUMER_STATS_RESPONSE = 26; + + REACHED_END_OF_TOPIC = 27; + + SEEK = 28; + + GET_LAST_MESSAGE_ID = 29; + GET_LAST_MESSAGE_ID_RESPONSE = 30; + + ACTIVE_CONSUMER_CHANGE = 31; + + + GET_TOPICS_OF_NAMESPACE = 32; + GET_TOPICS_OF_NAMESPACE_RESPONSE = 33; + + GET_SCHEMA = 34; + GET_SCHEMA_RESPONSE = 35; + + AUTH_CHALLENGE = 36; + AUTH_RESPONSE = 37; + + ACK_RESPONSE = 38; + + GET_OR_CREATE_SCHEMA = 39; + GET_OR_CREATE_SCHEMA_RESPONSE = 40; + + // transaction related + NEW_TXN = 50; + NEW_TXN_RESPONSE = 51; + + ADD_PARTITION_TO_TXN = 52; + ADD_PARTITION_TO_TXN_RESPONSE = 53; + + ADD_SUBSCRIPTION_TO_TXN = 54; + ADD_SUBSCRIPTION_TO_TXN_RESPONSE = 55; + + END_TXN = 56; + END_TXN_RESPONSE = 57; + + END_TXN_ON_PARTITION = 58; + END_TXN_ON_PARTITION_RESPONSE = 59; + + END_TXN_ON_SUBSCRIPTION = 60; + END_TXN_ON_SUBSCRIPTION_RESPONSE = 61; + TC_CLIENT_CONNECT_REQUEST = 62; + TC_CLIENT_CONNECT_RESPONSE = 63; + + WATCH_TOPIC_LIST = 64; + WATCH_TOPIC_LIST_SUCCESS = 65; + WATCH_TOPIC_UPDATE = 66; + WATCH_TOPIC_LIST_CLOSE = 67; + + } + + + required Type type = 1; + + optional CommandConnect connect = 2; + optional CommandConnected connected = 3; + + optional CommandSubscribe subscribe = 4; + optional CommandProducer producer = 5; + optional CommandSend send = 6; + optional CommandSendReceipt send_receipt = 7; + optional CommandSendError send_error = 8; + optional CommandMessage message = 9; + optional CommandAck ack = 10; + optional CommandFlow flow = 11; + optional CommandUnsubscribe unsubscribe = 12; + + optional CommandSuccess success = 13; + optional CommandError error = 14; + + optional CommandCloseProducer close_producer = 15; + optional CommandCloseConsumer close_consumer = 16; + + optional CommandProducerSuccess producer_success = 17; + optional CommandPing ping = 18; + optional CommandPong pong = 19; + optional CommandRedeliverUnacknowledgedMessages redeliverUnacknowledgedMessages = 20; + + optional CommandPartitionedTopicMetadata partitionMetadata = 21; + optional CommandPartitionedTopicMetadataResponse partitionMetadataResponse = 22; + + optional CommandLookupTopic lookupTopic = 23; + optional CommandLookupTopicResponse lookupTopicResponse = 24; + + optional CommandConsumerStats consumerStats = 25; + optional CommandConsumerStatsResponse consumerStatsResponse = 26; + + optional CommandReachedEndOfTopic reachedEndOfTopic = 27; + + optional CommandSeek seek = 28; + + optional CommandGetLastMessageId getLastMessageId = 29; + optional CommandGetLastMessageIdResponse getLastMessageIdResponse = 30; + + optional CommandActiveConsumerChange active_consumer_change = 31; + + optional CommandGetTopicsOfNamespace getTopicsOfNamespace = 32; + optional CommandGetTopicsOfNamespaceResponse getTopicsOfNamespaceResponse = 33; + + optional CommandGetSchema getSchema = 34; + optional CommandGetSchemaResponse getSchemaResponse = 35; + + optional CommandAuthChallenge authChallenge = 36; + optional CommandAuthResponse authResponse = 37; + + optional CommandAckResponse ackResponse = 38; + + optional CommandGetOrCreateSchema getOrCreateSchema = 39; + optional CommandGetOrCreateSchemaResponse getOrCreateSchemaResponse = 40; + + // transaction related + optional CommandNewTxn newTxn = 50; + optional CommandNewTxnResponse newTxnResponse = 51; + optional CommandAddPartitionToTxn addPartitionToTxn= 52; + optional CommandAddPartitionToTxnResponse addPartitionToTxnResponse = 53; + optional CommandAddSubscriptionToTxn addSubscriptionToTxn = 54; + optional CommandAddSubscriptionToTxnResponse addSubscriptionToTxnResponse = 55; + optional CommandEndTxn endTxn = 56; + optional CommandEndTxnResponse endTxnResponse = 57; + optional CommandEndTxnOnPartition endTxnOnPartition = 58; + optional CommandEndTxnOnPartitionResponse endTxnOnPartitionResponse = 59; + optional CommandEndTxnOnSubscription endTxnOnSubscription = 60; + optional CommandEndTxnOnSubscriptionResponse endTxnOnSubscriptionResponse = 61; + optional CommandTcClientConnectRequest tcClientConnectRequest = 62; + optional CommandTcClientConnectResponse tcClientConnectResponse = 63; + + optional CommandWatchTopicList watchTopicList = 64; + optional CommandWatchTopicListSuccess watchTopicListSuccess = 65; + optional CommandWatchTopicUpdate watchTopicUpdate = 66; + optional CommandWatchTopicListClose watchTopicListClose = 67; +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto/README.md b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto/README.md new file mode 100644 index 00000000..0ca933f4 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto/README.md @@ -0,0 +1,11 @@ +protoc-gen-go: + +```shell +go install google.golang.org/protobuf/cmd/protoc-gen-go@latest +``` + +Generate code: + +```shell +protoc --go_out=. --go_opt=paths=source_relative PulsarApi.proto +``` \ No newline at end of file diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/rpc_client.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/rpc_client.go new file mode 100644 index 00000000..2213083d --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/rpc_client.go @@ -0,0 +1,190 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "errors" + "net/url" + "sync/atomic" + "time" + + "github.com/apache/pulsar-client-go/pulsar/log" + + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "google.golang.org/protobuf/proto" +) + +var ( + // ErrRequestTimeOut happens when request not finished in given requestTimeout. + ErrRequestTimeOut = errors.New("request timed out") +) + +type result struct { + *RPCResult + error +} + +type RPCResult struct { + Response *pb.BaseCommand + Cnx Connection +} + +type RPCClient interface { + // Create a new unique request id + NewRequestID() uint64 + + NewProducerID() uint64 + + NewConsumerID() uint64 + + // Send a request and block until the result is available + RequestToAnyBroker(requestID uint64, cmdType pb.BaseCommand_Type, message proto.Message) (*RPCResult, error) + + Request(logicalAddr *url.URL, physicalAddr *url.URL, requestID uint64, + cmdType pb.BaseCommand_Type, message proto.Message) (*RPCResult, error) + + RequestOnCnxNoWait(cnx Connection, cmdType pb.BaseCommand_Type, message proto.Message) error + + RequestOnCnx(cnx Connection, requestID uint64, cmdType pb.BaseCommand_Type, message proto.Message) (*RPCResult, error) +} + +type rpcClient struct { + serviceNameResolver ServiceNameResolver + pool ConnectionPool + requestTimeout time.Duration + requestIDGenerator uint64 + producerIDGenerator uint64 + consumerIDGenerator uint64 + log log.Logger + metrics *Metrics +} + +func NewRPCClient(serviceURL *url.URL, serviceNameResolver ServiceNameResolver, pool ConnectionPool, + requestTimeout time.Duration, logger log.Logger, metrics *Metrics) RPCClient { + return &rpcClient{ + serviceNameResolver: serviceNameResolver, + pool: pool, + requestTimeout: requestTimeout, + log: logger.SubLogger(log.Fields{"serviceURL": serviceURL}), + metrics: metrics, + } +} + +func (c *rpcClient) RequestToAnyBroker(requestID uint64, cmdType pb.BaseCommand_Type, + message proto.Message) (*RPCResult, error) { + var err error + var host *url.URL + var rpcResult *RPCResult + startTime := time.Now() + backoff := DefaultBackoff{100 * time.Millisecond} + // we can retry these requests because this kind of request is + // not specific to any particular broker + for time.Since(startTime) < c.requestTimeout { + host, err = c.serviceNameResolver.ResolveHost() + if err != nil { + c.log.WithError(err).Errorf("rpc client failed to resolve host") + return nil, err + } + rpcResult, err = c.Request(host, host, requestID, cmdType, message) + // success we got a response + if err == nil { + break + } + + retryTime := backoff.Next() + c.log.Debugf("Retrying request in {%v} with timeout in {%v}", retryTime, c.requestTimeout) + time.Sleep(retryTime) + } + + return rpcResult, err +} + +func (c *rpcClient) Request(logicalAddr *url.URL, physicalAddr *url.URL, requestID uint64, + cmdType pb.BaseCommand_Type, message proto.Message) (*RPCResult, error) { + c.metrics.RPCRequestCount.Inc() + cnx, err := c.pool.GetConnection(logicalAddr, physicalAddr) + if err != nil { + return nil, err + } + + ch := make(chan result, 1) + + cnx.SendRequest(requestID, baseCommand(cmdType, message), func(response *pb.BaseCommand, err error) { + ch <- result{&RPCResult{ + Cnx: cnx, + Response: response, + }, err} + }) + + timeoutCh := time.After(c.requestTimeout) + for { + select { + case res := <-ch: + // Ignoring producer not ready response. + // Continue to wait for the producer to create successfully + if res.error == nil && *res.RPCResult.Response.Type == pb.BaseCommand_PRODUCER_SUCCESS { + if !res.RPCResult.Response.ProducerSuccess.GetProducerReady() { + timeoutCh = nil + break + } + } + return res.RPCResult, res.error + case <-timeoutCh: + return nil, ErrRequestTimeOut + } + } +} + +func (c *rpcClient) RequestOnCnx(cnx Connection, requestID uint64, cmdType pb.BaseCommand_Type, + message proto.Message) (*RPCResult, error) { + c.metrics.RPCRequestCount.Inc() + + ch := make(chan result, 1) + + cnx.SendRequest(requestID, baseCommand(cmdType, message), func(response *pb.BaseCommand, err error) { + ch <- result{&RPCResult{ + Cnx: cnx, + Response: response, + }, err} + close(ch) + }) + + select { + case res := <-ch: + return res.RPCResult, res.error + case <-time.After(c.requestTimeout): + return nil, ErrRequestTimeOut + } +} + +func (c *rpcClient) RequestOnCnxNoWait(cnx Connection, cmdType pb.BaseCommand_Type, message proto.Message) error { + c.metrics.RPCRequestCount.Inc() + return cnx.SendRequestNoWait(baseCommand(cmdType, message)) +} + +func (c *rpcClient) NewRequestID() uint64 { + return atomic.AddUint64(&c.requestIDGenerator, 1) +} + +func (c *rpcClient) NewProducerID() uint64 { + return atomic.AddUint64(&c.producerIDGenerator, 1) +} + +func (c *rpcClient) NewConsumerID() uint64 { + return atomic.AddUint64(&c.consumerIDGenerator, 1) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/semaphore.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/semaphore.go new file mode 100644 index 00000000..6a67cc35 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/semaphore.go @@ -0,0 +1,105 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "context" + "sync/atomic" + + log "github.com/sirupsen/logrus" +) + +type Semaphore interface { + // Acquire a permit, if one is available and returns immediately, + // reducing the number of available permits by one. + Acquire(ctx context.Context) bool + + // Try to acquire a permit. The method will return immediately + // with a `true` if it was possible to acquire a permit and + // `false` otherwise. + TryAcquire() bool + + // Release a permit, returning it to the semaphore. + // Release a permit, increasing the number of available permits by + // one. If any threads are trying to acquire a permit, then one is + // selected and given the permit that was just released. That thread + // is (re)enabled for thread scheduling purposes. + // There is no requirement that a thread that releases a permit must + // have acquired that permit by calling Acquire(). + // Correct usage of a semaphore is established by programming convention + // in the application. + Release() +} + +type semaphore struct { + maxPermits int32 + permits int32 + ch chan bool +} + +func NewSemaphore(maxPermits int32) Semaphore { + if maxPermits <= 0 { + log.Fatal("Max permits for semaphore needs to be > 0") + } + + return &semaphore{ + maxPermits: maxPermits, + permits: 0, + ch: make(chan bool), + } +} + +func (s *semaphore) Acquire(ctx context.Context) bool { + permits := atomic.AddInt32(&s.permits, 1) + if permits <= s.maxPermits { + return true + } + + // Block on the channel until a new permit is available + // or the context expires + select { + case <-s.ch: + return true + case <-ctx.Done(): + atomic.AddInt32(&s.permits, -1) + return false + } +} + +func (s *semaphore) TryAcquire() bool { + for { + currentPermits := atomic.LoadInt32(&s.permits) + if currentPermits >= s.maxPermits { + // All the permits are already exhausted + return false + } + + if atomic.CompareAndSwapInt32(&s.permits, currentPermits, currentPermits+1) { + // Successfully incremented counter + return true + } + } +} + +func (s *semaphore) Release() { + permits := atomic.AddInt32(&s.permits, -1) + if permits >= s.maxPermits { + // Unblock the next in line to acquire the semaphore + s.ch <- true + } +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/service_name_resolver.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/service_name_resolver.go new file mode 100644 index 00000000..419f8be9 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/service_name_resolver.go @@ -0,0 +1,128 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "errors" + "fmt" + "math/rand" + "net/url" + "sync" + "time" + + log "github.com/sirupsen/logrus" +) + +type ServiceNameResolver interface { + ResolveHost() (*url.URL, error) + ResolveHostURI() (*PulsarServiceURI, error) + UpdateServiceURL(url *url.URL) error + GetServiceURI() *PulsarServiceURI + GetServiceURL() *url.URL + GetAddressList() []*url.URL +} + +type pulsarServiceNameResolver struct { + ServiceURI *PulsarServiceURI + ServiceURL *url.URL + CurrentIndex int32 + AddressList []*url.URL + + mutex sync.Mutex +} + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func NewPulsarServiceNameResolver(url *url.URL) ServiceNameResolver { + r := &pulsarServiceNameResolver{} + err := r.UpdateServiceURL(url) + if err != nil { + log.Errorf("create pulsar service name resolver failed : %v", err) + } + return r +} + +func (r *pulsarServiceNameResolver) ResolveHost() (*url.URL, error) { + r.mutex.Lock() + defer r.mutex.Unlock() + + if r.AddressList == nil { + return nil, errors.New("no service url is provided yet") + } + if len(r.AddressList) == 0 { + return nil, fmt.Errorf("no hosts found for service url : %v", r.ServiceURL) + } + if len(r.AddressList) == 1 { + return r.AddressList[0], nil + } + idx := (r.CurrentIndex + 1) % int32(len(r.AddressList)) + r.CurrentIndex = idx + return r.AddressList[idx], nil +} + +func (r *pulsarServiceNameResolver) ResolveHostURI() (*PulsarServiceURI, error) { + host, err := r.ResolveHost() + if err != nil { + return nil, err + } + hostURL := host.Scheme + "://" + host.Hostname() + ":" + host.Port() + return NewPulsarServiceURIFromURIString(hostURL) +} + +func (r *pulsarServiceNameResolver) UpdateServiceURL(u *url.URL) error { + uri, err := NewPulsarServiceURIFromURL(u) + if err != nil { + log.Errorf("invalid service-url instance %s provided %v", u, err) + return err + } + + hosts := uri.ServiceHosts + addresses := []*url.URL{} + for _, host := range hosts { + hostURL := uri.URL.Scheme + "://" + host + u, err := url.Parse(hostURL) + if err != nil { + log.Errorf("invalid host-url %s provided %v", hostURL, err) + return err + } + addresses = append(addresses, u) + } + + r.mutex.Lock() + defer r.mutex.Unlock() + + r.AddressList = addresses + r.ServiceURL = u + r.ServiceURI = uri + r.CurrentIndex = int32(rand.Intn(len(addresses))) + return nil +} + +func (r *pulsarServiceNameResolver) GetServiceURI() *PulsarServiceURI { + return r.ServiceURI +} + +func (r *pulsarServiceNameResolver) GetServiceURL() *url.URL { + return r.ServiceURL +} + +func (r *pulsarServiceNameResolver) GetAddressList() []*url.URL { + return r.AddressList +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/service_uri.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/service_uri.go new file mode 100644 index 00000000..7b753398 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/service_uri.go @@ -0,0 +1,211 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "errors" + "fmt" + "net" + "net/url" + "strings" + + log "github.com/sirupsen/logrus" +) + +const ( + BinaryService = "pulsar" + HTTPService = "http" + HTTPSService = "https" + SSLService = "ssl" + BinaryPort = 6650 + BinaryTLSPort = 6651 + HTTPPort = 80 + HTTPSPort = 443 +) + +type PulsarServiceURI struct { + ServiceName string + ServiceInfos []string + ServiceHosts []string + servicePath string + URL *url.URL +} + +func NewPulsarServiceURIFromURIString(uri string) (*PulsarServiceURI, error) { + u, err := fromString(uri) + if err != nil { + log.Error(err) + return nil, err + } + return u, nil +} + +func NewPulsarServiceURIFromURL(url *url.URL) (*PulsarServiceURI, error) { + u, err := fromURL(url) + if err != nil { + log.Error(err) + return nil, err + } + return u, nil +} + +func fromString(uriStr string) (*PulsarServiceURI, error) { + if uriStr == "" || len(uriStr) == 0 { + return nil, errors.New("service uriStr string is null") + } + if strings.Contains(uriStr, "[") && strings.Contains(uriStr, "]") { + // deal with ipv6 address + hosts := strings.FieldsFunc(uriStr, splitURI) + if len(hosts) > 1 { + // deal with ipv6 address + firstHost := hosts[0] + lastHost := hosts[len(hosts)-1] + hasPath := strings.Contains(lastHost, "/") + path := "" + if hasPath { + idx := strings.Index(lastHost, "/") + path = lastHost[idx:] + } + firstHost += path + url, err := url.Parse(firstHost) + if err != nil { + return nil, err + } + serviceURI, err := fromURL(url) + if err != nil { + return nil, err + } + var mHosts []string + var multiHosts []string + mHosts = append(mHosts, serviceURI.ServiceHosts[0]) + mHosts = append(mHosts, hosts[1:]...) + + for _, v := range mHosts { + h, err := validateHostName(serviceURI.ServiceName, serviceURI.ServiceInfos, v) + if err == nil { + multiHosts = append(multiHosts, h) + } else { + return nil, err + } + } + + return &PulsarServiceURI{ + serviceURI.ServiceName, + serviceURI.ServiceInfos, + multiHosts, + serviceURI.servicePath, + serviceURI.URL, + }, nil + } + } + + url, err := url.Parse(uriStr) + if err != nil { + return nil, err + } + + return fromURL(url) +} + +func fromURL(url *url.URL) (*PulsarServiceURI, error) { + if url == nil { + return nil, errors.New("service url instance is null") + } + + if url.Host == "" || len(url.Host) == 0 { + return nil, errors.New("service host is null") + } + + var serviceName string + var serviceInfos []string + scheme := url.Scheme + if scheme != "" { + scheme = strings.ToLower(scheme) + schemeParts := strings.Split(scheme, "+") + serviceName = schemeParts[0] + serviceInfos = schemeParts[1:] + } + + var serviceHosts []string + hosts := strings.FieldsFunc(url.Host, splitURI) + for _, v := range hosts { + h, err := validateHostName(serviceName, serviceInfos, v) + if err == nil { + serviceHosts = append(serviceHosts, h) + } else { + return nil, err + } + } + + return &PulsarServiceURI{ + serviceName, + serviceInfos, + serviceHosts, + url.Path, + url, + }, nil +} + +func splitURI(r rune) bool { + return r == ',' || r == ';' +} + +func validateHostName(serviceName string, serviceInfos []string, hostname string) (string, error) { + uri, err := url.Parse("dummyscheme://" + hostname) + if err != nil { + return "", err + } + host := uri.Hostname() + if strings.Contains(hostname, "[") && strings.Contains(hostname, "]") { + host = fmt.Sprintf("[%s]", host) + } + if host == "" || uri.Scheme == "" { + return "", errors.New("Invalid hostname : " + hostname) + } + + port := uri.Port() + if uri.Port() == "" { + p := getServicePort(serviceName, serviceInfos) + if p == -1 { + return "", fmt.Errorf("invalid port : %d", p) + } + port = fmt.Sprint(p) + } + result := host + ":" + port + _, _, err = net.SplitHostPort(result) + if err != nil { + return "", err + } + return result, nil +} + +func getServicePort(serviceName string, serviceInfos []string) int { + switch strings.ToLower(serviceName) { + case BinaryService: + if len(serviceInfos) == 0 { + return BinaryPort + } else if len(serviceInfos) == 1 && strings.ToLower(serviceInfos[0]) == SSLService { + return BinaryTLSPort + } + case HTTPService: + return HTTPPort + case HTTPSService: + return HTTPSPort + } + return -1 +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/topic_name.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/topic_name.go new file mode 100644 index 00000000..481e41f5 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/topic_name.go @@ -0,0 +1,140 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "errors" + "fmt" + "net/url" + "strconv" + "strings" +) + +// TopicName abstract a struct contained in a Topic +type TopicName struct { + Domain string + Tenant string + Namespace string + Topic string + Name string + Partition int +} + +const ( + publicTenant = "public" + defaultNamespace = "default" + partitionedTopicSuffix = "-partition-" +) + +// ParseTopicName parse the given topic name and return TopicName. +func ParseTopicName(topic string) (*TopicName, error) { + // The topic name can be in two different forms, one is fully qualified topic name, + // the other one is short topic name + if !strings.Contains(topic, "://") { + // The short topic name can be: + // - + // - // + // - /// + parts := strings.Split(topic, "/") + if len(parts) == 3 || len(parts) == 4 { + topic = "persistent://" + topic + } else if len(parts) == 1 { + topic = "persistent://" + publicTenant + "/" + defaultNamespace + "/" + parts[0] + } else { + return nil, errors.New( + "Invalid short topic name '" + topic + + "', it should be in the format of // or ") + } + } + + tn := &TopicName{} + + // The fully qualified topic name can be in two different forms: + // new: persistent://tenant/namespace/topic + // legacy: persistent://tenant/cluster/namespace/topic + parts := strings.SplitN(topic, "://", 2) + domain := parts[0] + if domain != "persistent" && domain != "non-persistent" { + return nil, errors.New("Invalid topic domain: " + domain) + } + tn.Domain = domain + + rest := parts[1] + var err error + + // The rest of the name can be in different forms: + // new: tenant/namespace/ + // legacy: tenant/cluster/namespace/ + // Examples of localName: + // 1. some/name/xyz// + // 2. /xyz-123/feeder-2 + parts = strings.SplitN(rest, "/", 4) + tn.Tenant = parts[0] + if len(parts) == 3 { + // New topic name without cluster name + tn.Namespace = parts[0] + "/" + parts[1] + tn.Topic = parts[2] + } else if len(parts) == 4 { + // Legacy topic name that includes cluster name + tn.Namespace = fmt.Sprintf("%s/%s/%s", parts[0], parts[1], parts[2]) + tn.Topic = parts[3] + } else { + return nil, errors.New("Invalid topic name: " + topic) + } + + tn.Name = topic + tn.Partition, err = getPartitionIndex(topic) + if err != nil { + return nil, err + } + + return tn, nil +} + +func TopicNameWithoutPartitionPart(tn *TopicName) string { + if tn == nil { + return "" + } + if tn.Partition < 0 { + return tn.Name + } + idx := strings.LastIndex(tn.Name, partitionedTopicSuffix) + if idx > 0 { + return tn.Name[:idx] + } + return tn.Name +} + +func getPartitionIndex(topic string) (int, error) { + if strings.Contains(topic, partitionedTopicSuffix) { + idx := strings.LastIndex(topic, "-") + 1 + return strconv.Atoi(topic[idx:]) + } + return -1, nil +} + +func IsV2TopicName(tn *TopicName) bool { + parts := strings.Split(tn.Namespace, "/") + // Legacy topic name that includes cluster name + // tn.Namespace = fmt.Sprintf("%s/%s/%s", parts[0], parts[1], parts[2]) + return len(parts) != 3 +} + +func GetTopicRestPath(tn *TopicName) string { + return fmt.Sprintf("%s/%s/%s", tn.Domain, tn.Namespace, url.QueryEscape(tn.Topic)) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/utils.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/utils.go new file mode 100644 index 00000000..9378d9dc --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/utils.go @@ -0,0 +1,87 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "strconv" + "strings" + "sync/atomic" + "time" + + "google.golang.org/protobuf/proto" + + "github.com/pkg/errors" +) + +// TimestampMillis return a time unix nano. +func TimestampMillis(t time.Time) uint64 { + // calling UnixNano on the zero Time is undefined + if t.IsZero() { + return 0 + } + return uint64(t.UnixNano()) / uint64(time.Millisecond) +} + +// GetAndAdd perform atomic read and update +func GetAndAdd(n *uint64, diff uint64) uint64 { + for { + v := *n + if atomic.CompareAndSwapUint64(n, v, v+diff) { + return v + } + } +} + +func ParseRelativeTimeInSeconds(relativeTime string) (time.Duration, error) { + if relativeTime == "" { + return -1, errors.New("time can not be empty") + } + + unitTime := relativeTime[len(relativeTime)-1:] + t := relativeTime[:len(relativeTime)-1] + timeValue, err := strconv.ParseInt(t, 10, 64) + if err != nil { + return -1, errors.Errorf("invalid time '%s'", t) + } + + switch strings.ToLower(unitTime) { + case "s": + return time.Duration(timeValue) * time.Second, nil + case "m": + return time.Duration(timeValue) * time.Minute, nil + case "h": + return time.Duration(timeValue) * time.Hour, nil + case "d": + return time.Duration(timeValue) * time.Hour * 24, nil + case "w": + return time.Duration(timeValue) * time.Hour * 24 * 7, nil + case "y": + return time.Duration(timeValue) * time.Hour * 24 * 7 * 365, nil + default: + return -1, errors.Errorf("invalid time unit '%s'", unitTime) + } +} + +func MarshalToSizedBuffer(m proto.Message, out []byte) error { + b, err := proto.Marshal(m) + if err != nil { + return err + } + copy(out, b[:len(out)]) + return nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/internal/version.go b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/version.go new file mode 100644 index 00000000..089f0dd1 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/internal/version.go @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package internal + +import ( + "runtime/debug" + + "golang.org/x/mod/semver" +) + +const ( + pulsarClientGoModulePath = "github.com/apache/pulsar-client-go" +) + +var ( + Version string + ClientVersionString string +) + +// init Initializes the module version information by reading +// the built in golang build info. If the application was not built +// using go modules then the version string will not be available. +func init() { + if buildInfo, ok := debug.ReadBuildInfo(); ok { + for _, dep := range buildInfo.Deps { + if dep.Path == pulsarClientGoModulePath { + Version = semver.Canonical(dep.Version) + ClientVersionString = "Pulsar Go " + Version + return + } + } + } + Version = "unknown" + ClientVersionString = "Pulsar Go version unknown" +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/key_shared_policy.go b/vendor/github.com/apache/pulsar-client-go/pulsar/key_shared_policy.go new file mode 100644 index 00000000..30c6dc4d --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/key_shared_policy.go @@ -0,0 +1,107 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "fmt" + + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" +) + +type KeySharedPolicyMode int + +const ( + // KeySharedPolicyModeAutoSplit Auto split hash range key shared policy. + KeySharedPolicyModeAutoSplit KeySharedPolicyMode = iota + // KeySharedPolicyModeSticky is Sticky attach topic with fixed hash range. + KeySharedPolicyModeSticky +) + +// KeySharedPolicy for KeyShared subscription +type KeySharedPolicy struct { + //KeySharedPolicyMode + Mode KeySharedPolicyMode + //HashRanges value pair list + HashRanges []int + // If enabled, it will relax the ordering requirement, allowing the broker to send out-of-order messages in case of + // failures. This will make it faster for new consumers to join without being stalled by an existing slow consumer. + AllowOutOfOrderDelivery bool +} + +// NewKeySharedPolicySticky construct KeySharedPolicy in Sticky mode with +// hashRanges formed in value pair list: [x1, x2, y1, y2, z1, z2], and must not overlap with each others +func NewKeySharedPolicySticky(hashRanges []int) (*KeySharedPolicy, error) { + err := validateHashRanges(hashRanges) + if err != nil { + return nil, err + } + return &KeySharedPolicy{ + Mode: KeySharedPolicyModeSticky, + HashRanges: hashRanges, + }, nil +} + +func toProtoKeySharedMeta(ksp *KeySharedPolicy) *pb.KeySharedMeta { + if ksp == nil { + return nil + } + + mode := pb.KeySharedMode(ksp.Mode) + meta := &pb.KeySharedMeta{ + KeySharedMode: &mode, + AllowOutOfOrderDelivery: &ksp.AllowOutOfOrderDelivery, + } + + if ksp.Mode == KeySharedPolicyModeSticky { + for i := 0; i < len(ksp.HashRanges); i += 2 { + start, end := int32(ksp.HashRanges[i]), int32(ksp.HashRanges[i+1]) + meta.HashRanges = append(meta.HashRanges, &pb.IntRange{Start: &start, End: &end}) + } + } + + return meta +} + +func validateHashRanges(hashRanges []int) error { + sz := len(hashRanges) + if sz == 0 || sz%2 != 0 { + return fmt.Errorf("ranges must not be empty or not in value pairs") + } + var x1, x2, y1, y2 int + //check that the ranges are well-formed + for i := 0; i < sz; i += 2 { + x1, x2 = hashRanges[i], hashRanges[i+1] + if x1 >= x2 || x1 < 0 || x2 > 65535 { + return fmt.Errorf("ranges must be in [0, 65535], but provided range is, %d - %d", x1, x2) + } + } + //loop again for checking range overlap + for i := 0; i < sz; i += 2 { + x1, x2 = hashRanges[i], hashRanges[i+1] + for j := 0; j < sz; j += 2 { + if j == i { + continue + } + y1, y2 = hashRanges[j], hashRanges[j+1] + if x1 <= y2 && y1 <= x2 { + return fmt.Errorf("ranges with overlap between, %d - %d, and %d - %d", x1, x2, y1, y2) + } + } + } + return nil +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/log/log.go b/vendor/github.com/apache/pulsar-client-go/pulsar/log/log.go new file mode 100644 index 00000000..7ed52317 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/log/log.go @@ -0,0 +1,52 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package log + +// DefaultNopLogger returns a nop logger. +func DefaultNopLogger() Logger { + return nopLogger{} +} + +type nopLogger struct{} + +func (l nopLogger) SubLogger(fields Fields) Logger { return l } +func (l nopLogger) WithFields(fields Fields) Entry { return nopEntry{} } +func (l nopLogger) WithField(name string, value interface{}) Entry { return nopEntry{} } +func (l nopLogger) WithError(err error) Entry { return nopEntry{} } +func (l nopLogger) Debug(args ...interface{}) {} +func (l nopLogger) Info(args ...interface{}) {} +func (l nopLogger) Warn(args ...interface{}) {} +func (l nopLogger) Error(args ...interface{}) {} +func (l nopLogger) Debugf(format string, args ...interface{}) {} +func (l nopLogger) Infof(format string, args ...interface{}) {} +func (l nopLogger) Warnf(format string, args ...interface{}) {} +func (l nopLogger) Errorf(format string, args ...interface{}) {} + +type nopEntry struct{} + +func (e nopEntry) WithFields(fields Fields) Entry { return nopEntry{} } +func (e nopEntry) WithField(name string, value interface{}) Entry { return nopEntry{} } + +func (e nopEntry) Debug(args ...interface{}) {} +func (e nopEntry) Info(args ...interface{}) {} +func (e nopEntry) Warn(args ...interface{}) {} +func (e nopEntry) Error(args ...interface{}) {} +func (e nopEntry) Debugf(format string, args ...interface{}) {} +func (e nopEntry) Infof(format string, args ...interface{}) {} +func (e nopEntry) Warnf(format string, args ...interface{}) {} +func (e nopEntry) Errorf(format string, args ...interface{}) {} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/log/logger.go b/vendor/github.com/apache/pulsar-client-go/pulsar/log/logger.go new file mode 100644 index 00000000..693416c6 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/log/logger.go @@ -0,0 +1,67 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +// Package log defines the logger interfaces used by pulsar client. +// Users can leverage these interfaces to provide a customized logger +// implementation. +// +// The Logger and Entry interfaces defined here are inspired +// by sirupsen/logrus, both logrus and zap logging libraries +// are good resources to learn how to implement a effective +// logging library. +// +// Besides the interfaces, this log library also provides an +// implementation based on logrus, and a No-op one as well. +package log + +// Fields type, used to pass to `WithFields`. +type Fields map[string]interface{} + +// Logger describes the interface that must be implemeted by all loggers. +type Logger interface { + SubLogger(fields Fields) Logger + + WithFields(fields Fields) Entry + WithField(name string, value interface{}) Entry + WithError(err error) Entry + + Debug(args ...interface{}) + Info(args ...interface{}) + Warn(args ...interface{}) + Error(args ...interface{}) + + Debugf(format string, args ...interface{}) + Infof(format string, args ...interface{}) + Warnf(format string, args ...interface{}) + Errorf(format string, args ...interface{}) +} + +// Entry describes the interface for the logger entry. +type Entry interface { + WithFields(fields Fields) Entry + WithField(name string, value interface{}) Entry + + Debug(args ...interface{}) + Info(args ...interface{}) + Warn(args ...interface{}) + Error(args ...interface{}) + + Debugf(format string, args ...interface{}) + Infof(format string, args ...interface{}) + Warnf(format string, args ...interface{}) + Errorf(format string, args ...interface{}) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/log/wrapper_logrus.go b/vendor/github.com/apache/pulsar-client-go/pulsar/log/wrapper_logrus.go new file mode 100644 index 00000000..b8f94d0d --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/log/wrapper_logrus.go @@ -0,0 +1,140 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package log + +import ( + "github.com/sirupsen/logrus" +) + +// logrusWrapper implements Logger interface +// based on underlying logrus.FieldLogger +type logrusWrapper struct { + l logrus.FieldLogger +} + +// NewLoggerWithLogrus creates a new logger which wraps +// the given logrus.Logger +func NewLoggerWithLogrus(logger *logrus.Logger) Logger { + return &logrusWrapper{ + l: logger, + } +} + +func (l *logrusWrapper) SubLogger(fs Fields) Logger { + return &logrusWrapper{ + l: l.l.WithFields(logrus.Fields(fs)), + } +} + +func (l *logrusWrapper) WithFields(fs Fields) Entry { + return logrusEntry{ + e: l.l.WithFields(logrus.Fields(fs)), + } +} + +func (l *logrusWrapper) WithField(name string, value interface{}) Entry { + return logrusEntry{ + e: l.l.WithField(name, value), + } +} + +func (l *logrusWrapper) WithError(err error) Entry { + return logrusEntry{ + e: l.l.WithError(err), + } +} + +func (l *logrusWrapper) Debug(args ...interface{}) { + l.l.Debug(args...) +} + +func (l *logrusWrapper) Info(args ...interface{}) { + l.l.Info(args...) +} + +func (l *logrusWrapper) Warn(args ...interface{}) { + l.l.Warn(args...) +} + +func (l *logrusWrapper) Error(args ...interface{}) { + l.l.Error(args...) +} + +func (l *logrusWrapper) Debugf(format string, args ...interface{}) { + l.l.Debugf(format, args...) +} + +func (l *logrusWrapper) Infof(format string, args ...interface{}) { + l.l.Infof(format, args...) +} + +func (l *logrusWrapper) Warnf(format string, args ...interface{}) { + l.l.Warnf(format, args...) +} + +func (l *logrusWrapper) Errorf(format string, args ...interface{}) { + l.l.Errorf(format, args...) +} + +type logrusEntry struct { + e logrus.FieldLogger +} + +func (l logrusEntry) WithFields(fs Fields) Entry { + return logrusEntry{ + e: l.e.WithFields(logrus.Fields(fs)), + } +} + +func (l logrusEntry) WithField(name string, value interface{}) Entry { + return logrusEntry{ + e: l.e.WithField(name, value), + } +} + +func (l logrusEntry) Debug(args ...interface{}) { + l.e.Debug(args...) +} + +func (l logrusEntry) Info(args ...interface{}) { + l.e.Info(args...) +} + +func (l logrusEntry) Warn(args ...interface{}) { + l.e.Warn(args...) +} + +func (l logrusEntry) Error(args ...interface{}) { + l.e.Error(args...) +} + +func (l logrusEntry) Debugf(format string, args ...interface{}) { + l.e.Debugf(format, args...) +} + +func (l logrusEntry) Infof(format string, args ...interface{}) { + l.e.Infof(format, args...) +} + +func (l logrusEntry) Warnf(format string, args ...interface{}) { + l.e.Warnf(format, args...) +} + +func (l logrusEntry) Errorf(format string, args ...interface{}) { + l.e.Errorf(format, args...) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/message.go b/vendor/github.com/apache/pulsar-client-go/pulsar/message.go new file mode 100644 index 00000000..98190e91 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/message.go @@ -0,0 +1,214 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "time" +) + +// ProducerMessage abstraction used in Pulsar producer +type ProducerMessage struct { + // Payload for the message + Payload []byte + + // Value and payload is mutually exclusive, `Value interface{}` for schema message. + Value interface{} + + // Key sets the key of the message for routing policy + Key string + + // OrderingKey sets the ordering key of the message + OrderingKey string + + // Properties attach application defined properties on the message + Properties map[string]string + + // EventTime set the event time for a given message + // By default, messages don't have an event time associated, while the publish + // time will be be always present. + // Set the event time to a non-zero timestamp to explicitly declare the time + // that the event "happened", as opposed to when the message is being published. + EventTime time.Time + + // ReplicationClusters override the replication clusters for this message. + ReplicationClusters []string + + // DisableReplication disables the replication for this message + DisableReplication bool + + // SequenceID sets the sequence id to assign to the current message + SequenceID *int64 + + // DeliverAfter requests to deliver the message only after the specified relative delay. + // Note: messages are only delivered with delay when a consumer is consuming + // through a `SubscriptionType=Shared` subscription. With other subscription + // types, the messages will still be delivered immediately. + DeliverAfter time.Duration + + // DeliverAt delivers the message only at or after the specified absolute timestamp. + // Note: messages are only delivered with delay when a consumer is consuming + // through a `SubscriptionType=Shared` subscription. With other subscription + // types, the messages will still be delivered immediately. + DeliverAt time.Time + + //Schema assign to the current message + //Note: messages may have a different schema from producer schema, use it instead of producer schema when assigned + Schema Schema +} + +// Message abstraction used in Pulsar +type Message interface { + // Topic returns the topic from which this message originated from. + Topic() string + + // ProducerName returns the name of the producer that has published the message. + ProducerName() string + + // Properties are application defined key/value pairs that will be attached to the message. + // Returns the properties attached to the message. + Properties() map[string]string + + // Payload returns the payload of the message + Payload() []byte + + // ID returns the unique message ID associated with this message. + // The message id can be used to univocally refer to a message without having the keep the entire payload in memory. + ID() MessageID + + // PublishTime returns the publish time of this message. The publish time is the timestamp that a client + // publish the message. + PublishTime() time.Time + + // EventTime returns the event time associated with this message. It is typically set by the applications via + // `ProducerMessage.EventTime`. + // If EventTime is 0, it means there isn't any event time associated with this message. + EventTime() time.Time + + // Key returns the key of the message, if any + Key() string + + // OrderingKey returns the ordering key of the message, if any + OrderingKey() string + + // RedeliveryCount returns message redelivery count, redelivery count maintain in pulsar broker. + // When client nack acknowledge messages, + // broker will dispatch message again with message redelivery count in CommandMessage defined. + // + // Message redelivery increases monotonically in a broker, when topic switch ownership to a another broker + // redelivery count will be recalculated. + RedeliveryCount() uint32 + + // IsReplicated determines whether the message is replicated from another cluster. + IsReplicated() bool + + // GetReplicatedFrom returns the name of the cluster, from which the message is replicated. + GetReplicatedFrom() string + + // GetSchemaValue returns the de-serialized value of the message, according to the configuration. + GetSchemaValue(v interface{}) error + + //SchemaVersion get the schema version of the message, if any + SchemaVersion() []byte + + // GetEncryptionContext returns the ecryption context of the message. + // It will be used by the application to parse the undecrypted message. + GetEncryptionContext() *EncryptionContext + + // Index returns index from broker entry metadata, + // or empty if the feature is not enabled in the broker. + Index() *uint64 + + // BrokerPublishTime returns broker publish time from broker entry metadata, + // or empty if the feature is not enabled in the broker. + BrokerPublishTime() *time.Time +} + +// MessageID identifier for a particular message +type MessageID interface { + // Serialize the message id into a sequence of bytes that can be stored somewhere else + Serialize() []byte + + // LedgerID returns the message ledgerID + LedgerID() int64 + + // EntryID returns the message entryID + EntryID() int64 + + // BatchIdx returns the message batchIdx + BatchIdx() int32 + + // PartitionIdx returns the message partitionIdx + PartitionIdx() int32 + + // BatchSize returns 0 or the batch size, which must be greater than BatchIdx() + BatchSize() int32 + + // String returns message id in string format + String() string +} + +// DeserializeMessageID reconstruct a MessageID object from its serialized representation +func DeserializeMessageID(data []byte) (MessageID, error) { + return deserializeMessageID(data) +} + +// NewMessageID Custom Create MessageID +func NewMessageID(ledgerID int64, entryID int64, batchIdx int32, partitionIdx int32) MessageID { + return newMessageID(ledgerID, entryID, batchIdx, partitionIdx, 0) +} + +// EarliestMessageID returns a messageID that points to the earliest message available in a topic +func EarliestMessageID() MessageID { + return earliestMessageID +} + +// LatestMessageID returns a messageID that points to the latest message +func LatestMessageID() MessageID { + return latestMessageID +} + +func messageIDCompare(lhs MessageID, rhs MessageID) int { + if lhs.LedgerID() < rhs.LedgerID() { + return -1 + } else if lhs.LedgerID() > rhs.LedgerID() { + return 1 + } + if lhs.EntryID() < rhs.EntryID() { + return -1 + } else if lhs.EntryID() > rhs.EntryID() { + return 1 + } + // When performing batch index ACK on a batched message whose batch size is N, + // the ACK order should be: + // (ledger, entry, 0) -> (ledger, entry, 1) -> ... -> (ledger, entry, N-1) -> (ledger, entry) + // So we have to treat any MessageID with the batch index precedes the MessageID without the batch index + // if they are in the same entry. + if lhs.BatchIdx() < 0 && rhs.BatchIdx() < 0 { + return 0 + } else if lhs.BatchIdx() >= 0 && rhs.BatchIdx() < 0 { + return -1 + } else if lhs.BatchIdx() < 0 && rhs.BatchIdx() >= 0 { + return 1 + } + if lhs.BatchIdx() < rhs.BatchIdx() { + return -1 + } else if lhs.BatchIdx() > rhs.BatchIdx() { + return 1 + } + return 0 +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/negative_acks_tracker.go b/vendor/github.com/apache/pulsar-client-go/pulsar/negative_acks_tracker.go new file mode 100644 index 00000000..58f56767 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/negative_acks_tracker.go @@ -0,0 +1,155 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "sync" + "time" + + log "github.com/apache/pulsar-client-go/pulsar/log" +) + +type redeliveryConsumer interface { + Redeliver(msgIds []messageID) +} + +type negativeAcksTracker struct { + sync.Mutex + + doneCh chan interface{} + doneOnce sync.Once + negativeAcks map[messageID]time.Time + rc redeliveryConsumer + nackBackoff NackBackoffPolicy + tick *time.Ticker + delay time.Duration + log log.Logger +} + +func newNegativeAcksTracker(rc redeliveryConsumer, delay time.Duration, + nackBackoffPolicy NackBackoffPolicy, logger log.Logger) *negativeAcksTracker { + + t := &negativeAcksTracker{ + doneCh: make(chan interface{}), + negativeAcks: make(map[messageID]time.Time), + rc: rc, + nackBackoff: nackBackoffPolicy, + log: logger, + } + + if nackBackoffPolicy != nil { + firstDelayForNackBackoff := nackBackoffPolicy.Next(1) + t.delay = firstDelayForNackBackoff + } else { + t.delay = delay + } + + t.tick = time.NewTicker(t.delay / 3) + + go t.track() + return t +} + +func (t *negativeAcksTracker) Add(msgID *messageID) { + // Always clear up the batch index since we want to track the nack + // for the entire batch + batchMsgID := messageID{ + ledgerID: msgID.ledgerID, + entryID: msgID.entryID, + batchIdx: 0, + } + + t.Lock() + defer t.Unlock() + + _, present := t.negativeAcks[batchMsgID] + if present { + // The batch is already being tracked + return + } + + targetTime := time.Now().Add(t.delay) + t.negativeAcks[batchMsgID] = targetTime +} + +func (t *negativeAcksTracker) AddMessage(msg Message) { + nackBackoffDelay := t.nackBackoff.Next(msg.RedeliveryCount()) + + msgID := msg.ID() + + // Always clear up the batch index since we want to track the nack + // for the entire batch + batchMsgID := messageID{ + ledgerID: msgID.LedgerID(), + entryID: msgID.EntryID(), + batchIdx: 0, + } + + t.Lock() + defer t.Unlock() + + _, present := t.negativeAcks[batchMsgID] + if present { + // The batch is already being tracked + return + } + + targetTime := time.Now().Add(nackBackoffDelay) + t.negativeAcks[batchMsgID] = targetTime +} + +func (t *negativeAcksTracker) track() { + for { + select { + case <-t.doneCh: + t.log.Debug("Closing nack tracker") + return + + case <-t.tick.C: + { + now := time.Now() + msgIds := make([]messageID, 0) + + t.Lock() + + for msgID, targetTime := range t.negativeAcks { + t.log.Debugf("MsgId: %v -- targetTime: %v -- now: %v", msgID, targetTime, now) + if targetTime.Before(now) { + t.log.Debugf("Adding MsgId: %v", msgID) + msgIds = append(msgIds, msgID) + delete(t.negativeAcks, msgID) + } + } + + t.Unlock() + + if len(msgIds) > 0 { + t.rc.Redeliver(msgIds) + } + } + } + } +} + +func (t *negativeAcksTracker) Close() { + // allow Close() to be invoked multiple times by consumer_partition to avoid panic + t.doneOnce.Do(func() { + t.tick.Stop() + t.doneCh <- nil + }) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/negative_backoff_policy.go b/vendor/github.com/apache/pulsar-client-go/pulsar/negative_backoff_policy.go new file mode 100644 index 00000000..5cd35bcf --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/negative_backoff_policy.go @@ -0,0 +1,49 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "math" + "time" +) + +// NackBackoffPolicy is a interface for custom message negativeAcked policy, users can specify a NackBackoffPolicy +// for a consumer. +// +// > Notice: the consumer crashes will trigger the redelivery of the unacked message, this case will not respect the +// > NackBackoffPolicy, which means the message might get redelivered earlier than the delay time +// > from the backoff. +type NackBackoffPolicy interface { + // Next param redeliveryCount indicates the number of times the message was redelivered. + // We can get the redeliveryCount from the CommandMessage. + Next(redeliveryCount uint32) time.Duration +} + +// defaultNackBackoffPolicy is default impl for NackBackoffPolicy. +type defaultNackBackoffPolicy struct{} + +func (nbp *defaultNackBackoffPolicy) Next(redeliveryCount uint32) time.Duration { + minNackTime := 1 * time.Second // 1sec + maxNackTime := 10 * time.Minute // 10min + + if redeliveryCount < 0 { + return minNackTime + } + + return time.Duration(math.Min(math.Abs(float64(minNackTime<https://en.wikipedia.org/wiki/MurmurHash + // + // Default is `JavaStringHash`. + HashingScheme + + // CompressionType specifies the compression type for the producer. + // By default, message payloads are not compressed. Supported compression types are: + // - LZ4 + // - ZLIB + // - ZSTD + // + // Note: ZSTD is supported since Pulsar 2.3. Consumers will need to be at least at that + // release in order to be able to receive messages compressed with ZSTD. + CompressionType + + // CompressionLevel defines the desired compression level. Options: + // - Default + // - Faster + // - Better + CompressionLevel + + // MessageRouter represents a custom message routing policy by passing an implementation of MessageRouter + // The router is a function that given a particular message and the topic metadata, returns the + // partition index where the message should be routed to + MessageRouter func(*ProducerMessage, TopicMetadata) int + + // DisableBatching controls whether automatic batching of messages is enabled for the producer. By default batching + // is enabled. + // When batching is enabled, multiple calls to Producer.sendAsync can result in a single batch to be sent to the + // broker, leading to better throughput, especially when publishing small messages. If compression is enabled, + // messages will be compressed at the batch level, leading to a much better compression ratio for similar headers or + // contents. + // When enabled default batch delay is set to 1 ms and default batch size is 1000 messages + // Setting `DisableBatching: true` will make the producer to send messages individually + DisableBatching bool + + // BatchingMaxPublishDelay specifies the time period within which the messages sent will be batched (default: 10ms) + // if batch messages are enabled. If set to a non zero value, messages will be queued until this time + // interval or until + BatchingMaxPublishDelay time.Duration + + // BatchingMaxMessages specifies the maximum number of messages permitted in a batch. (default: 1000) + // If set to a value greater than 1, messages will be queued until this threshold is reached or + // BatchingMaxSize (see below) has been reached or the batch interval has elapsed. + BatchingMaxMessages uint + + // BatchingMaxSize specifies the maximum number of bytes permitted in a batch. (default 128 KB) + // If set to a value greater than 1, messages will be queued until this threshold is reached or + // BatchingMaxMessages (see above) has been reached or the batch interval has elapsed. + BatchingMaxSize uint + + // Interceptors is a chain of interceptors, These interceptors will be called at some points defined + // in ProducerInterceptor interface + Interceptors ProducerInterceptors + + // Schema represents the schema implementation. + Schema Schema + + // MaxReconnectToBroker specifies the maximum retry number of reconnectToBroker. (default: ultimate) + MaxReconnectToBroker *uint + + // BackoffPolicy parameterize the following options in the reconnection logic to + // allow users to customize the reconnection logic (minBackoff, maxBackoff and jitterPercentage) + BackoffPolicy internal.BackoffPolicy + + // BatcherBuilderType sets the batch builder type (default DefaultBatchBuilder) + // This will be used to create batch container when batching is enabled. + // Options: + // - DefaultBatchBuilder + // - KeyBasedBatchBuilder + BatcherBuilderType + + // PartitionsAutoDiscoveryInterval is the time interval for the background process to discover new partitions + // Default is 1 minute + PartitionsAutoDiscoveryInterval time.Duration + + // Disable multiple Schame Version + // Default false + DisableMultiSchema bool + + // Encryption specifies the fields required to encrypt a message + Encryption *ProducerEncryptionInfo + + // EnableChunking controls whether automatic chunking of messages is enabled for the producer. By default, chunking + // is disabled. + // Chunking can not be enabled when batching is enabled. + EnableChunking bool + + // ChunkMaxMessageSize is the max size of single chunk payload. + // It will actually only take effect if it is smaller than the maxMessageSize from the broker. + ChunkMaxMessageSize uint + + // The type of access to the topic that the producer requires. (default ProducerAccessModeShared) + // Options: + // - ProducerAccessModeShared + // - ProducerAccessModeExclusive + ProducerAccessMode +} + +// Producer is used to publish messages on a topic +type Producer interface { + // Topic return the topic to which producer is publishing to + Topic() string + + // Name return the producer name which could have been assigned by the system or specified by the client + Name() string + + // Send a message + // This call will be blocking until is successfully acknowledged by the Pulsar broker. + // Example: + // producer.Send(ctx, pulsar.ProducerMessage{ Payload: myPayload }) + Send(context.Context, *ProducerMessage) (MessageID, error) + + // SendAsync a message in asynchronous mode + // This call is blocked when the `event channel` becomes full (default: 10) or the + // `maxPendingMessages` becomes full (default: 1000) + // The callback will report back the message being published and + // the eventual error in publishing + SendAsync(context.Context, *ProducerMessage, func(MessageID, *ProducerMessage, error)) + + // LastSequenceID get the last sequence id that was published by this producer. + // This represent either the automatically assigned or custom sequence id (set on the ProducerMessage) that + // was published and acknowledged by the broker. + // After recreating a producer with the same producer name, this will return the last message that was + // published in the previous producer session, or -1 if there no message was ever published. + // return the last sequence id published by this producer. + LastSequenceID() int64 + + // Flush all the messages buffered in the client and wait until all messages have been successfully + // persisted. + Flush() error + + // Close the producer and releases resources allocated + // No more writes will be accepted from this producer. Waits until all pending write request are persisted. In case + // of errors, pending writes will not be retried. + Close() +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/producer_impl.go b/vendor/github.com/apache/pulsar-client-go/pulsar/producer_impl.go new file mode 100644 index 00000000..3c45b597 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/producer_impl.go @@ -0,0 +1,363 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" + "fmt" + "sync" + "sync/atomic" + "time" + "unsafe" + + "github.com/apache/pulsar-client-go/pulsar/crypto" + "github.com/apache/pulsar-client-go/pulsar/internal" + "github.com/apache/pulsar-client-go/pulsar/log" +) + +const ( + // defaultSendTimeout init default timeout for ack since sent. + defaultSendTimeout = 30 * time.Second + + // defaultBatchingMaxPublishDelay init default for maximum delay to batch messages + defaultBatchingMaxPublishDelay = 10 * time.Millisecond + + // defaultMaxBatchSize init default for maximum number of bytes per batch + defaultMaxBatchSize = 128 * 1024 + + // defaultMaxMessagesPerBatch init default num of entries in per batch. + defaultMaxMessagesPerBatch = 1000 + + // defaultPartitionsAutoDiscoveryInterval init default time interval for partitions auto discovery + defaultPartitionsAutoDiscoveryInterval = 1 * time.Minute +) + +type producer struct { + sync.RWMutex + client *client + options *ProducerOptions + topic string + producers []Producer + producersPtr unsafe.Pointer + numPartitions uint32 + messageRouter func(*ProducerMessage, TopicMetadata) int + closeOnce sync.Once + stopDiscovery func() + log log.Logger + metrics *internal.LeveledMetrics +} + +func getHashingFunction(s HashingScheme) func(string) uint32 { + switch s { + case JavaStringHash: + return internal.JavaStringHash + case Murmur3_32Hash: + return internal.Murmur3_32Hash + default: + return internal.JavaStringHash + } +} + +func newProducer(client *client, options *ProducerOptions) (*producer, error) { + if options.Topic == "" { + return nil, newError(InvalidTopicName, "Topic name is required for producer") + } + + if options.SendTimeout == 0 { + options.SendTimeout = defaultSendTimeout + } + if options.BatchingMaxMessages == 0 { + options.BatchingMaxMessages = defaultMaxMessagesPerBatch + } + if options.BatchingMaxSize == 0 { + options.BatchingMaxSize = defaultMaxBatchSize + } + if options.BatchingMaxPublishDelay <= 0 { + options.BatchingMaxPublishDelay = defaultBatchingMaxPublishDelay + } + if options.PartitionsAutoDiscoveryInterval <= 0 { + options.PartitionsAutoDiscoveryInterval = defaultPartitionsAutoDiscoveryInterval + } + + if !options.DisableBatching && options.EnableChunking { + return nil, fmt.Errorf("batching and chunking can not be enabled together") + } + + p := &producer{ + options: options, + topic: options.Topic, + client: client, + log: client.log.SubLogger(log.Fields{"topic": options.Topic}), + metrics: client.metrics.GetLeveledMetrics(options.Topic), + } + + if options.Interceptors == nil { + options.Interceptors = defaultProducerInterceptors + } + + if options.MessageRouter == nil { + internalRouter := NewDefaultRouter( + getHashingFunction(options.HashingScheme), + options.BatchingMaxMessages, + options.BatchingMaxSize, + options.BatchingMaxPublishDelay, + options.DisableBatching) + p.messageRouter = func(message *ProducerMessage, metadata TopicMetadata) int { + return internalRouter(message, metadata.NumPartitions()) + } + } else { + p.messageRouter = options.MessageRouter + } + + if options.Schema != nil && options.Schema.GetSchemaInfo() != nil { + if options.Schema.GetSchemaInfo().Type == NONE { + options.Schema = NewBytesSchema(nil) + } + } + + encryption := options.Encryption + // add default message crypto if not provided + if encryption != nil && len(encryption.Keys) > 0 { + if encryption.KeyReader == nil { + return nil, fmt.Errorf("encryption is enabled, KeyReader can not be nil") + } + + if encryption.MessageCrypto == nil { + logCtx := fmt.Sprintf("[%v] [%v]", p.topic, p.options.Name) + messageCrypto, err := crypto.NewDefaultMessageCrypto(logCtx, + true, + client.log.SubLogger(log.Fields{"topic": p.topic})) + if err != nil { + return nil, fmt.Errorf("unable to get MessageCrypto instance. Producer creation is abandoned. %v", err) + } + p.options.Encryption.MessageCrypto = messageCrypto + } + } + + err := p.internalCreatePartitionsProducers() + if err != nil { + return nil, err + } + + p.stopDiscovery = p.runBackgroundPartitionDiscovery(options.PartitionsAutoDiscoveryInterval) + + p.metrics.ProducersOpened.Inc() + return p, nil +} + +func (p *producer) runBackgroundPartitionDiscovery(period time.Duration) (cancel func()) { + var wg sync.WaitGroup + stopDiscoveryCh := make(chan struct{}) + ticker := time.NewTicker(period) + + wg.Add(1) + go func() { + defer wg.Done() + for { + select { + case <-stopDiscoveryCh: + return + case <-ticker.C: + p.log.Debug("Auto discovering new partitions") + p.internalCreatePartitionsProducers() + } + } + }() + + return func() { + ticker.Stop() + close(stopDiscoveryCh) + wg.Wait() + } +} + +func (p *producer) internalCreatePartitionsProducers() error { + partitions, err := p.client.TopicPartitions(p.topic) + if err != nil { + return err + } + + oldNumPartitions := 0 + newNumPartitions := len(partitions) + + p.Lock() + defer p.Unlock() + + oldProducers := p.producers + oldNumPartitions = len(oldProducers) + + if oldProducers != nil { + if oldNumPartitions == newNumPartitions { + p.log.Debug("Number of partitions in topic has not changed") + return nil + } + + p.log.WithField("old_partitions", oldNumPartitions). + WithField("new_partitions", newNumPartitions). + Info("Changed number of partitions in topic") + + } + + p.producers = make([]Producer, newNumPartitions) + + // When for some reason (eg: forced deletion of sub partition) causes oldNumPartitions> newNumPartitions, + // we need to rebuild the cache of new producers, otherwise the array will be out of bounds. + if oldProducers != nil && oldNumPartitions < newNumPartitions { + // Copy over the existing consumer instances + for i := 0; i < oldNumPartitions; i++ { + p.producers[i] = oldProducers[i] + } + } + + type ProducerError struct { + partition int + prod Producer + err error + } + + startPartition := oldNumPartitions + partitionsToAdd := newNumPartitions - oldNumPartitions + if partitionsToAdd < 0 { + partitionsToAdd = newNumPartitions + startPartition = 0 + } + c := make(chan ProducerError, partitionsToAdd) + + for partitionIdx := startPartition; partitionIdx < newNumPartitions; partitionIdx++ { + partition := partitions[partitionIdx] + + go func(partitionIdx int, partition string) { + prod, e := newPartitionProducer(p.client, partition, p.options, partitionIdx, p.metrics) + c <- ProducerError{ + partition: partitionIdx, + prod: prod, + err: e, + } + }(partitionIdx, partition) + } + + for i := 0; i < partitionsToAdd; i++ { + pe, ok := <-c + if ok { + if pe.err != nil { + err = pe.err + } else { + p.producers[pe.partition] = pe.prod + } + } + } + + if err != nil { + // Since there were some failures, cleanup all the partitions that succeeded in creating the producers + for _, producer := range p.producers { + if producer != nil { + producer.Close() + } + } + return err + } + + if newNumPartitions < oldNumPartitions { + p.metrics.ProducersPartitions.Set(float64(newNumPartitions)) + } else { + p.metrics.ProducersPartitions.Add(float64(partitionsToAdd)) + } + atomic.StorePointer(&p.producersPtr, unsafe.Pointer(&p.producers)) + atomic.StoreUint32(&p.numPartitions, uint32(len(p.producers))) + return nil +} + +func (p *producer) Topic() string { + return p.topic +} + +func (p *producer) Name() string { + p.RLock() + defer p.RUnlock() + + return p.producers[0].Name() +} + +func (p *producer) NumPartitions() uint32 { + return atomic.LoadUint32(&p.numPartitions) +} + +func (p *producer) Send(ctx context.Context, msg *ProducerMessage) (MessageID, error) { + return p.getPartition(msg).Send(ctx, msg) +} + +func (p *producer) SendAsync(ctx context.Context, msg *ProducerMessage, + callback func(MessageID, *ProducerMessage, error)) { + p.getPartition(msg).SendAsync(ctx, msg, callback) +} + +func (p *producer) getPartition(msg *ProducerMessage) Producer { + // Since partitions can only increase, it's ok if the producers list + // is updated in between. The numPartition is updated only after the list. + partition := p.messageRouter(msg, p) + producers := *(*[]Producer)(atomic.LoadPointer(&p.producersPtr)) + if partition >= len(producers) { + // We read the old producers list while the count was already + // updated + partition %= len(producers) + } + return producers[partition] +} + +func (p *producer) LastSequenceID() int64 { + p.RLock() + defer p.RUnlock() + + var maxSeq int64 = -1 + for _, pp := range p.producers { + s := pp.LastSequenceID() + if s > maxSeq { + maxSeq = s + } + } + return maxSeq +} + +func (p *producer) Flush() error { + p.RLock() + defer p.RUnlock() + + for _, pp := range p.producers { + if err := pp.Flush(); err != nil { + return err + } + + } + return nil +} + +func (p *producer) Close() { + p.closeOnce.Do(func() { + p.stopDiscovery() + + p.Lock() + defer p.Unlock() + + for _, pp := range p.producers { + pp.Close() + } + p.client.handlers.Del(p) + p.metrics.ProducersPartitions.Sub(float64(len(p.producers))) + p.metrics.ProducersClosed.Inc() + }) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/producer_interceptor.go b/vendor/github.com/apache/pulsar-client-go/pulsar/producer_interceptor.go new file mode 100644 index 00000000..cb2cc152 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/producer_interceptor.go @@ -0,0 +1,43 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +type ProducerInterceptor interface { + // BeforeSend This is called before send the message to the brokers. This method is allowed to modify the + BeforeSend(producer Producer, message *ProducerMessage) + + // OnSendAcknowledgement This method is called when the message sent to the broker has been acknowledged, + // or when sending the message fails. + OnSendAcknowledgement(producer Producer, message *ProducerMessage, msgID MessageID) +} + +type ProducerInterceptors []ProducerInterceptor + +func (x ProducerInterceptors) BeforeSend(producer Producer, message *ProducerMessage) { + for i := range x { + x[i].BeforeSend(producer, message) + } +} + +func (x ProducerInterceptors) OnSendAcknowledgement(producer Producer, message *ProducerMessage, msgID MessageID) { + for i := range x { + x[i].OnSendAcknowledgement(producer, message, msgID) + } +} + +var defaultProducerInterceptors = make(ProducerInterceptors, 0) diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/producer_partition.go b/vendor/github.com/apache/pulsar-client-go/pulsar/producer_partition.go new file mode 100644 index 00000000..744df799 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/producer_partition.go @@ -0,0 +1,1397 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" + "errors" + "fmt" + "math" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/apache/pulsar-client-go/pulsar/internal/compression" + internalcrypto "github.com/apache/pulsar-client-go/pulsar/internal/crypto" + + "google.golang.org/protobuf/proto" + + "github.com/apache/pulsar-client-go/pulsar/internal" + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "github.com/apache/pulsar-client-go/pulsar/log" + + uAtomic "go.uber.org/atomic" +) + +type producerState int32 + +const ( + // producer states + producerInit = iota + producerReady + producerClosing + producerClosed +) + +var ( + errFailAddToBatch = newError(AddToBatchFailed, "message add to batch failed") + errSendTimeout = newError(TimeoutError, "message send timeout") + errSendQueueIsFull = newError(ProducerQueueIsFull, "producer send queue is full") + errContextExpired = newError(TimeoutError, "message send context expired") + errMessageTooLarge = newError(MessageTooBig, "message size exceeds MaxMessageSize") + errMetaTooLarge = newError(InvalidMessage, "message metadata size exceeds MaxMessageSize") + errProducerClosed = newError(ProducerClosed, "producer already been closed") + errMemoryBufferIsFull = newError(ClientMemoryBufferIsFull, "client memory buffer is full") + + buffersPool sync.Pool +) + +var errTopicNotFount = "TopicNotFound" + +type partitionProducer struct { + state uAtomic.Int32 + client *client + topic string + log log.Logger + + conn uAtomic.Value + + options *ProducerOptions + producerName string + userProvidedProducerName bool + producerID uint64 + batchBuilder internal.BatchBuilder + sequenceIDGenerator *uint64 + batchFlushTicker *time.Ticker + encryptor internalcrypto.Encryptor + compressionProvider compression.Provider + + // Channel where app is posting messages to be published + eventsChan chan interface{} + closeCh chan struct{} + connectClosedCh chan connectionClosed + + publishSemaphore internal.Semaphore + pendingQueue internal.BlockingQueue + lastSequenceID int64 + schemaInfo *SchemaInfo + partitionIdx int32 + metrics *internal.LeveledMetrics + epoch uint64 + schemaCache *schemaCache + topicEpoch *uint64 +} + +type schemaCache struct { + lock sync.RWMutex + schemas map[string][]byte +} + +func newSchemaCache() *schemaCache { + return &schemaCache{ + schemas: make(map[string][]byte), + } +} + +func (s *schemaCache) Put(schema *SchemaInfo, schemaVersion []byte) { + s.lock.Lock() + defer s.lock.Unlock() + + key := schema.hash() + s.schemas[key] = schemaVersion +} + +func (s *schemaCache) Get(schema *SchemaInfo) (schemaVersion []byte) { + s.lock.RLock() + defer s.lock.RUnlock() + + key := schema.hash() + return s.schemas[key] +} +func newPartitionProducer(client *client, topic string, options *ProducerOptions, partitionIdx int, + metrics *internal.LeveledMetrics) ( + *partitionProducer, error) { + var batchingMaxPublishDelay time.Duration + if options.BatchingMaxPublishDelay != 0 { + batchingMaxPublishDelay = options.BatchingMaxPublishDelay + } else { + batchingMaxPublishDelay = defaultBatchingMaxPublishDelay + } + + var maxPendingMessages int + if options.MaxPendingMessages == 0 { + maxPendingMessages = 1000 + } else { + maxPendingMessages = options.MaxPendingMessages + } + + logger := client.log.SubLogger(log.Fields{"topic": topic}) + + p := &partitionProducer{ + client: client, + topic: topic, + log: logger, + options: options, + producerID: client.rpcClient.NewProducerID(), + eventsChan: make(chan interface{}, maxPendingMessages), + connectClosedCh: make(chan connectionClosed, 10), + closeCh: make(chan struct{}), + batchFlushTicker: time.NewTicker(batchingMaxPublishDelay), + compressionProvider: internal.GetCompressionProvider(pb.CompressionType(options.CompressionType), + compression.Level(options.CompressionLevel)), + publishSemaphore: internal.NewSemaphore(int32(maxPendingMessages)), + pendingQueue: internal.NewBlockingQueue(maxPendingMessages), + lastSequenceID: -1, + partitionIdx: int32(partitionIdx), + metrics: metrics, + epoch: 0, + schemaCache: newSchemaCache(), + } + if p.options.DisableBatching { + p.batchFlushTicker.Stop() + } + p.setProducerState(producerInit) + + if options.Schema != nil && options.Schema.GetSchemaInfo() != nil { + p.schemaInfo = options.Schema.GetSchemaInfo() + } else { + p.schemaInfo = nil + } + + if options.Name != "" { + p.producerName = options.Name + p.userProvidedProducerName = true + } else { + p.userProvidedProducerName = false + } + err := p.grabCnx() + if err != nil { + p.batchFlushTicker.Stop() + logger.WithError(err).Error("Failed to create producer at newPartitionProducer") + return nil, err + } + + p.log = p.log.SubLogger(log.Fields{ + "producer_name": p.producerName, + "producerID": p.producerID, + }) + + p.log.WithField("cnx", p._getConn().ID()).Info("Created producer") + p.setProducerState(producerReady) + + if p.options.SendTimeout > 0 { + go p.failTimeoutMessages() + } + + go p.runEventsLoop() + + return p, nil +} + +func (p *partitionProducer) grabCnx() error { + lr, err := p.client.lookupService.Lookup(p.topic) + if err != nil { + p.log.WithError(err).Warn("Failed to lookup topic") + return err + } + + p.log.Debug("Lookup result: ", lr) + id := p.client.rpcClient.NewRequestID() + + // set schema info for producer + + var pbSchema *pb.Schema + if p.schemaInfo != nil { + tmpSchemaType := pb.Schema_Type(int32(p.schemaInfo.Type)) + pbSchema = &pb.Schema{ + Name: proto.String(p.schemaInfo.Name), + Type: &tmpSchemaType, + SchemaData: []byte(p.schemaInfo.Schema), + Properties: internal.ConvertFromStringMap(p.schemaInfo.Properties), + } + p.log.Debugf("The partition producer schema name is: %s", pbSchema.Name) + } else { + p.log.Debug("The partition producer schema is nil") + } + + cmdProducer := &pb.CommandProducer{ + RequestId: proto.Uint64(id), + Topic: proto.String(p.topic), + Encrypted: nil, + ProducerId: proto.Uint64(p.producerID), + Schema: pbSchema, + Epoch: proto.Uint64(atomic.LoadUint64(&p.epoch)), + UserProvidedProducerName: proto.Bool(p.userProvidedProducerName), + ProducerAccessMode: toProtoProducerAccessMode(p.options.ProducerAccessMode).Enum(), + } + + if p.topicEpoch != nil { + cmdProducer.TopicEpoch = proto.Uint64(*p.topicEpoch) + } + + if p.producerName != "" { + cmdProducer.ProducerName = proto.String(p.producerName) + } + + if len(p.options.Properties) > 0 { + cmdProducer.Metadata = toKeyValues(p.options.Properties) + } + res, err := p.client.rpcClient.Request(lr.LogicalAddr, lr.PhysicalAddr, id, pb.BaseCommand_PRODUCER, cmdProducer) + if err != nil { + p.log.WithError(err).Error("Failed to create producer at send PRODUCER request") + return err + } + + p.producerName = res.Response.ProducerSuccess.GetProducerName() + nextTopicEpoch := res.Response.ProducerSuccess.GetTopicEpoch() + p.topicEpoch = &nextTopicEpoch + + if p.options.Encryption != nil { + p.encryptor = internalcrypto.NewProducerEncryptor(p.options.Encryption.Keys, + p.options.Encryption.KeyReader, + p.options.Encryption.MessageCrypto, + p.options.Encryption.ProducerCryptoFailureAction, p.log) + } else { + p.encryptor = internalcrypto.NewNoopEncryptor() + } + + if p.sequenceIDGenerator == nil { + nextSequenceID := uint64(res.Response.ProducerSuccess.GetLastSequenceId() + 1) + p.sequenceIDGenerator = &nextSequenceID + } + + schemaVersion := res.Response.ProducerSuccess.GetSchemaVersion() + if len(schemaVersion) != 0 { + p.schemaCache.Put(p.schemaInfo, schemaVersion) + } + + p._setConn(res.Cnx) + err = p._getConn().RegisterListener(p.producerID, p) + if err != nil { + return err + } + + if !p.options.DisableBatching && p.batchBuilder == nil { + provider, err := GetBatcherBuilderProvider(p.options.BatcherBuilderType) + if err != nil { + return err + } + maxMessageSize := uint32(p._getConn().GetMaxMessageSize()) + p.batchBuilder, err = provider(p.options.BatchingMaxMessages, p.options.BatchingMaxSize, + maxMessageSize, p.producerName, p.producerID, pb.CompressionType(p.options.CompressionType), + compression.Level(p.options.CompressionLevel), + p, + p.log, + p.encryptor) + if err != nil { + return err + } + } + + p.log.WithFields(log.Fields{ + "cnx": res.Cnx.ID(), + "epoch": atomic.LoadUint64(&p.epoch), + }).Info("Connected producer") + + pendingItems := p.pendingQueue.ReadableSlice() + viewSize := len(pendingItems) + if viewSize > 0 { + p.log.Infof("Resending %d pending batches", viewSize) + lastViewItem := pendingItems[viewSize-1].(*pendingItem) + + // iterate at most pending items + for i := 0; i < viewSize; i++ { + item := p.pendingQueue.Poll() + if item == nil { + continue + } + pi := item.(*pendingItem) + // when resending pending batches, we update the sendAt timestamp and put to the back of queue + // to avoid pending item been removed by failTimeoutMessages and cause race condition + pi.Lock() + pi.sentAt = time.Now() + pi.Unlock() + p.pendingQueue.Put(pi) + p._getConn().WriteData(pi.buffer) + + if pi == lastViewItem { + break + } + } + } + return nil +} + +type connectionClosed struct{} + +func (p *partitionProducer) GetBuffer() internal.Buffer { + b, ok := buffersPool.Get().(internal.Buffer) + if ok { + b.Clear() + } + return b +} + +func (p *partitionProducer) ConnectionClosed() { + // Trigger reconnection in the produce goroutine + p.log.WithField("cnx", p._getConn().ID()).Warn("Connection was closed") + p.connectClosedCh <- connectionClosed{} +} + +func (p *partitionProducer) getOrCreateSchema(schemaInfo *SchemaInfo) (schemaVersion []byte, err error) { + + tmpSchemaType := pb.Schema_Type(int32(schemaInfo.Type)) + pbSchema := &pb.Schema{ + Name: proto.String(schemaInfo.Name), + Type: &tmpSchemaType, + SchemaData: []byte(schemaInfo.Schema), + Properties: internal.ConvertFromStringMap(schemaInfo.Properties), + } + id := p.client.rpcClient.NewRequestID() + req := &pb.CommandGetOrCreateSchema{ + RequestId: proto.Uint64(id), + Topic: proto.String(p.topic), + Schema: pbSchema, + } + res, err := p.client.rpcClient.RequestOnCnx(p._getConn(), id, pb.BaseCommand_GET_OR_CREATE_SCHEMA, req) + if err != nil { + return + } + if res.Response.Error != nil { + err = errors.New(res.Response.GetError().String()) + return + } + if res.Response.GetOrCreateSchemaResponse.ErrorCode != nil { + err = errors.New(*res.Response.GetOrCreateSchemaResponse.ErrorMessage) + return + } + return res.Response.GetOrCreateSchemaResponse.SchemaVersion, nil +} + +func (p *partitionProducer) reconnectToBroker() { + var maxRetry int + if p.options.MaxReconnectToBroker == nil { + maxRetry = -1 + } else { + maxRetry = int(*p.options.MaxReconnectToBroker) + } + + for maxRetry != 0 { + if p.getProducerState() != producerReady { + // Producer is already closing + p.log.Info("producer state not ready, exit reconnect") + return + } + + var ( + delayReconnectTime time.Duration + defaultBackoff = internal.DefaultBackoff{} + ) + + if p.options.BackoffPolicy == nil { + delayReconnectTime = defaultBackoff.Next() + } else { + delayReconnectTime = p.options.BackoffPolicy.Next() + } + p.log.Info("Reconnecting to broker in ", delayReconnectTime) + time.Sleep(delayReconnectTime) + atomic.AddUint64(&p.epoch, 1) + err := p.grabCnx() + if err == nil { + // Successfully reconnected + p.log.WithField("cnx", p._getConn().ID()).Info("Reconnected producer to broker") + return + } + p.log.WithError(err).Error("Failed to create producer at reconnect") + errMsg := err.Error() + if strings.Contains(errMsg, errTopicNotFount) { + // when topic is deleted, we should give up reconnection. + p.log.Warn("Topic Not Found.") + break + } + + if maxRetry > 0 { + maxRetry-- + } + p.metrics.ProducersReconnectFailure.Inc() + if maxRetry == 0 || defaultBackoff.IsMaxBackoffReached() { + p.metrics.ProducersReconnectMaxRetry.Inc() + } + } +} + +func (p *partitionProducer) runEventsLoop() { + go func() { + for { + select { + case <-p.closeCh: + p.log.Info("close producer, exit reconnect") + return + case <-p.connectClosedCh: + p.log.Info("runEventsLoop will reconnect in producer") + p.reconnectToBroker() + } + } + }() + + for { + select { + case i := <-p.eventsChan: + switch v := i.(type) { + case *sendRequest: + p.internalSend(v) + case *flushRequest: + p.internalFlush(v) + case *closeProducer: + p.internalClose(v) + return + } + case <-p.batchFlushTicker.C: + p.internalFlushCurrentBatch() + } + } +} + +func (p *partitionProducer) Topic() string { + return p.topic +} + +func (p *partitionProducer) Name() string { + return p.producerName +} + +func (p *partitionProducer) internalSend(request *sendRequest) { + p.log.Debug("Received send request: ", *request.msg) + + msg := request.msg + + // read payload from message + uncompressedPayload := msg.Payload + uncompressedPayloadSize := int64(len(uncompressedPayload)) + + var schemaPayload []byte + var err error + if msg.Value != nil && msg.Payload != nil { + p.log.Error("Can not set Value and Payload both") + request.callback(nil, request.msg, errors.New("can not set Value and Payload both")) + return + } + + // The block chan must be closed when returned with exception + defer request.stopBlock() + if !p.canAddToQueue(request, uncompressedPayloadSize) { + return + } + + if p.options.DisableMultiSchema { + if msg.Schema != nil && p.options.Schema != nil && + msg.Schema.GetSchemaInfo().hash() != p.options.Schema.GetSchemaInfo().hash() { + p.releaseSemaphoreAndMem(uncompressedPayloadSize) + request.callback(nil, request.msg, fmt.Errorf("msg schema can not match with producer schema")) + p.log.WithError(err).Errorf("The producer %s of the topic %s is disabled the `MultiSchema`", p.producerName, p.topic) + return + } + } + var schema Schema + var schemaVersion []byte + if msg.Schema != nil { + schema = msg.Schema + } else if p.options.Schema != nil { + schema = p.options.Schema + } + if msg.Value != nil { + // payload and schema are mutually exclusive + // try to get payload from schema value only if payload is not set + if uncompressedPayload == nil && schema != nil { + schemaPayload, err = schema.Encode(msg.Value) + if err != nil { + p.releaseSemaphoreAndMem(uncompressedPayloadSize) + request.callback(nil, request.msg, newError(SchemaFailure, err.Error())) + p.log.WithError(err).Errorf("Schema encode message failed %s", msg.Value) + return + } + } + } + if uncompressedPayload == nil { + uncompressedPayload = schemaPayload + } + + if schema != nil { + schemaVersion = p.schemaCache.Get(schema.GetSchemaInfo()) + if schemaVersion == nil { + schemaVersion, err = p.getOrCreateSchema(schema.GetSchemaInfo()) + if err != nil { + p.releaseSemaphoreAndMem(uncompressedPayloadSize) + p.log.WithError(err).Error("get schema version fail") + request.callback(nil, request.msg, fmt.Errorf("get schema version fail, err: %w", err)) + return + } + p.schemaCache.Put(schema.GetSchemaInfo(), schemaVersion) + } + } + + uncompressedSize := len(uncompressedPayload) + + deliverAt := msg.DeliverAt + if msg.DeliverAfter.Nanoseconds() > 0 { + deliverAt = time.Now().Add(msg.DeliverAfter) + } + + mm := p.genMetadata(msg, uncompressedSize, deliverAt) + + // set default ReplicationClusters when DisableReplication + if msg.DisableReplication { + msg.ReplicationClusters = []string{"__local__"} + } + + sendAsBatch := !p.options.DisableBatching && + msg.ReplicationClusters == nil && + deliverAt.UnixNano() < 0 + + // Once the batching is enabled, it can close blockCh early to make block finish + if sendAsBatch { + request.stopBlock() + } else { + // update sequence id for metadata, make the size of msgMetadata more accurate + // batch sending will update sequence ID in the BatchBuilder + p.updateMetadataSeqID(mm, msg) + } + + maxMessageSize := int(p._getConn().GetMaxMessageSize()) + + // compress payload if not batching + var compressedPayload []byte + var compressedSize int + var checkSize int + if !sendAsBatch { + compressedPayload = p.compressionProvider.Compress(nil, uncompressedPayload) + compressedSize = len(compressedPayload) + checkSize = compressedSize + + // set the compress type in msgMetaData + compressionType := pb.CompressionType(p.options.CompressionType) + if compressionType != pb.CompressionType_NONE { + mm.Compression = &compressionType + } + } else { + // final check for batching message is in serializeMessage + // this is a double check + checkSize = uncompressedSize + } + + // if msg is too large and chunking is disabled + if checkSize > maxMessageSize && !p.options.EnableChunking { + p.releaseSemaphoreAndMem(uncompressedPayloadSize) + request.callback(nil, request.msg, errMessageTooLarge) + p.log.WithError(errMessageTooLarge). + WithField("size", checkSize). + WithField("properties", msg.Properties). + Errorf("MaxMessageSize %d", maxMessageSize) + p.metrics.PublishErrorsMsgTooLarge.Inc() + return + } + + var totalChunks int + // max chunk payload size + var payloadChunkSize int + if sendAsBatch || !p.options.EnableChunking { + totalChunks = 1 + payloadChunkSize = int(p._getConn().GetMaxMessageSize()) + } else { + payloadChunkSize = int(p._getConn().GetMaxMessageSize()) - proto.Size(mm) + if payloadChunkSize <= 0 { + p.releaseSemaphoreAndMem(uncompressedPayloadSize) + request.callback(nil, msg, errMetaTooLarge) + p.log.WithError(errMetaTooLarge). + WithField("metadata size", proto.Size(mm)). + WithField("properties", msg.Properties). + Errorf("MaxMessageSize %d", int(p._getConn().GetMaxMessageSize())) + p.metrics.PublishErrorsMsgTooLarge.Inc() + return + } + // set ChunkMaxMessageSize + if p.options.ChunkMaxMessageSize != 0 { + payloadChunkSize = int(math.Min(float64(payloadChunkSize), float64(p.options.ChunkMaxMessageSize))) + } + totalChunks = int(math.Max(1, math.Ceil(float64(compressedSize)/float64(payloadChunkSize)))) + } + + // set total chunks to send request + request.totalChunks = totalChunks + + if !sendAsBatch { + if totalChunks > 1 { + var lhs, rhs int + uuid := fmt.Sprintf("%s-%s", p.producerName, strconv.FormatUint(*mm.SequenceId, 10)) + mm.Uuid = proto.String(uuid) + mm.NumChunksFromMsg = proto.Int32(int32(totalChunks)) + mm.TotalChunkMsgSize = proto.Int32(int32(compressedSize)) + cr := newChunkRecorder() + for chunkID := 0; chunkID < totalChunks; chunkID++ { + lhs = chunkID * payloadChunkSize + if rhs = lhs + payloadChunkSize; rhs > compressedSize { + rhs = compressedSize + } + // update chunk id + mm.ChunkId = proto.Int32(int32(chunkID)) + nsr := &sendRequest{ + ctx: request.ctx, + msg: request.msg, + callback: request.callback, + callbackOnce: request.callbackOnce, + publishTime: request.publishTime, + blockCh: request.blockCh, + closeBlockChOnce: request.closeBlockChOnce, + totalChunks: totalChunks, + chunkID: chunkID, + uuid: uuid, + chunkRecorder: cr, + } + // the permit of first chunk has acquired + if chunkID != 0 && !p.canAddToQueue(nsr, 0) { + p.releaseSemaphoreAndMem(uncompressedPayloadSize - int64(rhs)) + return + } + p.internalSingleSend(mm, compressedPayload[lhs:rhs], nsr, uint32(maxMessageSize)) + } + // close the blockCh when all the chunks acquired permits + request.stopBlock() + } else { + // close the blockCh when totalChunks is 1 (it has acquired permits) + request.stopBlock() + p.internalSingleSend(mm, compressedPayload, request, uint32(maxMessageSize)) + } + } else { + smm := p.genSingleMessageMetadataInBatch(msg, uncompressedSize) + multiSchemaEnabled := !p.options.DisableMultiSchema + added := p.batchBuilder.Add(smm, p.sequenceIDGenerator, uncompressedPayload, request, + msg.ReplicationClusters, deliverAt, schemaVersion, multiSchemaEnabled) + if !added { + // The current batch is full.. flush it and retry + + p.internalFlushCurrentBatch() + + // after flushing try again to add the current payload + if ok := p.batchBuilder.Add(smm, p.sequenceIDGenerator, uncompressedPayload, request, + msg.ReplicationClusters, deliverAt, schemaVersion, multiSchemaEnabled); !ok { + p.releaseSemaphoreAndMem(uncompressedPayloadSize) + request.callback(nil, request.msg, errFailAddToBatch) + p.log.WithField("size", uncompressedSize). + WithField("properties", msg.Properties). + Error("unable to add message to batch") + return + } + } + if request.flushImmediately { + + p.internalFlushCurrentBatch() + + } + } +} + +func (p *partitionProducer) genMetadata(msg *ProducerMessage, + uncompressedSize int, + deliverAt time.Time) (mm *pb.MessageMetadata) { + mm = &pb.MessageMetadata{ + ProducerName: &p.producerName, + PublishTime: proto.Uint64(internal.TimestampMillis(time.Now())), + ReplicateTo: msg.ReplicationClusters, + UncompressedSize: proto.Uint32(uint32(uncompressedSize)), + } + + if msg.Key != "" { + mm.PartitionKey = proto.String(msg.Key) + } + + if msg.Properties != nil { + mm.Properties = internal.ConvertFromStringMap(msg.Properties) + } + + if deliverAt.UnixNano() > 0 { + mm.DeliverAtTime = proto.Int64(int64(internal.TimestampMillis(deliverAt))) + } + + return +} + +func (p *partitionProducer) updateMetadataSeqID(mm *pb.MessageMetadata, msg *ProducerMessage) { + if msg.SequenceID != nil { + mm.SequenceId = proto.Uint64(uint64(*msg.SequenceID)) + } else { + mm.SequenceId = proto.Uint64(internal.GetAndAdd(p.sequenceIDGenerator, 1)) + } +} + +func (p *partitionProducer) genSingleMessageMetadataInBatch(msg *ProducerMessage, + uncompressedSize int) (smm *pb.SingleMessageMetadata) { + smm = &pb.SingleMessageMetadata{ + PayloadSize: proto.Int32(int32(uncompressedSize)), + } + + if !msg.EventTime.IsZero() { + smm.EventTime = proto.Uint64(internal.TimestampMillis(msg.EventTime)) + } + + if msg.Key != "" { + smm.PartitionKey = proto.String(msg.Key) + } + + if len(msg.OrderingKey) != 0 { + smm.OrderingKey = []byte(msg.OrderingKey) + } + + if msg.Properties != nil { + smm.Properties = internal.ConvertFromStringMap(msg.Properties) + } + + var sequenceID uint64 + if msg.SequenceID != nil { + sequenceID = uint64(*msg.SequenceID) + } else { + sequenceID = internal.GetAndAdd(p.sequenceIDGenerator, 1) + } + + smm.SequenceId = proto.Uint64(sequenceID) + + return +} + +func (p *partitionProducer) internalSingleSend(mm *pb.MessageMetadata, + compressedPayload []byte, + request *sendRequest, + maxMessageSize uint32) { + msg := request.msg + + payloadBuf := internal.NewBuffer(len(compressedPayload)) + payloadBuf.Write(compressedPayload) + + buffer := p.GetBuffer() + if buffer == nil { + buffer = internal.NewBuffer(int(payloadBuf.ReadableBytes() * 3 / 2)) + } + + sid := *mm.SequenceId + + if err := internal.SingleSend( + buffer, + p.producerID, + sid, + mm, + payloadBuf, + p.encryptor, + maxMessageSize, + ); err != nil { + request.callback(nil, request.msg, err) + p.releaseSemaphoreAndMem(int64(len(msg.Payload))) + p.log.WithError(err).Errorf("Single message serialize failed %s", msg.Value) + return + } + + p.pendingQueue.Put(&pendingItem{ + sentAt: time.Now(), + buffer: buffer, + sequenceID: sid, + sendRequests: []interface{}{request}, + }) + p._getConn().WriteData(buffer) +} + +type pendingItem struct { + sync.Mutex + buffer internal.Buffer + sequenceID uint64 + sentAt time.Time + sendRequests []interface{} + completed bool +} + +func (p *partitionProducer) internalFlushCurrentBatch() { + if p.batchBuilder.IsMultiBatches() { + p.internalFlushCurrentBatches() + return + } + + batchData, sequenceID, callbacks, err := p.batchBuilder.Flush() + if batchData == nil { + return + } + + // error occurred in batch flush + // report it using callback + if err != nil { + for _, cb := range callbacks { + if sr, ok := cb.(*sendRequest); ok { + sr.callback(nil, sr.msg, err) + } + } + if errors.Is(err, internal.ErrExceedMaxMessageSize) { + p.log.WithError(errMessageTooLarge). + Errorf("internal err: %s", err) + p.metrics.PublishErrorsMsgTooLarge.Inc() + return + } + return + } + + p.pendingQueue.Put(&pendingItem{ + sentAt: time.Now(), + buffer: batchData, + sequenceID: sequenceID, + sendRequests: callbacks, + }) + p._getConn().WriteData(batchData) +} + +func (p *partitionProducer) failTimeoutMessages() { + diff := func(sentAt time.Time) time.Duration { + return p.options.SendTimeout - time.Since(sentAt) + } + + t := time.NewTimer(p.options.SendTimeout) + defer t.Stop() + + for range t.C { + state := p.getProducerState() + if state == producerClosing || state == producerClosed { + return + } + + item := p.pendingQueue.Peek() + if item == nil { + // pending queue is empty + t.Reset(p.options.SendTimeout) + continue + } + oldestItem := item.(*pendingItem) + if nextWaiting := diff(oldestItem.sentAt); nextWaiting > 0 { + // none of these pending messages have timed out, wait and retry + t.Reset(nextWaiting) + continue + } + + // since pending queue is not thread safe because of there is no global iteration lock + // to control poll from pending queue, current goroutine and connection receipt handler + // iterate pending queue at the same time, this maybe a performance trade-off + // see https://github.com/apache/pulsar-client-go/pull/301 + curViewItems := p.pendingQueue.ReadableSlice() + viewSize := len(curViewItems) + if viewSize <= 0 { + // double check + t.Reset(p.options.SendTimeout) + continue + } + p.log.Infof("Failing %d messages", viewSize) + lastViewItem := curViewItems[viewSize-1].(*pendingItem) + + // iterate at most viewSize items + for i := 0; i < viewSize; i++ { + tickerNeedWaiting := time.Duration(0) + item := p.pendingQueue.CompareAndPoll( + func(m interface{}) bool { + if m == nil { + return false + } + + pi := m.(*pendingItem) + pi.Lock() + defer pi.Unlock() + if nextWaiting := diff(pi.sentAt); nextWaiting > 0 { + // current and subsequent items not timeout yet, stop iterating + tickerNeedWaiting = nextWaiting + return false + } + return true + }) + + if item == nil { + t.Reset(p.options.SendTimeout) + break + } + + if tickerNeedWaiting > 0 { + t.Reset(tickerNeedWaiting) + break + } + + pi := item.(*pendingItem) + pi.Lock() + + for _, i := range pi.sendRequests { + sr := i.(*sendRequest) + if sr.msg != nil { + size := len(sr.msg.Payload) + p.releaseSemaphoreAndMem(int64(size)) + p.metrics.MessagesPending.Dec() + p.metrics.BytesPending.Sub(float64(size)) + p.metrics.PublishErrorsTimeout.Inc() + p.log.WithError(errSendTimeout). + WithField("size", size). + WithField("properties", sr.msg.Properties) + } + + if sr.callback != nil { + sr.callbackOnce.Do(func() { + sr.callback(nil, sr.msg, errSendTimeout) + }) + } + } + + // flag the send has completed with error, flush make no effect + pi.Complete() + pi.Unlock() + + // finally reached the last view item, current iteration ends + if pi == lastViewItem { + t.Reset(p.options.SendTimeout) + break + } + } + } +} + +func (p *partitionProducer) internalFlushCurrentBatches() { + batchesData, sequenceIDs, callbacks, errs := p.batchBuilder.FlushBatches() + if batchesData == nil { + return + } + + for i := range batchesData { + // error occurred in processing batch + // report it using callback + if errs[i] != nil { + for _, cb := range callbacks[i] { + if sr, ok := cb.(*sendRequest); ok { + sr.callback(nil, sr.msg, errs[i]) + } + } + if errors.Is(errs[i], internal.ErrExceedMaxMessageSize) { + p.log.WithError(errMessageTooLarge). + Errorf("internal err: %s", errs[i]) + p.metrics.PublishErrorsMsgTooLarge.Inc() + return + } + continue + } + if batchesData[i] == nil { + continue + } + p.pendingQueue.Put(&pendingItem{ + sentAt: time.Now(), + buffer: batchesData[i], + sequenceID: sequenceIDs[i], + sendRequests: callbacks[i], + }) + p._getConn().WriteData(batchesData[i]) + } + +} + +func (p *partitionProducer) internalFlush(fr *flushRequest) { + + p.internalFlushCurrentBatch() + + pi, ok := p.pendingQueue.PeekLast().(*pendingItem) + if !ok { + close(fr.doneCh) + return + } + + // lock the pending request while adding requests + // since the ReceivedSendReceipt func iterates over this list + pi.Lock() + defer pi.Unlock() + + if pi.completed { + // The last item in the queue has been completed while we were + // looking at it. It's safe at this point to assume that every + // message enqueued before Flush() was called are now persisted + close(fr.doneCh) + return + } + + sendReq := &sendRequest{ + msg: nil, + callback: func(id MessageID, message *ProducerMessage, e error) { + fr.err = e + close(fr.doneCh) + }, + } + + pi.sendRequests = append(pi.sendRequests, sendReq) +} + +func (p *partitionProducer) Send(ctx context.Context, msg *ProducerMessage) (MessageID, error) { + var err error + var msgID MessageID + + // use atomic bool to avoid race + isDone := uAtomic.NewBool(false) + doneCh := make(chan struct{}) + + p.internalSendAsync(ctx, msg, func(ID MessageID, message *ProducerMessage, e error) { + if isDone.CAS(false, true) { + err = e + msgID = ID + close(doneCh) + } + }, true) + + // wait for send request to finish + <-doneCh + + return msgID, err +} + +func (p *partitionProducer) SendAsync(ctx context.Context, msg *ProducerMessage, + callback func(MessageID, *ProducerMessage, error)) { + p.internalSendAsync(ctx, msg, callback, false) +} + +func (p *partitionProducer) internalSendAsync(ctx context.Context, msg *ProducerMessage, + callback func(MessageID, *ProducerMessage, error), flushImmediately bool) { + if p.getProducerState() != producerReady { + // Producer is closing + callback(nil, msg, errProducerClosed) + return + } + + // bc only works when DisableBlockIfQueueFull is false + bc := make(chan struct{}) + + // callbackOnce make sure the callback is only invoked once in chunking + callbackOnce := &sync.Once{} + + sr := &sendRequest{ + ctx: ctx, + msg: msg, + callback: callback, + callbackOnce: callbackOnce, + flushImmediately: flushImmediately, + publishTime: time.Now(), + blockCh: bc, + closeBlockChOnce: &sync.Once{}, + } + p.options.Interceptors.BeforeSend(p, msg) + + p.eventsChan <- sr + + if !p.options.DisableBlockIfQueueFull { + // block if queue full + <-bc + } +} + +func (p *partitionProducer) ReceivedSendReceipt(response *pb.CommandSendReceipt) { + pi, ok := p.pendingQueue.Peek().(*pendingItem) + + if !ok { + // if we receive a receipt although the pending queue is empty, the state of the broker and the producer differs. + p.log.Warnf("Got ack %v for timed out msg", response.GetMessageId()) + return + } + + if pi.sequenceID < response.GetSequenceId() { + // Force connection closing so that messages can be re-transmitted in a new connection + p.log.Warnf("Received ack for %v on sequenceId %v - expected: %v, closing connection", response.GetMessageId(), + response.GetSequenceId(), pi.sequenceID) + p._getConn().Close() + return + } else if pi.sequenceID > response.GetSequenceId() { + // Ignoring the ack since it's referring to a message that has already timed out. + p.log.Warnf("Received ack for %v on sequenceId %v - expected: %v, closing connection", response.GetMessageId(), + response.GetSequenceId(), pi.sequenceID) + return + } else { + // The ack was indeed for the expected item in the queue, we can remove it and trigger the callback + p.pendingQueue.Poll() + + now := time.Now().UnixNano() + + // lock the pending item while sending the requests + pi.Lock() + defer pi.Unlock() + p.metrics.PublishRPCLatency.Observe(float64(now-pi.sentAt.UnixNano()) / 1.0e9) + batchSize := int32(0) + for _, i := range pi.sendRequests { + sr := i.(*sendRequest) + if sr.msg != nil { + batchSize = batchSize + 1 + } else { // Flush request + break + } + } + for idx, i := range pi.sendRequests { + sr := i.(*sendRequest) + if sr.msg != nil { + atomic.StoreInt64(&p.lastSequenceID, int64(pi.sequenceID)) + p.releaseSemaphoreAndMem(int64(len(sr.msg.Payload))) + p.metrics.PublishLatency.Observe(float64(now-sr.publishTime.UnixNano()) / 1.0e9) + p.metrics.MessagesPublished.Inc() + p.metrics.MessagesPending.Dec() + payloadSize := float64(len(sr.msg.Payload)) + p.metrics.BytesPublished.Add(payloadSize) + p.metrics.BytesPending.Sub(payloadSize) + } + + if sr.callback != nil || len(p.options.Interceptors) > 0 { + msgID := newMessageID( + int64(response.MessageId.GetLedgerId()), + int64(response.MessageId.GetEntryId()), + int32(idx), + p.partitionIdx, + batchSize, + ) + + if sr.totalChunks > 1 { + if sr.chunkID == 0 { + sr.chunkRecorder.setFirstChunkID( + &messageID{ + int64(response.MessageId.GetLedgerId()), + int64(response.MessageId.GetEntryId()), + -1, + p.partitionIdx, + 0, + }) + } else if sr.chunkID == sr.totalChunks-1 { + sr.chunkRecorder.setLastChunkID( + &messageID{ + int64(response.MessageId.GetLedgerId()), + int64(response.MessageId.GetEntryId()), + -1, + p.partitionIdx, + 0, + }) + // use chunkMsgID to set msgID + msgID = &sr.chunkRecorder.chunkedMsgID + } + } + + if sr.totalChunks <= 1 || sr.chunkID == sr.totalChunks-1 { + if sr.callback != nil { + sr.callback(msgID, sr.msg, nil) + } + p.options.Interceptors.OnSendAcknowledgement(p, sr.msg, msgID) + } + } + } + + // Mark this pending item as done + pi.Complete() + } +} + +func (p *partitionProducer) internalClose(req *closeProducer) { + defer close(req.doneCh) + if !p.casProducerState(producerReady, producerClosing) { + return + } + + p.log.Info("Closing producer") + + id := p.client.rpcClient.NewRequestID() + _, err := p.client.rpcClient.RequestOnCnx(p._getConn(), id, pb.BaseCommand_CLOSE_PRODUCER, &pb.CommandCloseProducer{ + ProducerId: &p.producerID, + RequestId: &id, + }) + + if err != nil { + p.log.WithError(err).Warn("Failed to close producer") + } else { + p.log.Info("Closed producer") + } + + if p.batchBuilder != nil { + if err = p.batchBuilder.Close(); err != nil { + p.log.WithError(err).Warn("Failed to close batch builder") + } + } + + p.setProducerState(producerClosed) + p._getConn().UnregisterListener(p.producerID) + p.batchFlushTicker.Stop() + + close(p.closeCh) +} + +func (p *partitionProducer) LastSequenceID() int64 { + return atomic.LoadInt64(&p.lastSequenceID) +} + +func (p *partitionProducer) Flush() error { + flushReq := &flushRequest{ + doneCh: make(chan struct{}), + err: nil, + } + p.eventsChan <- flushReq + + // wait for the flush request to complete + <-flushReq.doneCh + return flushReq.err +} + +func (p *partitionProducer) getProducerState() producerState { + return producerState(p.state.Load()) +} + +func (p *partitionProducer) setProducerState(state producerState) { + p.state.Swap(int32(state)) +} + +// set a new consumerState and return the last state +// returns bool if the new state has been set or not +func (p *partitionProducer) casProducerState(oldState, newState producerState) bool { + return p.state.CAS(int32(oldState), int32(newState)) +} + +func (p *partitionProducer) Close() { + if p.getProducerState() != producerReady { + // Producer is closing + return + } + + cp := &closeProducer{doneCh: make(chan struct{})} + p.eventsChan <- cp + + // wait for close producer request to complete + <-cp.doneCh +} + +type sendRequest struct { + ctx context.Context + msg *ProducerMessage + callback func(MessageID, *ProducerMessage, error) + callbackOnce *sync.Once + publishTime time.Time + flushImmediately bool + blockCh chan struct{} + closeBlockChOnce *sync.Once + totalChunks int + chunkID int + uuid string + chunkRecorder *chunkRecorder +} + +// stopBlock can be invoked multiple times safety +func (sr *sendRequest) stopBlock() { + sr.closeBlockChOnce.Do(func() { + close(sr.blockCh) + }) +} + +type closeProducer struct { + doneCh chan struct{} +} + +type flushRequest struct { + doneCh chan struct{} + err error +} + +func (i *pendingItem) Complete() { + if i.completed { + return + } + i.completed = true + buffersPool.Put(i.buffer) +} + +// _setConn sets the internal connection field of this partition producer atomically. +// Note: should only be called by this partition producer when a new connection is available. +func (p *partitionProducer) _setConn(conn internal.Connection) { + p.conn.Store(conn) +} + +// _getConn returns internal connection field of this partition producer atomically. +// Note: should only be called by this partition producer before attempting to use the connection +func (p *partitionProducer) _getConn() internal.Connection { + // Invariant: The conn must be non-nill for the lifetime of the partitionProducer. + // For this reason we leave this cast unchecked and panic() if the + // invariant is broken + return p.conn.Load().(internal.Connection) +} + +func (p *partitionProducer) releaseSemaphoreAndMem(size int64) { + p.publishSemaphore.Release() + p.client.memLimit.ReleaseMemory(size) +} + +func (p *partitionProducer) canAddToQueue(sr *sendRequest, uncompressedPayloadSize int64) bool { + if p.options.DisableBlockIfQueueFull { + if !p.publishSemaphore.TryAcquire() { + if sr.callback != nil { + sr.callback(nil, sr.msg, errSendQueueIsFull) + } + return false + } + if !p.client.memLimit.TryReserveMemory(uncompressedPayloadSize) { + p.publishSemaphore.Release() + if sr.callback != nil { + sr.callback(nil, sr.msg, errMemoryBufferIsFull) + } + return false + } + + } else { + if !p.publishSemaphore.Acquire(sr.ctx) { + sr.callback(nil, sr.msg, errContextExpired) + return false + } + if !p.client.memLimit.ReserveMemory(sr.ctx, uncompressedPayloadSize) { + p.publishSemaphore.Release() + sr.callback(nil, sr.msg, errContextExpired) + return false + } + } + p.metrics.MessagesPending.Inc() + p.metrics.BytesPending.Add(float64(len(sr.msg.Payload))) + return true +} + +type chunkRecorder struct { + chunkedMsgID chunkMessageID +} + +func newChunkRecorder() *chunkRecorder { + return &chunkRecorder{ + chunkedMsgID: chunkMessageID{}, + } +} + +func (c *chunkRecorder) setFirstChunkID(msgID *messageID) { + c.chunkedMsgID.firstChunkID = msgID +} + +func (c *chunkRecorder) setLastChunkID(msgID *messageID) { + c.chunkedMsgID.messageID = msgID +} + +func toProtoProducerAccessMode(accessMode ProducerAccessMode) pb.ProducerAccessMode { + switch accessMode { + case ProducerAccessModeShared: + return pb.ProducerAccessMode_Shared + case ProducerAccessModeExclusive: + return pb.ProducerAccessMode_Exclusive + case ProducerAccessModeWaitForExclusive: + return pb.ProducerAccessMode_WaitForExclusive + } + + return pb.ProducerAccessMode_Shared +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/reader.go b/vendor/github.com/apache/pulsar-client-go/pulsar/reader.go new file mode 100644 index 00000000..d58d06f6 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/reader.go @@ -0,0 +1,137 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" + "time" + + "github.com/apache/pulsar-client-go/pulsar/internal" +) + +// ReaderMessage packages Reader and Message as a struct to use. +type ReaderMessage struct { + Reader + Message +} + +// ReaderOptions represents Reader options to use. +type ReaderOptions struct { + // Topic specifies the topic this consumer will subscribe on. + // This argument is required when constructing the reader. + Topic string + + // Name set the reader name. + Name string + + // Properties represents a set of application defined properties for the reader. + // Those properties will be visible in the topic stats. + Properties map[string]string + + // StartMessageID initial reader positioning is done by specifying a message id. The options are: + // * `pulsar.EarliestMessage` : Start reading from the earliest message available in the topic + // * `pulsar.LatestMessage` : Start reading from the end topic, only getting messages published after the + // reader was created + // * `MessageID` : Start reading from a particular message id, the reader will position itself on that + // specific position. The first message to be read will be the message next to the specified + // messageID + StartMessageID MessageID + + // StartMessageIDInclusive, if true, the reader will start at the `StartMessageID`, included. + // Default is `false` and the reader will start from the "next" message + StartMessageIDInclusive bool + + // MessageChannel sets a `MessageChannel` for the consumer + // When a message is received, it will be pushed to the channel for consumption + MessageChannel chan ReaderMessage + + // ReceiverQueueSize sets the size of the consumer receive queue. + // The consumer receive queue controls how many messages can be accumulated by the Reader before the + // application calls Reader.readNext(). Using a higher value could potentially increase the consumer + // throughput at the expense of bigger memory utilization. + // Default value is {@code 1000} messages and should be good for most use cases. + ReceiverQueueSize int + + // SubscriptionRolePrefix sets the subscription role prefix. The default prefix is "reader". + SubscriptionRolePrefix string + + // SubscriptionName sets the subscription name. + // If subscriptionRolePrefix is set at the same time, this configuration will prevail + SubscriptionName string + + // ReadCompacted, if enabled, the reader will read messages from the compacted topic rather than reading the + // full message backlog of the topic. This means that, if the topic has been compacted, the reader will only + // see the latest value for each key in the topic, up until the point in the topic message backlog that has + // been compacted. Beyond that point, the messages will be sent as normal. + // + // ReadCompacted can only be enabled when reading from a persistent topic. Attempting to enable it on non-persistent + // topics will lead to the reader create call throwing a PulsarClientException. + ReadCompacted bool + + // Decryption represents the encryption related fields required by the reader to decrypt a message. + Decryption *MessageDecryptionInfo + + // Schema represents the schema implementation. + Schema Schema + + // BackoffPolicy parameterize the following options in the reconnection logic to + // allow users to customize the reconnection logic (minBackoff, maxBackoff and jitterPercentage) + BackoffPolicy internal.BackoffPolicy + + // MaxPendingChunkedMessage sets the maximum pending chunked messages. (default: 100) + MaxPendingChunkedMessage int + + // ExpireTimeOfIncompleteChunk sets the expiry time of discarding incomplete chunked message. (default: 60 seconds) + ExpireTimeOfIncompleteChunk time.Duration + + // AutoAckIncompleteChunk sets whether reader auto acknowledges incomplete chunked message when it should + // be removed (e.g.the chunked message pending queue is full). (default: false) + AutoAckIncompleteChunk bool +} + +// Reader can be used to scan through all the messages currently available in a topic. +type Reader interface { + // Topic from which this reader is reading from + Topic() string + + // Next reads the next message in the topic, blocking until a message is available + Next(context.Context) (Message, error) + + // HasNext checks if there is any message available to read from the current position + HasNext() bool + + // Close the reader and stop the broker to push more messages + Close() + + // Seek resets the subscription associated with this reader to a specific message id. + // The message id can either be a specific message or represent the first or last messages in the topic. + // + // Note: this operation can only be done on non-partitioned topics. For these, one can rather perform the + // seek() on the individual partitions. + Seek(MessageID) error + + // SeekByTime resets the subscription associated with this reader to a specific message publish time. + // + // Note: this operation can only be done on non-partitioned topics. For these, one can rather perform the seek() on + // the individual partitions. + // + // @param timestamp + // the message publish time where to reposition the subscription + // + SeekByTime(time time.Time) error +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/reader_impl.go b/vendor/github.com/apache/pulsar-client-go/pulsar/reader_impl.go new file mode 100644 index 00000000..36b492ab --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/reader_impl.go @@ -0,0 +1,246 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/apache/pulsar-client-go/pulsar/crypto" + "github.com/apache/pulsar-client-go/pulsar/internal" + "github.com/apache/pulsar-client-go/pulsar/log" +) + +const ( + defaultReceiverQueueSize = 1000 +) + +type reader struct { + sync.Mutex + client *client + pc *partitionConsumer + messageCh chan ConsumerMessage + lastMessageInBroker *trackingMessageID + log log.Logger + metrics *internal.LeveledMetrics +} + +func newReader(client *client, options ReaderOptions) (Reader, error) { + if options.Topic == "" { + return nil, newError(InvalidConfiguration, "Topic is required") + } + + if options.StartMessageID == nil { + return nil, newError(InvalidConfiguration, "StartMessageID is required") + } + + var startMessageID *trackingMessageID + if !checkMessageIDType(options.StartMessageID) { + // a custom type satisfying MessageID may not be a messageID or trackingMessageID + // so re-create messageID using its data + deserMsgID, err := deserializeMessageID(options.StartMessageID.Serialize()) + if err != nil { + return nil, err + } + // de-serialized MessageID is a messageID + startMessageID = toTrackingMessageID(deserMsgID) + } else { + startMessageID = toTrackingMessageID(options.StartMessageID) + } + + subscriptionName := options.SubscriptionName + if subscriptionName == "" { + subscriptionName = options.SubscriptionRolePrefix + if subscriptionName == "" { + subscriptionName = "reader" + } + subscriptionName += "-" + generateRandomName() + } + + receiverQueueSize := options.ReceiverQueueSize + if receiverQueueSize <= 0 { + receiverQueueSize = defaultReceiverQueueSize + } + + // decryption is enabled, use default message crypto if not provided + if options.Decryption != nil && options.Decryption.MessageCrypto == nil { + messageCrypto, err := crypto.NewDefaultMessageCrypto("decrypt", + false, + client.log.SubLogger(log.Fields{"topic": options.Topic})) + if err != nil { + return nil, err + } + options.Decryption.MessageCrypto = messageCrypto + } + + if options.MaxPendingChunkedMessage == 0 { + options.MaxPendingChunkedMessage = 100 + } + + if options.ExpireTimeOfIncompleteChunk == 0 { + options.ExpireTimeOfIncompleteChunk = time.Minute + } + + consumerOptions := &partitionConsumerOpts{ + topic: options.Topic, + consumerName: options.Name, + subscription: subscriptionName, + subscriptionType: Exclusive, + receiverQueueSize: receiverQueueSize, + startMessageID: startMessageID, + startMessageIDInclusive: options.StartMessageIDInclusive, + subscriptionMode: nonDurable, + readCompacted: options.ReadCompacted, + metadata: options.Properties, + nackRedeliveryDelay: defaultNackRedeliveryDelay, + replicateSubscriptionState: false, + decryption: options.Decryption, + schema: options.Schema, + backoffPolicy: options.BackoffPolicy, + maxPendingChunkedMessage: options.MaxPendingChunkedMessage, + expireTimeOfIncompleteChunk: options.ExpireTimeOfIncompleteChunk, + autoAckIncompleteChunk: options.AutoAckIncompleteChunk, + } + + reader := &reader{ + client: client, + messageCh: make(chan ConsumerMessage), + log: client.log.SubLogger(log.Fields{"topic": options.Topic}), + metrics: client.metrics.GetLeveledMetrics(options.Topic), + } + + // Provide dummy dlq router with not dlq policy + dlq, err := newDlqRouter(client, nil, client.log) + if err != nil { + return nil, err + } + + pc, err := newPartitionConsumer(nil, client, consumerOptions, reader.messageCh, dlq, reader.metrics) + if err != nil { + close(reader.messageCh) + return nil, err + } + + reader.pc = pc + reader.metrics.ReadersOpened.Inc() + return reader, nil +} + +func (r *reader) Topic() string { + return r.pc.topic +} + +func (r *reader) Next(ctx context.Context) (Message, error) { + for { + select { + case cm, ok := <-r.messageCh: + if !ok { + return nil, newError(ConsumerClosed, "consumer closed") + } + + // Acknowledge message immediately because the reader is based on non-durable subscription. When it reconnects, + // it will specify the subscription position anyway + msgID := cm.Message.ID() + mid := toTrackingMessageID(msgID) + r.pc.lastDequeuedMsg = mid + r.pc.AckID(mid) + return cm.Message, nil + case <-ctx.Done(): + return nil, ctx.Err() + } + } +} + +func (r *reader) HasNext() bool { + if r.lastMessageInBroker != nil && r.hasMoreMessages() { + return true + } + + for { + lastMsgID, err := r.pc.getLastMessageID() + if err != nil { + r.log.WithError(err).Error("Failed to get last message id from broker") + continue + } else { + r.lastMessageInBroker = lastMsgID + break + } + } + + return r.hasMoreMessages() +} + +func (r *reader) hasMoreMessages() bool { + if r.pc.lastDequeuedMsg != nil { + return r.lastMessageInBroker.isEntryIDValid() && r.lastMessageInBroker.greater(r.pc.lastDequeuedMsg.messageID) + } + + if r.pc.options.startMessageIDInclusive { + return r.lastMessageInBroker.isEntryIDValid() && + r.lastMessageInBroker.greaterEqual(r.pc.startMessageID.get().messageID) + } + + // Non-inclusive + return r.lastMessageInBroker.isEntryIDValid() && + r.lastMessageInBroker.greater(r.pc.startMessageID.get().messageID) +} + +func (r *reader) Close() { + r.pc.Close() + r.client.handlers.Del(r) + r.metrics.ReadersClosed.Inc() +} + +func (r *reader) messageID(msgID MessageID) *trackingMessageID { + mid := toTrackingMessageID(msgID) + + partition := int(mid.partitionIdx) + // did we receive a valid partition index? + if partition < 0 { + r.log.Warnf("invalid partition index %d expected", partition) + return nil + } + + return mid +} + +func (r *reader) Seek(msgID MessageID) error { + r.Lock() + defer r.Unlock() + + if !checkMessageIDType(msgID) { + r.log.Warnf("invalid message id type %T", msgID) + return fmt.Errorf("invalid message id type %T", msgID) + } + + mid := r.messageID(msgID) + if mid == nil { + return nil + } + + return r.pc.Seek(mid) +} + +func (r *reader) SeekByTime(time time.Time) error { + r.Lock() + defer r.Unlock() + + return r.pc.SeekByTime(time) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/retry_router.go b/vendor/github.com/apache/pulsar-client-go/pulsar/retry_router.go new file mode 100644 index 00000000..75792adc --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/retry_router.go @@ -0,0 +1,148 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" + "time" + + "github.com/apache/pulsar-client-go/pulsar/internal" + "github.com/apache/pulsar-client-go/pulsar/log" +) + +const ( + DlqTopicSuffix = "-DLQ" + RetryTopicSuffix = "-RETRY" + MaxReconsumeTimes = 16 + + SysPropertyDelayTime = "DELAY_TIME" + SysPropertyRealTopic = "REAL_TOPIC" + SysPropertyRetryTopic = "RETRY_TOPIC" + SysPropertyReconsumeTimes = "RECONSUMETIMES" + SysPropertyOriginMessageID = "ORIGIN_MESSAGE_IDY_TIME" + PropertyOriginMessageID = "ORIGIN_MESSAGE_ID" +) + +type RetryMessage struct { + producerMsg ProducerMessage + consumerMsg ConsumerMessage +} + +type retryRouter struct { + client Client + producer Producer + policy *DLQPolicy + messageCh chan RetryMessage + closeCh chan interface{} + log log.Logger +} + +func newRetryRouter(client Client, policy *DLQPolicy, retryEnabled bool, logger log.Logger) (*retryRouter, error) { + r := &retryRouter{ + client: client, + policy: policy, + log: logger, + } + + if policy != nil && retryEnabled { + if policy.MaxDeliveries <= 0 { + return nil, newError(InvalidConfiguration, "DLQPolicy.MaxDeliveries needs to be > 0") + } + + if policy.RetryLetterTopic == "" { + return nil, newError(InvalidConfiguration, "DLQPolicy.RetryLetterTopic needs to be set to a valid topic name") + } + + r.messageCh = make(chan RetryMessage) + r.closeCh = make(chan interface{}, 1) + r.log = logger.SubLogger(log.Fields{"rlq-topic": policy.RetryLetterTopic}) + go r.run() + } + return r, nil +} + +func (r *retryRouter) Chan() chan RetryMessage { + return r.messageCh +} + +func (r *retryRouter) run() { + for { + select { + case rm := <-r.messageCh: + r.log.WithField("msgID", rm.consumerMsg.ID()).Debug("Got message for RLQ") + producer := r.getProducer() + + msgID := rm.consumerMsg.ID() + producer.SendAsync(context.Background(), &rm.producerMsg, func(messageID MessageID, + producerMessage *ProducerMessage, err error) { + if err != nil { + r.log.WithError(err).WithField("msgID", msgID).Error("Failed to send message to RLQ") + rm.consumerMsg.Consumer.Nack(rm.consumerMsg) + } else { + r.log.WithField("msgID", msgID).Debug("Succeed to send message to RLQ") + rm.consumerMsg.Consumer.AckID(msgID) + } + }) + + case <-r.closeCh: + if r.producer != nil { + r.producer.Close() + } + r.log.Debug("Closed RLQ router") + return + } + } +} + +func (r *retryRouter) close() { + // Attempt to write on the close channel, without blocking + select { + case r.closeCh <- nil: + default: + } +} + +func (r *retryRouter) getProducer() Producer { + if r.producer != nil { + // Producer was already initialized + return r.producer + } + + // Retry to create producer indefinitely + backoff := &internal.DefaultBackoff{} + for { + opt := r.policy.ProducerOptions + opt.Topic = r.policy.RetryLetterTopic + // the origin code sets to LZ4 compression with no options + // so the new design allows compression type to be overwritten but still set lz4 by default + if r.policy.ProducerOptions.CompressionType == NoCompression { + opt.CompressionType = LZ4 + } + + producer, err := r.client.CreateProducer(opt) + + if err != nil { + r.log.WithError(err).Error("Failed to create RLQ producer") + time.Sleep(backoff.Next()) + continue + } else { + r.producer = producer + return producer + } + } +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/schema.go b/vendor/github.com/apache/pulsar-client-go/pulsar/schema.go new file mode 100644 index 00000000..997d85fb --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/schema.go @@ -0,0 +1,570 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "reflect" + "unsafe" + + log "github.com/sirupsen/logrus" + + "github.com/linkedin/goavro/v2" + "google.golang.org/protobuf/proto" +) + +type SchemaType int + +const ( + NONE SchemaType = iota //No schema defined + STRING //Simple String encoding with UTF-8 + JSON //JSON object encoding and validation + PROTOBUF //Protobuf message encoding and decoding + AVRO //Serialize and deserialize via Avro + BOOLEAN // + INT8 //A 8-byte integer. + INT16 //A 16-byte integer. + INT32 //A 32-byte integer. + INT64 //A 64-byte integer. + FLOAT //A float number. + DOUBLE //A double number + _ // + _ // + _ // + KeyValue //A Schema that contains Key Schema and Value Schema. + BYTES = -1 //A bytes array. + AUTO = -2 // + AutoConsume = -3 //Auto Consume Type. + AutoPublish = -4 // Auto Publish Type. +) + +// Encapsulates data around the schema definition +type SchemaInfo struct { + Name string + Schema string + Type SchemaType + Properties map[string]string +} + +func (s SchemaInfo) hash() string { + h := sha256.New() + h.Write([]byte(s.Schema)) + return hex.EncodeToString(h.Sum(nil)) +} + +type Schema interface { + Encode(v interface{}) ([]byte, error) + Decode(data []byte, v interface{}) error + Validate(message []byte) error + GetSchemaInfo() *SchemaInfo +} + +func NewSchema(schemaType SchemaType, schemaData []byte, properties map[string]string) (schema Schema, err error) { + var schemaDef = string(schemaData) + var s Schema + switch schemaType { + case STRING: + s = NewStringSchema(properties) + case JSON: + s = NewJSONSchema(schemaDef, properties) + case PROTOBUF: + s = NewProtoSchema(schemaDef, properties) + case AVRO: + s = NewAvroSchema(schemaDef, properties) + case INT8: + s = NewInt8Schema(properties) + case INT16: + s = NewInt16Schema(properties) + case INT32: + s = NewInt32Schema(properties) + case INT64: + s = NewInt64Schema(properties) + case FLOAT: + s = NewFloatSchema(properties) + case DOUBLE: + s = NewDoubleSchema(properties) + default: + err = fmt.Errorf("not support schema type of %v", schemaType) + } + schema = s + return +} + +type AvroCodec struct { + Codec *goavro.Codec +} + +func NewSchemaDefinition(schema *goavro.Codec) *AvroCodec { + schemaDef := &AvroCodec{ + Codec: schema, + } + return schemaDef +} + +// initAvroCodec returns a Codec used to translate between a byte slice of either +// binary or textual Avro data and native Go data. +func initAvroCodec(codec string) (*goavro.Codec, error) { + return goavro.NewCodec(codec) +} + +type JSONSchema struct { + AvroCodec + SchemaInfo +} + +// NewJSONSchema creates a new JSONSchema +// Note: the function will panic if creation of codec fails +func NewJSONSchema(jsonAvroSchemaDef string, properties map[string]string) *JSONSchema { + js, err := NewJSONSchemaWithValidation(jsonAvroSchemaDef, properties) + if err != nil { + log.Fatalf("JSONSchema init codec error:%v", err) + } + return js +} + +// NewJSONSchemaWithValidation creates a new JSONSchema and error to indicate codec failure +func NewJSONSchemaWithValidation(jsonAvroSchemaDef string, properties map[string]string) (*JSONSchema, error) { + js := new(JSONSchema) + avroCodec, err := initAvroCodec(jsonAvroSchemaDef) + if err != nil { + return nil, err + } + schemaDef := NewSchemaDefinition(avroCodec) + js.SchemaInfo.Schema = schemaDef.Codec.Schema() + js.SchemaInfo.Type = JSON + js.SchemaInfo.Properties = properties + js.SchemaInfo.Name = "JSON" + return js, nil +} + +func (js *JSONSchema) Encode(data interface{}) ([]byte, error) { + return json.Marshal(data) +} + +func (js *JSONSchema) Decode(data []byte, v interface{}) error { + return json.Unmarshal(data, v) +} + +func (js *JSONSchema) Validate(message []byte) error { + return js.Decode(message, nil) +} + +func (js *JSONSchema) GetSchemaInfo() *SchemaInfo { + return &js.SchemaInfo +} + +type ProtoSchema struct { + AvroCodec + SchemaInfo +} + +// NewProtoSchema creates a new ProtoSchema +// Note: the function will panic if creation of codec fails +func NewProtoSchema(protoAvroSchemaDef string, properties map[string]string) *ProtoSchema { + ps, err := NewProtoSchemaWithValidation(protoAvroSchemaDef, properties) + if err != nil { + log.Fatalf("ProtoSchema init codec error:%v", err) + } + return ps +} + +// NewProtoSchemaWithValidation creates a new ProtoSchema and error to indicate codec failure +func NewProtoSchemaWithValidation(protoAvroSchemaDef string, properties map[string]string) (*ProtoSchema, error) { + ps := new(ProtoSchema) + avroCodec, err := initAvroCodec(protoAvroSchemaDef) + if err != nil { + return nil, err + } + schemaDef := NewSchemaDefinition(avroCodec) + ps.AvroCodec.Codec = schemaDef.Codec + ps.SchemaInfo.Schema = schemaDef.Codec.Schema() + ps.SchemaInfo.Type = PROTOBUF + ps.SchemaInfo.Properties = properties + ps.SchemaInfo.Name = "Proto" + return ps, nil +} + +func (ps *ProtoSchema) Encode(data interface{}) ([]byte, error) { + return proto.Marshal(data.(proto.Message)) +} + +func (ps *ProtoSchema) Decode(data []byte, v interface{}) error { + return proto.Unmarshal(data, v.(proto.Message)) +} + +func (ps *ProtoSchema) Validate(message []byte) error { + return ps.Decode(message, nil) +} + +func (ps *ProtoSchema) GetSchemaInfo() *SchemaInfo { + return &ps.SchemaInfo +} + +type AvroSchema struct { + AvroCodec + SchemaInfo +} + +// NewAvroSchema creates a new AvroSchema +// Note: the function will panic if creation of codec fails +func NewAvroSchema(avroSchemaDef string, properties map[string]string) *AvroSchema { + ps, err := NewAvroSchemaWithValidation(avroSchemaDef, properties) + if err != nil { + log.Fatalf("AvroSchema init codec error:%v", err) + } + return ps +} + +// NewAvroSchemaWithValidation creates a new AvroSchema and error to indicate codec failure +func NewAvroSchemaWithValidation(avroSchemaDef string, properties map[string]string) (*AvroSchema, error) { + as := new(AvroSchema) + avroCodec, err := initAvroCodec(avroSchemaDef) + if err != nil { + return nil, err + } + schemaDef := NewSchemaDefinition(avroCodec) + as.AvroCodec.Codec = schemaDef.Codec + as.SchemaInfo.Schema = schemaDef.Codec.Schema() + as.SchemaInfo.Type = AVRO + as.SchemaInfo.Name = "Avro" + as.SchemaInfo.Properties = properties + return as, nil +} + +func (as *AvroSchema) Encode(data interface{}) ([]byte, error) { + textual, err := json.Marshal(data) + if err != nil { + log.Errorf("serialize data error:%s", err.Error()) + return nil, err + } + native, _, err := as.Codec.NativeFromTextual(textual) + if err != nil { + log.Errorf("convert native Go form to binary Avro data error:%s", err.Error()) + return nil, err + } + return as.Codec.BinaryFromNative(nil, native) +} + +func (as *AvroSchema) Decode(data []byte, v interface{}) error { + native, _, err := as.Codec.NativeFromBinary(data) + if err != nil { + log.Errorf("convert binary Avro data back to native Go form error:%s", err.Error()) + return err + } + textual, err := as.Codec.TextualFromNative(nil, native) + if err != nil { + log.Errorf("convert native Go form to textual Avro data error:%s", err.Error()) + return err + } + err = json.Unmarshal(textual, v) + if err != nil { + log.Errorf("unSerialize textual error:%s", err.Error()) + return err + } + return nil +} + +func (as *AvroSchema) Validate(message []byte) error { + return as.Decode(message, nil) +} + +func (as *AvroSchema) GetSchemaInfo() *SchemaInfo { + return &as.SchemaInfo +} + +type StringSchema struct { + SchemaInfo +} + +func NewStringSchema(properties map[string]string) *StringSchema { + strSchema := new(StringSchema) + strSchema.SchemaInfo.Properties = properties + strSchema.SchemaInfo.Name = "String" + strSchema.SchemaInfo.Type = STRING + strSchema.SchemaInfo.Schema = "" + return strSchema +} + +func (ss *StringSchema) Encode(v interface{}) ([]byte, error) { + return []byte(v.(string)), nil +} + +// Decode convert from byte slice to string without allocating a new string +func (ss *StringSchema) Decode(data []byte, v interface{}) error { + strPtr := (*string)(unsafe.Pointer(&data)) + reflect.ValueOf(v).Elem().Set(reflect.ValueOf(strPtr)) + return nil +} + +func (ss *StringSchema) Validate(message []byte) error { + return ss.Decode(message, nil) +} + +func (ss *StringSchema) GetSchemaInfo() *SchemaInfo { + return &ss.SchemaInfo +} + +type BytesSchema struct { + SchemaInfo +} + +func NewBytesSchema(properties map[string]string) *BytesSchema { + bytesSchema := new(BytesSchema) + bytesSchema.SchemaInfo.Properties = properties + bytesSchema.SchemaInfo.Name = "Bytes" + bytesSchema.SchemaInfo.Type = BYTES + bytesSchema.SchemaInfo.Schema = "" + return bytesSchema +} + +func (bs *BytesSchema) Encode(data interface{}) ([]byte, error) { + return data.([]byte), nil +} + +func (bs *BytesSchema) Decode(data []byte, v interface{}) error { + reflect.ValueOf(v).Elem().Set(reflect.ValueOf(data)) + return nil +} + +func (bs *BytesSchema) Validate(message []byte) error { + return bs.Decode(message, nil) +} + +func (bs *BytesSchema) GetSchemaInfo() *SchemaInfo { + return &bs.SchemaInfo +} + +type Int8Schema struct { + SchemaInfo +} + +func NewInt8Schema(properties map[string]string) *Int8Schema { + int8Schema := new(Int8Schema) + int8Schema.SchemaInfo.Properties = properties + int8Schema.SchemaInfo.Schema = "" + int8Schema.SchemaInfo.Type = INT8 + int8Schema.SchemaInfo.Name = "INT8" + return int8Schema +} + +func (is8 *Int8Schema) Encode(value interface{}) ([]byte, error) { + var buf bytes.Buffer + err := WriteElements(&buf, value.(int8)) + return buf.Bytes(), err +} + +func (is8 *Int8Schema) Decode(data []byte, v interface{}) error { + buf := bytes.NewReader(data) + return ReadElements(buf, v) +} + +func (is8 *Int8Schema) Validate(message []byte) error { + if len(message) != 1 { + return newError(InvalidMessage, "size of data received by Int8Schema is not 1") + } + return nil +} + +func (is8 *Int8Schema) GetSchemaInfo() *SchemaInfo { + return &is8.SchemaInfo +} + +type Int16Schema struct { + SchemaInfo +} + +func NewInt16Schema(properties map[string]string) *Int16Schema { + int16Schema := new(Int16Schema) + int16Schema.SchemaInfo.Properties = properties + int16Schema.SchemaInfo.Name = "INT16" + int16Schema.SchemaInfo.Type = INT16 + int16Schema.SchemaInfo.Schema = "" + return int16Schema +} + +func (is16 *Int16Schema) Encode(value interface{}) ([]byte, error) { + var buf bytes.Buffer + err := WriteElements(&buf, value.(int16)) + return buf.Bytes(), err +} + +func (is16 *Int16Schema) Decode(data []byte, v interface{}) error { + buf := bytes.NewReader(data) + return ReadElements(buf, v) +} + +func (is16 *Int16Schema) Validate(message []byte) error { + if len(message) != 2 { + return newError(InvalidMessage, "size of data received by Int16Schema is not 2") + } + return nil +} + +func (is16 *Int16Schema) GetSchemaInfo() *SchemaInfo { + return &is16.SchemaInfo +} + +type Int32Schema struct { + SchemaInfo +} + +func NewInt32Schema(properties map[string]string) *Int32Schema { + int32Schema := new(Int32Schema) + int32Schema.SchemaInfo.Properties = properties + int32Schema.SchemaInfo.Schema = "" + int32Schema.SchemaInfo.Name = "INT32" + int32Schema.SchemaInfo.Type = INT32 + return int32Schema +} + +func (is32 *Int32Schema) Encode(value interface{}) ([]byte, error) { + var buf bytes.Buffer + err := WriteElements(&buf, value.(int32)) + return buf.Bytes(), err +} + +func (is32 *Int32Schema) Decode(data []byte, v interface{}) error { + buf := bytes.NewReader(data) + return ReadElements(buf, v) +} + +func (is32 *Int32Schema) Validate(message []byte) error { + if len(message) != 4 { + return newError(InvalidMessage, "size of data received by Int32Schema is not 4") + } + return nil +} + +func (is32 *Int32Schema) GetSchemaInfo() *SchemaInfo { + return &is32.SchemaInfo +} + +type Int64Schema struct { + SchemaInfo +} + +func NewInt64Schema(properties map[string]string) *Int64Schema { + int64Schema := new(Int64Schema) + int64Schema.SchemaInfo.Properties = properties + int64Schema.SchemaInfo.Name = "INT64" + int64Schema.SchemaInfo.Type = INT64 + int64Schema.SchemaInfo.Schema = "" + return int64Schema +} + +func (is64 *Int64Schema) Encode(value interface{}) ([]byte, error) { + var buf bytes.Buffer + err := WriteElements(&buf, value.(int64)) + return buf.Bytes(), err +} + +func (is64 *Int64Schema) Decode(data []byte, v interface{}) error { + buf := bytes.NewReader(data) + return ReadElements(buf, v) +} + +func (is64 *Int64Schema) Validate(message []byte) error { + if len(message) != 8 { + return newError(InvalidMessage, "size of data received by Int64Schema is not 8") + } + return nil +} + +func (is64 *Int64Schema) GetSchemaInfo() *SchemaInfo { + return &is64.SchemaInfo +} + +type FloatSchema struct { + SchemaInfo +} + +func NewFloatSchema(properties map[string]string) *FloatSchema { + floatSchema := new(FloatSchema) + floatSchema.SchemaInfo.Properties = properties + floatSchema.SchemaInfo.Type = FLOAT + floatSchema.SchemaInfo.Name = "FLOAT" + floatSchema.SchemaInfo.Schema = "" + return floatSchema +} + +func (fs *FloatSchema) Encode(value interface{}) ([]byte, error) { + return BinarySerializer.PutFloat(value) +} + +func (fs *FloatSchema) Decode(data []byte, v interface{}) error { + floatValue, err := BinarySerializer.Float32(data) + if err != nil { + log.Errorf("unSerialize float error:%s", err.Error()) + return err + } + reflect.ValueOf(v).Elem().Set(reflect.ValueOf(floatValue)) + return nil +} + +func (fs *FloatSchema) Validate(message []byte) error { + if len(message) != 4 { + return newError(InvalidMessage, "size of data received by FloatSchema is not 4") + } + return nil +} + +func (fs *FloatSchema) GetSchemaInfo() *SchemaInfo { + return &fs.SchemaInfo +} + +type DoubleSchema struct { + SchemaInfo +} + +func NewDoubleSchema(properties map[string]string) *DoubleSchema { + doubleSchema := new(DoubleSchema) + doubleSchema.SchemaInfo.Properties = properties + doubleSchema.SchemaInfo.Type = DOUBLE + doubleSchema.SchemaInfo.Name = "DOUBLE" + doubleSchema.SchemaInfo.Schema = "" + return doubleSchema +} + +func (ds *DoubleSchema) Encode(value interface{}) ([]byte, error) { + return BinarySerializer.PutDouble(value) +} + +func (ds *DoubleSchema) Decode(data []byte, v interface{}) error { + doubleValue, err := BinarySerializer.Float64(data) + if err != nil { + log.Errorf("unSerialize double value error:%s", err.Error()) + return err + } + reflect.ValueOf(v).Elem().Set(reflect.ValueOf(doubleValue)) + return nil +} + +func (ds *DoubleSchema) Validate(message []byte) error { + if len(message) != 8 { + return newError(InvalidMessage, "size of data received by DoubleSchema is not 8") + } + return nil +} + +func (ds *DoubleSchema) GetSchemaInfo() *SchemaInfo { + return &ds.SchemaInfo +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/table_view.go b/vendor/github.com/apache/pulsar-client-go/pulsar/table_view.go new file mode 100644 index 00000000..e566bf0b --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/table_view.go @@ -0,0 +1,78 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "reflect" + "time" + + "github.com/apache/pulsar-client-go/pulsar/log" +) + +// TableViewOptions contains the options for creating a TableView +type TableViewOptions struct { + // Topic specifies the topic this table view will subscribe on. + // This argument is required when constructing the table view. + Topic string + + // Set the interval of updating partitions. Default to 1 minute. + AutoUpdatePartitionsInterval time.Duration + + // Schema represents the schema implementation. + Schema Schema + + // SchemaValueType represents the type of values for the given schema. + SchemaValueType reflect.Type + + // Configure the logger used by the TableView. + // By default, a wrapped logrus.StandardLogger will be used, namely, + // log.NewLoggerWithLogrus(logrus.StandardLogger()) + Logger log.Logger +} + +// TableView provides a key-value map view of a compacted topic. Messages without keys will be ignored. +type TableView interface { + // Size returns the number of key-value mappings in the TableView. + Size() int + + // IsEmpty returns true if this TableView contains no key-value mappings. + IsEmpty() bool + + // ContainsKey returns true if this TableView contains a mapping for the specified key. + ContainsKey(key string) bool + + // Get returns the value to which the specified key is mapped, or nil if this map contains no mapping for the key. + Get(key string) interface{} + + // Entries returns a map view of the mappings contained in this TableView. + Entries() map[string]interface{} + + // Keys returns a slice of the keys contained in this TableView. + Keys() []string + + // ForEach performs the give action for each entry in this map until all entries have been processed or the action + // returns an error. + ForEach(func(string, interface{}) error) error + + // ForEachAndListen performs the give action for each entry in this map until all entries have been processed or + // the action returns an error. + ForEachAndListen(func(string, interface{}) error) error + + // Close closes the table view and releases resources allocated. + Close() +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/table_view_impl.go b/vendor/github.com/apache/pulsar-client-go/pulsar/table_view_impl.go new file mode 100644 index 00000000..85499f19 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/table_view_impl.go @@ -0,0 +1,277 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" + "errors" + "fmt" + "reflect" + "sync" + "time" + + "github.com/apache/pulsar-client-go/pulsar/log" + "github.com/sirupsen/logrus" +) + +type cancelReader struct { + reader Reader + cancelFunc context.CancelFunc +} + +type TableViewImpl struct { + client *client + options TableViewOptions + + dataMu sync.Mutex + data map[string]interface{} + + readersMu sync.Mutex + cancelRaders map[string]cancelReader + + listenersMu sync.Mutex + listeners []func(string, interface{}) error + + logger log.Logger + closed bool + closedCh chan struct{} +} + +func newTableView(client *client, options TableViewOptions) (TableView, error) { + if options.Topic == "" { + return nil, newError(TopicNotFound, "topic is required") + } + + if options.Schema != nil && options.SchemaValueType == nil { + return nil, newError(InvalidConfiguration, "SchemaValueType is required when Schema is present") + } + + var logger log.Logger + if options.Logger != nil { + logger = options.Logger + } else { + logger = log.NewLoggerWithLogrus(logrus.StandardLogger()) + } + + if options.AutoUpdatePartitionsInterval == 0 { + options.AutoUpdatePartitionsInterval = time.Minute + } + + tv := TableViewImpl{ + client: client, + options: options, + data: make(map[string]interface{}), + cancelRaders: make(map[string]cancelReader), + logger: logger, + closedCh: make(chan struct{}), + } + + // Do an initial round of partition update check to make sure we can populate the partition readers + if err := tv.partitionUpdateCheck(); err != nil { + return nil, err + } + go tv.periodicPartitionUpdateCheck() + + return &tv, nil +} + +func (tv *TableViewImpl) partitionUpdateCheck() error { + partitionsArray, err := tv.client.TopicPartitions(tv.options.Topic) + if err != nil { + return fmt.Errorf("tv.client.TopicPartitions(%s) failed: %w", tv.options.Topic, err) + } + + partitions := make(map[string]bool, len(partitionsArray)) + for _, partition := range partitionsArray { + partitions[partition] = true + } + + tv.readersMu.Lock() + defer tv.readersMu.Unlock() + + for partition, cancelReader := range tv.cancelRaders { + if _, ok := partitions[partition]; !ok { + cancelReader.cancelFunc() + cancelReader.reader.Close() + delete(tv.cancelRaders, partition) + } + } + + for partition := range partitions { + if _, ok := tv.cancelRaders[partition]; !ok { + reader, err := newReader(tv.client, ReaderOptions{ + Topic: partition, + StartMessageID: EarliestMessageID(), + ReadCompacted: true, + // TODO: Pooling? + Schema: tv.options.Schema, + }) + if err != nil { + return fmt.Errorf("create new reader failed for %s: %w", partition, err) + } + for reader.HasNext() { + msg, err := reader.Next(context.Background()) + if err != nil { + tv.logger.Errorf("read next message failed for %s: %w", partition, err) + } + tv.handleMessage(msg) + } + ctx, cancelFunc := context.WithCancel(context.Background()) + tv.cancelRaders[partition] = cancelReader{ + reader: reader, + cancelFunc: cancelFunc, + } + go tv.watchReaderForNewMessages(ctx, reader) + } + } + + return nil +} + +func (tv *TableViewImpl) periodicPartitionUpdateCheck() { + for { + if err := tv.partitionUpdateCheck(); err != nil { + tv.logger.Errorf("failed to check for changes in number of partitions: %w", err) + } + select { + case <-tv.closedCh: + // If the TableViewImpl has been closed, stop checking for partition updates + return + case <-time.After(tv.options.AutoUpdatePartitionsInterval): + continue + } + } +} + +func (tv *TableViewImpl) Size() int { + tv.dataMu.Lock() + defer tv.dataMu.Unlock() + return len(tv.data) +} + +func (tv *TableViewImpl) IsEmpty() bool { + tv.dataMu.Lock() + defer tv.dataMu.Unlock() + return tv.Size() == 0 +} + +func (tv *TableViewImpl) ContainsKey(key string) bool { + tv.dataMu.Lock() + defer tv.dataMu.Unlock() + _, ok := tv.data[key] + return ok +} + +func (tv *TableViewImpl) Get(key string) interface{} { + tv.dataMu.Lock() + defer tv.dataMu.Unlock() + return tv.data[key] +} + +func (tv *TableViewImpl) Entries() map[string]interface{} { + tv.dataMu.Lock() + defer tv.dataMu.Unlock() + data := make(map[string]interface{}, len(tv.data)) + for k, v := range tv.data { + data[k] = v + } + return tv.data +} + +func (tv *TableViewImpl) Keys() []string { + tv.dataMu.Lock() + defer tv.dataMu.Unlock() + keys := make([]string, len(tv.data)) + i := 0 + for k := range tv.data { + keys[i] = k + i++ + } + return keys +} + +func (tv *TableViewImpl) ForEach(action func(string, interface{}) error) error { + tv.dataMu.Lock() + defer tv.dataMu.Unlock() + for k, v := range tv.data { + if err := action(k, v); err != nil { + return err + } + } + return nil +} + +func (tv *TableViewImpl) ForEachAndListen(action func(string, interface{}) error) error { + tv.listenersMu.Lock() + defer tv.listenersMu.Unlock() + + if err := tv.ForEach(action); err != nil { + return err + } + + tv.listeners = append(tv.listeners, action) + return nil +} + +func (tv *TableViewImpl) Close() { + tv.readersMu.Lock() + defer tv.readersMu.Unlock() + + if !tv.closed { + tv.closed = true + for _, cancelReader := range tv.cancelRaders { + cancelReader.reader.Close() + } + close(tv.closedCh) + } +} + +func (tv *TableViewImpl) handleMessage(msg Message) { + tv.dataMu.Lock() + defer tv.dataMu.Unlock() + + var payload interface{} + if len(msg.Payload()) == 0 { + delete(tv.data, msg.Key()) + } else { + payload = reflect.Indirect(reflect.New(tv.options.SchemaValueType)).Interface() + if err := msg.GetSchemaValue(&payload); err != nil { + tv.logger.Errorf("msg.GetSchemaValue() failed with %w; msg is %v", msg, err) + } + tv.data[msg.Key()] = payload + } + + for _, listener := range tv.listeners { + if err := listener(msg.Key(), payload); err != nil { + tv.logger.Errorf("table view listener failed for %v: %w", msg, err) + } + } +} + +func (tv *TableViewImpl) watchReaderForNewMessages(ctx context.Context, reader Reader) { + for { + msg, err := reader.Next(ctx) + if err != nil { + tv.logger.Errorf("read next message failed for %s: %w", reader.Topic(), err) + } + if errors.Is(err, context.Canceled) { + return + } + tv.handleMessage(msg) + } +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/transaction.go b/vendor/github.com/apache/pulsar-client-go/pulsar/transaction.go new file mode 100644 index 00000000..60e1d2bf --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/transaction.go @@ -0,0 +1,69 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" +) + +// TxnState The state of the transaction. Check the state of the transaction before executing some operation +// with the transaction is necessary. +type TxnState int32 + +const ( + _ TxnState = iota + // TxnOpen The transaction in TxnOpen state can be used to send/ack messages. + TxnOpen + // TxnCommitting The state of the transaction will be TxnCommitting after the commit method is called. + // The transaction in TxnCommitting state can be committed again. + TxnCommitting + // TxnAborting The state of the transaction will be TxnAborting after the abort method is called. + // The transaction in TxnAborting state can be aborted again. + TxnAborting + // TxnCommitted The state of the transaction will be TxnCommitted after the commit method is executed success. + // This means that all the operations with the transaction are success. + TxnCommitted + // TxnAborted The state of the transaction will be TxnAborted after the abort method is executed success. + // This means that all the operations with the transaction are aborted. + TxnAborted + // TxnError The state of the transaction will be TxnError after the operation of transaction get a non-retryable error. + TxnError + // TxnTimeout The state of the transaction will be TxnTimeout after the transaction timeout. + TxnTimeout +) + +// TxnID An identifier for representing a transaction. +type TxnID struct { + // mostSigBits The most significant 64 bits of this TxnID. + mostSigBits uint64 + // leastSigBits The least significant 64 bits of this TxnID. + leastSigBits uint64 +} + +// Transaction used to guarantee exactly-once +type Transaction interface { + //Commit You can commit the transaction after all the sending/acknowledging operations with the transaction success. + Commit(context.Context) error + //Abort You can abort the transaction when you want to abort all the sending/acknowledging operations + // with the transaction. + Abort(context.Context) error + //GetState Get the state of the transaction. + GetState() TxnState + //GetTxnID Get the identified ID of the transaction. + GetTxnID() TxnID +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/transaction_coordinator_client.go b/vendor/github.com/apache/pulsar-client-go/pulsar/transaction_coordinator_client.go new file mode 100644 index 00000000..1535fad1 --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/transaction_coordinator_client.go @@ -0,0 +1,216 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" + "strconv" + "sync/atomic" + "time" + + "github.com/apache/pulsar-client-go/pulsar/internal" + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "github.com/apache/pulsar-client-go/pulsar/log" + "google.golang.org/protobuf/proto" +) + +type transactionCoordinatorClient struct { + client *client + cons []internal.Connection + epoch uint64 + semaphore internal.Semaphore + log log.Logger +} + +// TransactionCoordinatorAssign is the transaction_impl coordinator topic which is used to look up the broker +// where the TC located. +const TransactionCoordinatorAssign = "persistent://pulsar/system/transaction_coordinator_assign" + +// newTransactionCoordinatorClientImpl init a transactionImpl coordinator client and +// acquire connections with all transactionImpl coordinators. +func newTransactionCoordinatorClientImpl(client *client) *transactionCoordinatorClient { + tc := &transactionCoordinatorClient{ + client: client, + semaphore: internal.NewSemaphore(1000), + } + tc.log = client.log.SubLogger(log.Fields{}) + return tc +} + +func (tc *transactionCoordinatorClient) start() error { + r, err := tc.client.lookupService.GetPartitionedTopicMetadata(TransactionCoordinatorAssign) + if err != nil { + return err + } + tc.cons = make([]internal.Connection, r.Partitions) + + //Get connections with all transaction_impl coordinators which is synchronized + for i := 0; i < r.Partitions; i++ { + err := tc.grabConn(uint64(i)) + if err != nil { + return err + } + } + return nil +} + +func (tc *transactionCoordinatorClient) grabConn(partition uint64) error { + lr, err := tc.client.lookupService.Lookup(getTCAssignTopicName(partition)) + if err != nil { + tc.log.WithError(err).Warn("Failed to lookup the transaction_impl " + + "coordinator assign topic [" + strconv.FormatUint(partition, 10) + "]") + return err + } + + requestID := tc.client.rpcClient.NewRequestID() + cmdTCConnect := pb.CommandTcClientConnectRequest{ + RequestId: proto.Uint64(requestID), + TcId: proto.Uint64(partition), + } + + res, err := tc.client.rpcClient.Request(lr.LogicalAddr, lr.PhysicalAddr, requestID, + pb.BaseCommand_TC_CLIENT_CONNECT_REQUEST, &cmdTCConnect) + + if err != nil { + tc.log.WithError(err).Error("Failed to connect transaction_impl coordinator " + + strconv.FormatUint(partition, 10)) + return err + } + tc.cons[partition] = res.Cnx + return nil +} + +func (tc *transactionCoordinatorClient) close() { + for _, con := range tc.cons { + con.Close() + } +} + +// newTransaction new a transactionImpl which can be used to guarantee exactly-once semantics. +func (tc *transactionCoordinatorClient) newTransaction(timeout time.Duration) (*TxnID, error) { + if err := tc.canSendRequest(); err != nil { + return nil, err + } + requestID := tc.client.rpcClient.NewRequestID() + nextTcID := tc.nextTCNumber() + cmdNewTxn := &pb.CommandNewTxn{ + RequestId: proto.Uint64(requestID), + TcId: proto.Uint64(nextTcID), + TxnTtlSeconds: proto.Uint64(uint64(timeout.Milliseconds())), + } + + res, err := tc.client.rpcClient.RequestOnCnx(tc.cons[nextTcID], requestID, pb.BaseCommand_NEW_TXN, cmdNewTxn) + tc.semaphore.Release() + if err != nil { + return nil, err + } else if res.Response.NewTxnResponse.Error != nil { + return nil, getErrorFromServerError(res.Response.NewTxnResponse.Error) + } + + return &TxnID{*res.Response.NewTxnResponse.TxnidMostBits, + *res.Response.NewTxnResponse.TxnidLeastBits}, nil +} + +// addPublishPartitionToTxn register the partitions which published messages with the transactionImpl. +// And this can be used when ending the transactionImpl. +func (tc *transactionCoordinatorClient) addPublishPartitionToTxn(id *TxnID, partitions []string) error { + if err := tc.canSendRequest(); err != nil { + return err + } + requestID := tc.client.rpcClient.NewRequestID() + cmdAddPartitions := &pb.CommandAddPartitionToTxn{ + RequestId: proto.Uint64(requestID), + TxnidMostBits: proto.Uint64(id.mostSigBits), + TxnidLeastBits: proto.Uint64(id.leastSigBits), + Partitions: partitions, + } + res, err := tc.client.rpcClient.RequestOnCnx(tc.cons[id.mostSigBits], requestID, + pb.BaseCommand_ADD_PARTITION_TO_TXN, cmdAddPartitions) + tc.semaphore.Release() + if err != nil { + return err + } else if res.Response.AddPartitionToTxnResponse.Error != nil { + return getErrorFromServerError(res.Response.AddPartitionToTxnResponse.Error) + } + return nil +} + +// addSubscriptionToTxn register the subscription which acked messages with the transactionImpl. +// And this can be used when ending the transactionImpl. +func (tc *transactionCoordinatorClient) addSubscriptionToTxn(id *TxnID, topic string, subscription string) error { + if err := tc.canSendRequest(); err != nil { + return err + } + requestID := tc.client.rpcClient.NewRequestID() + sub := &pb.Subscription{ + Topic: &topic, + Subscription: &subscription, + } + cmdAddSubscription := &pb.CommandAddSubscriptionToTxn{ + RequestId: proto.Uint64(requestID), + TxnidMostBits: proto.Uint64(id.mostSigBits), + TxnidLeastBits: proto.Uint64(id.leastSigBits), + Subscription: []*pb.Subscription{sub}, + } + res, err := tc.client.rpcClient.RequestOnCnx(tc.cons[id.mostSigBits], requestID, + pb.BaseCommand_ADD_SUBSCRIPTION_TO_TXN, cmdAddSubscription) + tc.semaphore.Release() + if err != nil { + return err + } else if res.Response.AddSubscriptionToTxnResponse.Error != nil { + return getErrorFromServerError(res.Response.AddSubscriptionToTxnResponse.Error) + } + return nil +} + +// endTxn commit or abort the transactionImpl. +func (tc *transactionCoordinatorClient) endTxn(id *TxnID, action pb.TxnAction) error { + if err := tc.canSendRequest(); err != nil { + return err + } + requestID := tc.client.rpcClient.NewRequestID() + cmdEndTxn := &pb.CommandEndTxn{ + RequestId: proto.Uint64(requestID), + TxnAction: &action, + TxnidMostBits: proto.Uint64(id.mostSigBits), + TxnidLeastBits: proto.Uint64(id.leastSigBits), + } + res, err := tc.client.rpcClient.RequestOnCnx(tc.cons[id.mostSigBits], requestID, pb.BaseCommand_END_TXN, cmdEndTxn) + tc.semaphore.Release() + if err != nil { + return err + } else if res.Response.EndTxnResponse.Error != nil { + return getErrorFromServerError(res.Response.EndTxnResponse.Error) + } + return nil +} + +func getTCAssignTopicName(partition uint64) string { + return TransactionCoordinatorAssign + "-partition-" + strconv.FormatUint(partition, 10) +} + +func (tc *transactionCoordinatorClient) canSendRequest() error { + if !tc.semaphore.Acquire(context.Background()) { + return newError(UnknownError, "Failed to acquire semaphore") + } + return nil +} + +func (tc *transactionCoordinatorClient) nextTCNumber() uint64 { + return atomic.AddUint64(&tc.epoch, 1) % uint64(len(tc.cons)) +} diff --git a/vendor/github.com/apache/pulsar-client-go/pulsar/transaction_impl.go b/vendor/github.com/apache/pulsar-client-go/pulsar/transaction_impl.go new file mode 100644 index 00000000..7cc93eca --- /dev/null +++ b/vendor/github.com/apache/pulsar-client-go/pulsar/transaction_impl.go @@ -0,0 +1,237 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsar + +import ( + "context" + "sync" + "sync/atomic" + "time" + + pb "github.com/apache/pulsar-client-go/pulsar/internal/pulsar_proto" + "github.com/apache/pulsar-client-go/pulsar/log" +) + +type subscription struct { + topic string + subscription string +} + +type transaction struct { + sync.Mutex + txnID TxnID + state TxnState + tcClient *transactionCoordinatorClient + registerPartitions map[string]bool + registerAckSubscriptions map[subscription]bool + // opsFlow It has two effects: + // 1. Wait all the operations of sending and acking messages with the transaction complete + // by reading msg from the chan. + // 2. Prevent sending or acking messages with a committed or aborted transaction. + // opsCount is record the number of the uncompleted operations. + // opsFlow + // Write: + // 1. When the transaction is created, a bool will be written to opsFlow chan. + // 2. When the opsCount decrement from 1 to 0, a new bool will be written to opsFlow chan. + // 3. When get a retryable error after committing or aborting the transaction, + // a bool will be written to opsFlow chan. + // Read: + // 1. When the transaction is committed or aborted, a bool will be read from opsFlow chan. + // 2. When the opsCount increment from 0 to 1, a bool will be read from opsFlow chan. + opsFlow chan bool + opsCount int32 + opTimeout time.Duration + log log.Logger +} + +func newTransaction(id TxnID, tcClient *transactionCoordinatorClient, timeout time.Duration) *transaction { + transaction := &transaction{ + txnID: id, + state: TxnOpen, + registerPartitions: make(map[string]bool), + registerAckSubscriptions: make(map[subscription]bool), + opsFlow: make(chan bool, 1), + opTimeout: 5 * time.Second, + tcClient: tcClient, + } + //This means there are not pending requests with this transaction. The transaction can be committed or aborted. + transaction.opsFlow <- true + go func() { + //Set the state of the transaction to timeout after timeout + <-time.After(timeout) + atomic.CompareAndSwapInt32((*int32)(&transaction.state), int32(TxnOpen), int32(TxnTimeout)) + }() + transaction.log = tcClient.log.SubLogger(log.Fields{}) + return transaction +} + +func (txn *transaction) GetState() TxnState { + return txn.state +} + +func (txn *transaction) Commit(ctx context.Context) error { + if !(atomic.CompareAndSwapInt32((*int32)(&txn.state), int32(TxnOpen), int32(TxnCommitting)) || + txn.state == TxnCommitting) { + return newError(InvalidStatus, "Expect transaction state is TxnOpen but "+txn.state.string()) + } + + //Wait for all operations to complete + select { + case <-txn.opsFlow: + case <-time.After(txn.opTimeout): + return newError(TimeoutError, "There are some operations that are not completed after the timeout.") + } + //Send commit transaction command to transaction coordinator + err := txn.tcClient.endTxn(&txn.txnID, pb.TxnAction_COMMIT) + if err == nil { + atomic.StoreInt32((*int32)(&txn.state), int32(TxnCommitted)) + } else { + if err.(*Error).Result() == TransactionNoFoundError || err.(*Error).Result() == InvalidStatus { + atomic.StoreInt32((*int32)(&txn.state), int32(TxnError)) + return err + } + txn.opsFlow <- true + } + return err +} + +func (txn *transaction) Abort(ctx context.Context) error { + if !(atomic.CompareAndSwapInt32((*int32)(&txn.state), int32(TxnOpen), int32(TxnAborting)) || + txn.state == TxnAborting) { + return newError(InvalidStatus, "Expect transaction state is TxnOpen but "+txn.state.string()) + } + + //Wait for all operations to complete + select { + case <-txn.opsFlow: + case <-time.After(txn.opTimeout): + return newError(TimeoutError, "There are some operations that are not completed after the timeout.") + } + //Send abort transaction command to transaction coordinator + err := txn.tcClient.endTxn(&txn.txnID, pb.TxnAction_ABORT) + if err == nil { + atomic.StoreInt32((*int32)(&txn.state), int32(TxnAborted)) + } else { + if err.(*Error).Result() == TransactionNoFoundError || err.(*Error).Result() == InvalidStatus { + atomic.StoreInt32((*int32)(&txn.state), int32(TxnError)) + } else { + txn.opsFlow <- true + } + } + return err +} + +func (txn *transaction) registerSendOrAckOp() error { + if atomic.AddInt32(&txn.opsCount, 1) == 1 { + //There are new operations that not completed + select { + case <-txn.opsFlow: + return nil + case <-time.After(txn.opTimeout): + if _, err := txn.checkIfOpen(); err != nil { + return err + } + return newError(TimeoutError, "Failed to get the semaphore to register the send/ack operation") + } + } + return nil +} + +func (txn *transaction) endSendOrAckOp(err error) { + if err != nil { + atomic.StoreInt32((*int32)(&txn.state), int32(TxnError)) + } + if atomic.AddInt32(&txn.opsCount, -1) == 0 { + //This means there are not pending send/ack requests + txn.opsFlow <- true + } +} + +func (txn *transaction) registerProducerTopic(topic string) error { + isOpen, err := txn.checkIfOpen() + if !isOpen { + return err + } + _, ok := txn.registerPartitions[topic] + if !ok { + txn.Lock() + defer txn.Unlock() + if _, ok = txn.registerPartitions[topic]; !ok { + err := txn.tcClient.addPublishPartitionToTxn(&txn.txnID, []string{topic}) + if err != nil { + return err + } + txn.registerPartitions[topic] = true + } + } + return nil +} + +func (txn *transaction) registerAckTopic(topic string, subName string) error { + isOpen, err := txn.checkIfOpen() + if !isOpen { + return err + } + sub := subscription{ + topic: topic, + subscription: subName, + } + _, ok := txn.registerAckSubscriptions[sub] + if !ok { + txn.Lock() + defer txn.Unlock() + if _, ok = txn.registerAckSubscriptions[sub]; !ok { + err := txn.tcClient.addSubscriptionToTxn(&txn.txnID, topic, subName) + if err != nil { + return err + } + txn.registerAckSubscriptions[sub] = true + } + } + return nil +} + +func (txn *transaction) GetTxnID() TxnID { + return txn.txnID +} + +func (txn *transaction) checkIfOpen() (bool, error) { + if txn.state == TxnOpen { + return true, nil + } + return false, newError(InvalidStatus, "Expect transaction state is TxnOpen but "+txn.state.string()) +} + +func (state TxnState) string() string { + switch state { + case TxnOpen: + return "TxnOpen" + case TxnCommitting: + return "TxnCommitting" + case TxnAborting: + return "TxnAborting" + case TxnCommitted: + return "TxnCommitted" + case TxnAborted: + return "TxnAborted" + case TxnTimeout: + return "TxnTimeout" + default: + return "Unknown" + } +}