You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by mm...@apache.org on 2019/05/14 16:33:37 UTC
[pulsar-client-go] branch master updated (d74beea -> 9c5d509)
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git.
from d74beea Initial commit
new 84cb32e Initial import
new 0c2da14 Use string for result errors
new ccc596a Create producer session
new 1bdf19f Implemented keep-alive logic
new d31030e Set right level for logs
new d8a1dcc Removed internalClose method
new 0fe868a Added serialize method for string map
new f7cac7a Basic publishing works
new 2e74112 Reconnection logic
new b95a971 Added blocking queue implementation
new 7851714 Queue sending requests and trigger callbacks
new ecab9cf Added blocking queue iterator
new 427fe05 Resend pending messages after reconnection
new 9522dd5 Handle cases with no-batching
new 98552f3 Producer close
new ea44ac9 Implemented producer flush
new f9fa727 Added compression codecs and tests
new 0eb04d5 Support compression in producer
new b924b78 Completed lookup service with tests
new b2c9d8c Producer last sequence id
new 0ac7868 Added hash functions and tests
new e7a4aef Completed default message router and tests
new 585500e Added perf producer/consumer
new 9c6d52f Added auto-resize when writing to buffer
new e077250 Use logrus in perf producer/consumer
new b329bbf Fixed releasing of semaphore for each send request
new 05bc67f Added MessageID implementation
new dfd7550 Renamed to pulsar-client-go
new 1ead55b Added license headers
new b212407 Added README
new 617f0d5 Addressed comments
new d6dbcfa Renamed `impl` package to `internal`
new fe3258b Added scripts to start test service
new ddc789e Added TLS connection support
new 1a6dfaa TLS Auth provider
new e058b84 Added token auth provider
new 9c5d509 Merge pull request #1 from merlimat/master
The 38 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.gitignore | 1 +
Dockerfile | 34 +
LICENSE | 305 ++
NOTICE | 6 +
README.md | 60 +
integration-tests/certs/broker-cert.pem | 73 +
integration-tests/certs/broker-key.pem | 28 +
integration-tests/certs/cacert.pem | 62 +
integration-tests/certs/client-cert.pem | 73 +
integration-tests/certs/client-key.pem | 28 +
integration-tests/client.conf | 27 +
integration-tests/standalone.conf | 280 ++
integration-tests/tokens/secret.key | 1 +
integration-tests/tokens/token.txt | 1 +
perf/perf-consumer.go | 113 +
perf/perf-producer.go | 147 +
perf/pulsar-perf-go.go | 49 +
pulsar-test-service-start.sh | 79 +
pulsar-test-service-stop.sh | 35 +
pulsar/client.go | 113 +
pulsar/consumer.go | 179 +
pulsar/error.go | 103 +
pulsar/impl_client.go | 152 +
pulsar/impl_client_test.go | 203 ++
pulsar/impl_message.go | 78 +
pulsar/impl_message_test.go | 48 +
pulsar/impl_partition_producer.go | 427 +++
pulsar/impl_producer.go | 156 +
pulsar/internal/auth/disabled.go | 49 +
pulsar/internal/auth/provider.go | 63 +
pulsar/internal/auth/tls.go | 64 +
pulsar/internal/auth/token.go | 98 +
pulsar/internal/backoff.go | 45 +
pulsar/internal/batch_builder.go | 166 +
pulsar/internal/buffer.go | 193 ++
pulsar/internal/buffer_test.go | 38 +
pulsar/internal/checksum.go | 28 +
pulsar/internal/closable.go | 24 +
pulsar/internal/commands.go | 141 +
pulsar/internal/commands_test.go | 45 +
pulsar/internal/compression/compression.go | 33 +
pulsar/internal/compression/compression_test.go | 71 +
pulsar/internal/compression/lz4.go | 47 +
pulsar/internal/compression/noop.go | 35 +
pulsar/internal/compression/zlib.go | 54 +
pulsar/internal/compression/zstd.go | 39 +
pulsar/internal/connection.go | 484 +++
pulsar/internal/connection_pool.go | 85 +
pulsar/internal/connection_reader.go | 136 +
pulsar/internal/default_router.go | 69 +
pulsar/internal/default_router_test.go | 85 +
pulsar/internal/hash.go | 38 +
pulsar/internal/hash_test.go | 59 +
pulsar/internal/lookup_service.go | 132 +
pulsar/internal/lookup_service_test.go | 268 ++
pulsar/internal/pulsar_proto/PulsarApi.pb.go | 4043 +++++++++++++++++++++++
pulsar/internal/rpc_client.go | 124 +
pulsar/internal/topic_name.go | 107 +
pulsar/internal/topic_name_test.go | 87 +
pulsar/internal/util/blocking_queue.go | 203 ++
pulsar/internal/util/blocking_queue_test.go | 137 +
pulsar/internal/util/semaphore.go | 30 +
pulsar/internal/utils.go | 39 +
pulsar/message.go | 88 +
pulsar/producer.go | 167 +
pulsar/producer_test.go | 181 +
pulsar/reader.go | 84 +
pulsar/test_helper.go | 43 +
68 files changed, 10783 insertions(+)
create mode 100644 .gitignore
create mode 100644 Dockerfile
create mode 100644 LICENSE
create mode 100644 NOTICE
create mode 100644 integration-tests/certs/broker-cert.pem
create mode 100644 integration-tests/certs/broker-key.pem
create mode 100644 integration-tests/certs/cacert.pem
create mode 100644 integration-tests/certs/client-cert.pem
create mode 100644 integration-tests/certs/client-key.pem
create mode 100644 integration-tests/client.conf
create mode 100644 integration-tests/standalone.conf
create mode 100644 integration-tests/tokens/secret.key
create mode 100644 integration-tests/tokens/token.txt
create mode 100644 perf/perf-consumer.go
create mode 100644 perf/perf-producer.go
create mode 100644 perf/pulsar-perf-go.go
create mode 100755 pulsar-test-service-start.sh
create mode 100755 pulsar-test-service-stop.sh
create mode 100644 pulsar/client.go
create mode 100644 pulsar/consumer.go
create mode 100644 pulsar/error.go
create mode 100644 pulsar/impl_client.go
create mode 100644 pulsar/impl_client_test.go
create mode 100644 pulsar/impl_message.go
create mode 100644 pulsar/impl_message_test.go
create mode 100644 pulsar/impl_partition_producer.go
create mode 100644 pulsar/impl_producer.go
create mode 100644 pulsar/internal/auth/disabled.go
create mode 100644 pulsar/internal/auth/provider.go
create mode 100644 pulsar/internal/auth/tls.go
create mode 100644 pulsar/internal/auth/token.go
create mode 100644 pulsar/internal/backoff.go
create mode 100644 pulsar/internal/batch_builder.go
create mode 100644 pulsar/internal/buffer.go
create mode 100644 pulsar/internal/buffer_test.go
create mode 100644 pulsar/internal/checksum.go
create mode 100644 pulsar/internal/closable.go
create mode 100644 pulsar/internal/commands.go
create mode 100644 pulsar/internal/commands_test.go
create mode 100644 pulsar/internal/compression/compression.go
create mode 100644 pulsar/internal/compression/compression_test.go
create mode 100644 pulsar/internal/compression/lz4.go
create mode 100644 pulsar/internal/compression/noop.go
create mode 100644 pulsar/internal/compression/zlib.go
create mode 100644 pulsar/internal/compression/zstd.go
create mode 100644 pulsar/internal/connection.go
create mode 100644 pulsar/internal/connection_pool.go
create mode 100644 pulsar/internal/connection_reader.go
create mode 100644 pulsar/internal/default_router.go
create mode 100644 pulsar/internal/default_router_test.go
create mode 100644 pulsar/internal/hash.go
create mode 100644 pulsar/internal/hash_test.go
create mode 100644 pulsar/internal/lookup_service.go
create mode 100644 pulsar/internal/lookup_service_test.go
create mode 100644 pulsar/internal/pulsar_proto/PulsarApi.pb.go
create mode 100644 pulsar/internal/rpc_client.go
create mode 100644 pulsar/internal/topic_name.go
create mode 100644 pulsar/internal/topic_name_test.go
create mode 100644 pulsar/internal/util/blocking_queue.go
create mode 100644 pulsar/internal/util/blocking_queue_test.go
create mode 100644 pulsar/internal/util/semaphore.go
create mode 100644 pulsar/internal/utils.go
create mode 100644 pulsar/message.go
create mode 100644 pulsar/producer.go
create mode 100644 pulsar/producer_test.go
create mode 100644 pulsar/reader.go
create mode 100644 pulsar/test_helper.go
[pulsar-client-go] 28/38: Added MessageID implementation
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 05bc67ffc3b6d2c486481dc38dd65ad8b829596a
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Sun May 5 10:56:14 2019 -0700
Added MessageID implementation
---
pulsar/impl_message.go | 59 +++++++++++++++++++++++++++++++++++++++
pulsar/impl_message_test.go | 29 +++++++++++++++++++
pulsar/impl_partition_producer.go | 15 ++++++++--
pulsar/impl_producer.go | 2 +-
pulsar/message.go | 14 ++++------
5 files changed, 107 insertions(+), 12 deletions(-)
diff --git a/pulsar/impl_message.go b/pulsar/impl_message.go
new file mode 100644
index 0000000..5d54678
--- /dev/null
+++ b/pulsar/impl_message.go
@@ -0,0 +1,59 @@
+package pulsar
+
+import (
+ "github.com/golang/protobuf/proto"
+ pb "pulsar-client-go-native/pulsar/pulsar_proto"
+)
+
+type messageId struct {
+ ledgerID int64
+ entryID int64
+ batchIdx int
+ partitionIdx int
+}
+
+func newMessageId(ledgerID int64, entryID int64, batchIdx int, partitionIdx int) MessageID {
+ return &messageId{
+ ledgerID: ledgerID,
+ entryID: entryID,
+ batchIdx: batchIdx,
+ partitionIdx: partitionIdx,
+ }
+}
+
+func (id *messageId) Serialize() []byte {
+ msgId := &pb.MessageIdData{
+ LedgerId: proto.Uint64(uint64(id.ledgerID)),
+ EntryId: proto.Uint64(uint64(id.entryID)),
+ BatchIndex: proto.Int(id.batchIdx),
+ Partition: proto.Int(id.partitionIdx),
+ }
+ data, _ := proto.Marshal(msgId)
+ return data
+}
+
+func deserializeMessageId(data []byte) (MessageID, error) {
+ msgId := &pb.MessageIdData{}
+ err := proto.Unmarshal(data, msgId)
+ if err != nil {
+ return nil, err
+ } else {
+ id := newMessageId(
+ int64(msgId.GetLedgerId()),
+ int64(msgId.GetEntryId()),
+ int(msgId.GetBatchIndex()),
+ int(msgId.GetPartition()),
+ )
+ return id, nil
+ }
+}
+
+func earliestMessageID() MessageID {
+ return newMessageId(-1, -1, -1, -1)
+}
+
+const maxLong int64 = 0x7fffffffffffffff
+
+func latestMessageID() MessageID {
+ return newMessageId(maxLong, maxLong, -1, -1)
+}
diff --git a/pulsar/impl_message_test.go b/pulsar/impl_message_test.go
new file mode 100644
index 0000000..ea64640
--- /dev/null
+++ b/pulsar/impl_message_test.go
@@ -0,0 +1,29 @@
+package pulsar
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestMessageId(t *testing.T) {
+ id := newMessageId(1,2, 3, 4)
+ bytes := id.Serialize()
+
+ id2, err := DeserializeMessageID(bytes)
+ assert.NoError(t, err)
+ assert.NotNil(t, id2)
+
+ assert.Equal(t, int64(1), id2.(*messageId).ledgerID)
+ assert.Equal(t, int64(2), id2.(*messageId).entryID)
+ assert.Equal(t, 3, id2.(*messageId).batchIdx)
+ assert.Equal(t, 4, id2.(*messageId).partitionIdx)
+
+ id, err = DeserializeMessageID(nil)
+ assert.Error(t, err)
+ assert.Nil(t, id)
+
+ id, err = DeserializeMessageID(make([]byte, 0))
+ assert.Error(t, err)
+ assert.Nil(t, id)
+}
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index 5f3f671..78f14af 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -41,11 +41,13 @@ type partitionProducer struct {
publishSemaphore util.Semaphore
pendingQueue util.BlockingQueue
lastSequenceID int64
+
+ partitionIdx int
}
const defaultBatchingMaxPublishDelay = 10 * time.Millisecond
-func newPartitionProducer(client *client, topic string, options *ProducerOptions) (*partitionProducer, error) {
+func newPartitionProducer(client *client, topic string, options *ProducerOptions, partitionIdx int) (*partitionProducer, error) {
var batchingMaxPublishDelay time.Duration
if options.BatchingMaxPublishDelay != 0 {
@@ -73,6 +75,7 @@ func newPartitionProducer(client *client, topic string, options *ProducerOptions
publishSemaphore: make(util.Semaphore, maxPendingMessages),
pendingQueue: util.NewBlockingQueue(maxPendingMessages),
lastSequenceID: -1,
+ partitionIdx: partitionIdx,
}
if options.Name != "" {
@@ -313,12 +316,18 @@ func (p *partitionProducer) ReceivedSendReceipt(response *pb.CommandSendReceipt)
// The ack was indeed for the expected item in the queue, we can remove it and trigger the callback
p.pendingQueue.Poll()
- for _, i := range pi.sendRequests {
+ for idx, i := range pi.sendRequests {
sr := i.(*sendRequest)
atomic.StoreInt64(&p.lastSequenceID, int64(pi.sequenceId))
if sr.callback != nil {
p.publishSemaphore.Release()
- sr.callback(nil, sr.msg, nil)
+ msgID := newMessageId(
+ int64(response.MessageId.GetLedgerId()),
+ int64(response.MessageId.GetEntryId()),
+ idx,
+ p.partitionIdx,
+ )
+ sr.callback(msgID, sr.msg, nil)
}
}
}
diff --git a/pulsar/impl_producer.go b/pulsar/impl_producer.go
index 12e5e7c..aec4eb5 100644
--- a/pulsar/impl_producer.go
+++ b/pulsar/impl_producer.go
@@ -59,7 +59,7 @@ func newProducer(client *client, options *ProducerOptions) (*producer, error) {
for partitionIdx, partition := range partitions {
go func() {
- prod, err := newPartitionProducer(client, partition, options)
+ prod, err := newPartitionProducer(client, partition, options, partitionIdx)
c <- ProducerError{partitionIdx, prod, err}
}()
}
diff --git a/pulsar/message.go b/pulsar/message.go
index e987ad1..8323aa1 100644
--- a/pulsar/message.go
+++ b/pulsar/message.go
@@ -75,16 +75,14 @@ type MessageID interface {
}
// Reconstruct a MessageID object from its serialized representation
-func DeserializeMessageID(data []byte) MessageID {
- // TODO
- //return deserializeMessageId(data)
- return nil
+func DeserializeMessageID(data []byte) (MessageID, error) {
+ return deserializeMessageId(data)
}
var (
-// MessageID that points to the earliest message available in a topic
-// TODO: EarliestMessage MessageID = earliestMessageID()
+ // MessageID that points to the earliest message available in a topic
+ EarliestMessage MessageID = earliestMessageID()
-// MessageID that points to the latest message
-// TODO: LatestMessage MessageID = latestMessageID()
+ // MessageID that points to the latest message
+ LatestMessage MessageID = latestMessageID()
)
[pulsar-client-go] 16/38: Producer close
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 98552f3665b7f2964aeef2484de3e3db2b150b4c
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Thu Apr 11 11:39:59 2019 -0700
Producer close
---
pulsar/impl/commands.go | 2 ++
pulsar/impl/connection.go | 8 +++++
pulsar/impl/rpc_client.go | 20 ++++++++++++
pulsar/impl_partition_producer.go | 65 ++++++++++++++++++++++++++++++++++++---
4 files changed, 90 insertions(+), 5 deletions(-)
diff --git a/pulsar/impl/commands.go b/pulsar/impl/commands.go
index 08f8124..c2db791 100644
--- a/pulsar/impl/commands.go
+++ b/pulsar/impl/commands.go
@@ -29,6 +29,8 @@ func baseCommand(cmdType pb.BaseCommand_Type, msg proto.Message) *pb.BaseCommand
cmd.Pong = msg.(*pb.CommandPong)
case pb.BaseCommand_SEND:
cmd.Send = msg.(*pb.CommandSend)
+ case pb.BaseCommand_CLOSE_PRODUCER:
+ cmd.CloseProducer = msg.(*pb.CommandCloseProducer)
default:
log.Panic("Missing command type: ", cmdType)
}
diff --git a/pulsar/impl/connection.go b/pulsar/impl/connection.go
index 0cba51d..8cdcf8b 100644
--- a/pulsar/impl/connection.go
+++ b/pulsar/impl/connection.go
@@ -25,6 +25,7 @@ type Connection interface {
SendRequest(requestId uint64, req *pb.BaseCommand, callback func(command *pb.BaseCommand))
WriteData(data []byte)
RegisterListener(id uint64, listener ConnectionListener)
+ UnregisterListener(id uint64)
Close()
}
@@ -351,6 +352,13 @@ func (c *connection) RegisterListener(id uint64, listener ConnectionListener) {
c.listeners[id] = listener
}
+func (c *connection) UnregisterListener(id uint64) {
+ c.Lock()
+ defer c.Unlock()
+
+ delete(c.listeners, id)
+}
+
func (c *connection) Close() {
c.Lock()
defer c.Unlock()
diff --git a/pulsar/impl/rpc_client.go b/pulsar/impl/rpc_client.go
index 2aa6106..706b9a1 100644
--- a/pulsar/impl/rpc_client.go
+++ b/pulsar/impl/rpc_client.go
@@ -26,6 +26,8 @@ type RpcClient interface {
Request(logicalAddr *url.URL, physicalAddr *url.URL, requestId uint64,
cmdType pb.BaseCommand_Type, message proto.Message) (*RpcResult, error)
+
+ RequestOnCnx(cnx Connection, requestId uint64, cmdType pb.BaseCommand_Type, message proto.Message) (*RpcResult, error)
}
type rpcClient struct {
@@ -72,6 +74,24 @@ func (c *rpcClient) Request(logicalAddr *url.URL, physicalAddr *url.URL, request
return rpcResult, nil
}
+func (c *rpcClient) RequestOnCnx(cnx Connection, requestId uint64, cmdType pb.BaseCommand_Type,
+ message proto.Message) (*RpcResult, error) {
+ wg := sync.WaitGroup{}
+ wg.Add(1)
+
+ rpcResult := &RpcResult{
+ Cnx: cnx,
+ }
+
+ cnx.SendRequest(requestId, baseCommand(cmdType, message), func(response *pb.BaseCommand) {
+ rpcResult.Response = response
+ wg.Done()
+ })
+
+ wg.Wait()
+ return rpcResult, nil
+}
+
func (c *rpcClient) NewRequestId() uint64 {
return atomic.AddUint64(&c.requestIdGenerator, 1)
}
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index d0cd8cf..c99ea67 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -11,12 +11,20 @@ import (
"time"
)
+type producerState int
+
+const (
+ producerInit = iota
+ producerReady
+ producerClosing
+ producerClosed
+)
+
type partitionProducer struct {
+ state producerState
client *client
topic string
log *log.Entry
- mutex sync.Mutex
- cond *sync.Cond
cnx impl.Connection
options *ProducerOptions
@@ -52,6 +60,7 @@ func newPartitionProducer(client *client, topic string, options *ProducerOptions
}
p := &partitionProducer{
+ state: producerInit,
log: log.WithField("topic", topic),
client: client,
topic: topic,
@@ -74,6 +83,7 @@ func newPartitionProducer(client *client, topic string, options *ProducerOptions
} else {
p.log = p.log.WithField("name", *p.producerName)
p.log.Info("Created producer")
+ p.state = producerReady
go p.runEventsLoop()
return p, nil
}
@@ -136,6 +146,11 @@ func (p *partitionProducer) reconnectToBroker() {
p.log.Info("Reconnecting to broker")
backoff := impl.Backoff{}
for {
+ if p.state != producerReady {
+ // Producer is already closing
+ return
+ }
+
err := p.grabCnx()
if err == nil {
// Successfully reconnected
@@ -153,6 +168,10 @@ func (p *partitionProducer) runEventsLoop() {
for {
select {
case i := <-p.eventsChan:
+ if i == nil {
+ return
+ }
+
switch v := i.(type) {
case *sendRequest:
p.internalSend(v)
@@ -286,6 +305,33 @@ func (p *partitionProducer) ReceivedSendReceipt(response *pb.CommandSendReceipt)
}
}
+func (p *partitionProducer) internalClose(req *closeProducer) {
+ if p.state != producerReady {
+ req.waitGroup.Done()
+ return
+ }
+
+ p.state = producerClosing
+ p.log.Info("Closing producer")
+
+ id := p.client.rpcClient.NewRequestId()
+ _, err := p.client.rpcClient.RequestOnCnx(p.cnx, id, pb.BaseCommand_CLOSE_PRODUCER, &pb.CommandCloseProducer{
+ ProducerId: &p.producerId,
+ RequestId: &id,
+ })
+
+ if err != nil {
+ req.err = err
+ } else {
+ p.log.Info("Closed producer")
+ p.state = producerClosed
+ p.cnx.UnregisterListener(p.producerId)
+ p.batchFlushTicker.Stop()
+ }
+
+ req.waitGroup.Done()
+}
+
func (p *partitionProducer) LastSequenceID() int64 {
// TODO: return real last sequence id
return -1
@@ -296,8 +342,15 @@ func (p *partitionProducer) Flush() error {
}
func (p *partitionProducer) Close() error {
- p.log.Info("Closing producer")
- return nil
+
+ wg := sync.WaitGroup{}
+ wg.Add(1)
+
+ cp := &closeProducer{&wg, nil}
+ p.eventsChan <- cp
+
+ wg.Wait()
+ return cp.err
}
type sendRequest struct {
@@ -308,4 +361,6 @@ type sendRequest struct {
}
type closeProducer struct {
-}
\ No newline at end of file
+ waitGroup *sync.WaitGroup
+ err error
+}
[pulsar-client-go] 34/38: Added scripts to start test service
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit fe3258b10c9b81e120c4600a1aec961df836b5e7
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Wed May 8 10:58:37 2019 -0700
Added scripts to start test service
---
Dockerfile | 41 +++++
integration-tests/certs/broker-cert.pem | 73 +++++++++
integration-tests/certs/broker-key.pem | 28 ++++
integration-tests/certs/cacert.pem | 62 +++++++
integration-tests/certs/client-cert.pem | 73 +++++++++
integration-tests/certs/client-key.pem | 28 ++++
integration-tests/client.conf | 27 +++
integration-tests/standalone.conf | 280 ++++++++++++++++++++++++++++++++
pulsar-test-service-start.sh | 79 +++++++++
pulsar-test-service-stop.sh | 35 ++++
10 files changed, 726 insertions(+)
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..3451983
--- /dev/null
+++ b/Dockerfile
@@ -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.
+#
+
+FROM golang:1.12 as go
+
+FROM apachepulsar/pulsar:latest
+
+COPY --from=go /usr/local/go /usr/local/go
+ENV PATH /root/go/bin:/usr/local/go/bin:$PATH
+
+### Add test scripts
+
+COPY integration-tests/certs /pulsar/certs
+COPY integration-tests/standalone.conf /pulsar/conf
+COPY integration-tests/client.conf /pulsar/conf
+COPY pulsar-test-service-start.sh /pulsar/bin
+COPY pulsar-test-service-stop.sh /pulsar/bin
+
+# Initialize test configuration and credentials
+RUN mkdir /pulsar/tokens
+RUN /pulsar/bin/pulsar tokens create-secret-key --output /pulsar/tokens/secret.key
+RUN /pulsar/bin/pulsar tokens create \
+ --subject token-principal \
+ --secret-key file:///pulsar/tokens/secret.key \
+ > /pulsar/tokens/token.txt
diff --git a/integration-tests/certs/broker-cert.pem b/integration-tests/certs/broker-cert.pem
new file mode 100644
index 0000000..69ad71c
--- /dev/null
+++ b/integration-tests/certs/broker-cert.pem
@@ -0,0 +1,73 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 88:08:98:b3:13:d8:00:97
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, ST=CA, O=Apache, OU=Pulsar Incubator, CN=localhost
+ Validity
+ Not Before: Feb 17 02:06:21 2018 GMT
+ Not After : Nov 16 00:00:00 2030 GMT
+ Subject: C=US, ST=CA, O=Apache, OU=Apache Pulsar, CN=localhost
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:af:bf:b7:2d:98:ad:9d:f6:da:a3:13:d4:62:0f:
+ 98:be:1c:a2:89:22:ba:6f:d5:fd:1f:67:e3:91:03:
+ 98:80:81:0e:ed:d8:f6:70:7f:2c:36:68:3d:53:ea:
+ 58:3a:a6:d5:89:66:4b:bd:1e:57:71:13:6d:4b:11:
+ e5:40:a5:76:84:24:92:40:58:80:96:c9:1f:2c:c4:
+ 55:eb:a3:79:73:70:5c:37:9a:89:ed:2f:ba:6b:e3:
+ 82:7c:69:4a:02:54:8b:81:5e:3c:bf:4c:8a:cb:ea:
+ 2c:5e:83:e7:b7:10:08:5f:82:58:a3:89:d1:da:92:
+ ba:2a:28:ee:30:28:3f:5b:ae:10:71:96:c7:e1:12:
+ c5:b0:1a:ad:44:6f:44:3a:11:4a:9a:3c:0f:8d:06:
+ 80:7b:34:ef:3f:6c:f4:5e:c5:44:54:1e:c8:dd:c7:
+ 80:85:80:d9:68:e6:c6:53:03:77:e1:fe:18:61:07:
+ 77:05:4c:ed:59:bc:5d:41:38:6a:ef:5d:a1:b2:60:
+ 98:d4:48:28:95:02:8a:0e:fd:cf:7b:1b:d2:11:cc:
+ 10:0c:50:73:d7:cc:38:6c:83:dd:79:26:aa:90:c8:
+ 9b:84:86:bc:59:e9:62:69:f4:98:1b:c4:80:78:7e:
+ a0:1a:81:9d:d2:e1:66:dd:c4:cc:fc:63:04:ac:ec:
+ a7:35
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ D3:F3:19:AE:74:B1:AF:E7:AF:08:7B:16:72:78:29:87:79:ED:30:8C
+ X509v3 Authority Key Identifier:
+ keyid:D4:7A:CD:0F:44:1B:16:29:25:14:ED:A2:EF:13:0F:A7:46:09:78:F6
+
+ Signature Algorithm: sha1WithRSAEncryption
+ 0f:04:f3:91:f2:87:19:fe:9d:f8:34:5a:24:4a:00:d1:58:bf:
+ 1e:b2:77:67:07:bc:78:b5:4b:9a:4b:fd:a1:e5:dc:0e:09:84:
+ 9e:59:c4:dd:cf:f7:2e:bf:da:f3:31:36:6b:81:6e:a2:88:76:
+ e4:2e:0b:36:44:82:36:8f:80:93:f4:9e:fc:ed:85:d0:97:da:
+ 0f:fb:c9:b9:8b:da:ae:07:3d:4f:82:b7:0c:25:22:63:12:6b:
+ 0a:e9:c4:12:a4:5c:ed:11:12:cc:fe:b0:2e:d4:c1:ec:79:01:
+ 60:ea:cc:cc:e5:66:cc:57:f6:55:a9:09:4c:63:01:e9:b4:2e:
+ 73:a5
+-----BEGIN CERTIFICATE-----
+MIIDLjCCApegAwIBAgIJAIgImLMT2ACXMA0GCSqGSIb3DQEBBQUAMFoxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIEwJDQTEPMA0GA1UEChMGQXBhY2hlMRkwFwYDVQQLExBQ
+dWxzYXIgSW5jdWJhdG9yMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTgwMjE3MDIw
+NjIxWhcNMzAxMTE2MDAwMDAwWjBXMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
+DzANBgNVBAoTBkFwYWNoZTEWMBQGA1UECxMNQXBhY2hlIFB1bHNhcjESMBAGA1UE
+AxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr7+3
+LZitnfbaoxPUYg+YvhyiiSK6b9X9H2fjkQOYgIEO7dj2cH8sNmg9U+pYOqbViWZL
+vR5XcRNtSxHlQKV2hCSSQFiAlskfLMRV66N5c3BcN5qJ7S+6a+OCfGlKAlSLgV48
+v0yKy+osXoPntxAIX4JYo4nR2pK6KijuMCg/W64QcZbH4RLFsBqtRG9EOhFKmjwP
+jQaAezTvP2z0XsVEVB7I3ceAhYDZaObGUwN34f4YYQd3BUztWbxdQThq712hsmCY
+1EgolQKKDv3PexvSEcwQDFBz18w4bIPdeSaqkMibhIa8WeliafSYG8SAeH6gGoGd
+0uFm3cTM/GMErOynNQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf
+Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU0/MZrnSx
+r+evCHsWcngph3ntMIwwHwYDVR0jBBgwFoAU1HrND0QbFiklFO2i7xMPp0YJePYw
+DQYJKoZIhvcNAQEFBQADgYEADwTzkfKHGf6d+DRaJEoA0Vi/HrJ3Zwe8eLVLmkv9
+oeXcDgmEnlnE3c/3Lr/a8zE2a4Fuooh25C4LNkSCNo+Ak/Se/O2F0JfaD/vJuYva
+rgc9T4K3DCUiYxJrCunEEqRc7RESzP6wLtTB7HkBYOrMzOVmzFf2VakJTGMB6bQu
+c6U=
+-----END CERTIFICATE-----
diff --git a/integration-tests/certs/broker-key.pem b/integration-tests/certs/broker-key.pem
new file mode 100644
index 0000000..004bf8e
--- /dev/null
+++ b/integration-tests/certs/broker-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCvv7ctmK2d9tqj
+E9RiD5i+HKKJIrpv1f0fZ+ORA5iAgQ7t2PZwfyw2aD1T6lg6ptWJZku9HldxE21L
+EeVApXaEJJJAWICWyR8sxFXro3lzcFw3montL7pr44J8aUoCVIuBXjy/TIrL6ixe
+g+e3EAhfglijidHakroqKO4wKD9brhBxlsfhEsWwGq1Eb0Q6EUqaPA+NBoB7NO8/
+bPRexURUHsjdx4CFgNlo5sZTA3fh/hhhB3cFTO1ZvF1BOGrvXaGyYJjUSCiVAooO
+/c97G9IRzBAMUHPXzDhsg915JqqQyJuEhrxZ6WJp9JgbxIB4fqAagZ3S4WbdxMz8
+YwSs7Kc1AgMBAAECggEAAaWEK9MwXTiA1+JJrRmETtOp2isPIBkbI/4vLZ6hASM0
+ZpoPxQIMAf58BJs/dF03xu/EaeMs4oxSC9ABG9fxAk/tZtjta3w65Ip6W5jOfHxj
+AMpb3HMEBhq9kDjUTq1IGVAutYQcEMkC3WfS9e4ahfqMpguWgbu6LsbvZFgcL9mv
+pGnKv9YVe6Xk6isvqtq6G1af0rd7c//xF0i0e/qEo83Buok3gLEZOELZbcRxjUYc
+jnyglnXnwkGjuL4E3wgS3l73ZKsb6+AYoqhMPVz8t4/PN3tTrsBJKOSYo8KzIm0U
+ek9T8XmPbP0cuheRxp9Dp8TXJJQZK0N9jz+EL0ogQQKBgQDnavm8GpR4pap9cDOc
++YI5s823b507pNdSU8elO9gLsP0JlFzv+sqghVko29r85D7Vn3MkgYTy0S4ANLCs
+0NFDY8N2QH6U1dTkk1QXZydVZDuKJ5SSpC4v+Vafl8yDxhB4Nlxhbm9vJEMfLcXh
+2kL6UlAuFDtYD0AdczwnHu5DjQKBgQDCauocm55FpcyDMMBO2CjurxcjBYS3S1xT
+Bz+sPtxJLjlKbAt8kSHUQcCcX9zhrQBfsT38LATCmKaOFqUW5/PPh2LcrxiMqlL1
+OJBUJ3Te2LTjlUn8r+DHv/69UIh5tchwRr3YgB0DuIs7jfmr4VfiOWTBtPVhoGFR
+1Wt60j30SQKBgHzreS26J2VNAFBALgxRf6OIVMbtgDG/FOCDCyU9vazp+F2gcd61
+QYYPFYcBzx9uUiDctroBFHRCyJMh3jEbc6ruAogl3m6XUxmkEeOkMk5dEerM3N2f
+tLL+5Gy385U6aI+LwKhzhcG4EGeXPNdjC362ykNldnddnB2Jo/H2N2XNAoGAdnft
+xpbxP+GDGKIZXTIM5zzcLWQMdiC+1n1BSHVZiGJZWMczzKknYw7aDq+/iekApE79
+xW8RS373ZvfXi3i2Mcx+6pjrrbOQL4tTL2SHq8+DknaDCi4mG7IbyUKMlxW1WO1S
+e929UGogtZ6S+DCte9WbVwosyFuRUetpvgLk67kCgYBWetihZjgBWrqVYT24TTRH
+KxzSzH1JgzzF9qgTdlhXDv9hC+Kc0uTKsgViesDqVuCOjkwzY5OQr9c6duO0fwwP
+qNk/qltdgjMC5iiv7duyukfbEuqKEdGGer9HFb7en96dZdVQJpYHaaslAGurtD80
+ejCQZgzR2XaHSuIQb0IUVQ==
+-----END PRIVATE KEY-----
diff --git a/integration-tests/certs/cacert.pem b/integration-tests/certs/cacert.pem
new file mode 100644
index 0000000..55e9067
--- /dev/null
+++ b/integration-tests/certs/cacert.pem
@@ -0,0 +1,62 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 88:08:98:b3:13:d8:00:94
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, ST=CA, O=Apache, OU=Pulsar Incubator, CN=localhost
+ Validity
+ Not Before: Feb 17 01:37:33 2018 GMT
+ Not After : Feb 16 01:37:33 2021 GMT
+ Subject: C=US, ST=CA, O=Apache, OU=Pulsar Incubator, CN=localhost
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (1024 bit)
+ Modulus (1024 bit):
+ 00:ea:16:8d:a5:b1:19:61:34:54:07:02:60:4e:6d:
+ 54:92:08:fd:fb:23:79:9c:05:bf:14:f7:bc:aa:db:
+ 2b:42:a4:35:74:86:e3:00:ad:8b:18:79:73:7d:f2:
+ d1:74:dd:74:bc:b8:a2:4c:80:c9:f3:80:ce:bf:f8:
+ 6d:97:f5:05:4f:f4:b2:99:50:e8:d8:b0:c4:57:a0:
+ e7:dc:82:57:75:2a:a2:02:21:76:f7:37:c2:dc:7c:
+ 4c:36:a6:73:6f:dc:75:48:72:ad:fa:98:02:70:b2:
+ 5e:a2:83:cc:c3:8d:20:a7:1e:bc:d7:1e:c1:d1:7e:
+ 39:35:4b:f5:be:6b:c1:0f:f9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ D4:7A:CD:0F:44:1B:16:29:25:14:ED:A2:EF:13:0F:A7:46:09:78:F6
+ X509v3 Authority Key Identifier:
+ keyid:D4:7A:CD:0F:44:1B:16:29:25:14:ED:A2:EF:13:0F:A7:46:09:78:F6
+ DirName:/C=US/ST=CA/O=Apache/OU=Pulsar Incubator/CN=localhost
+ serial:88:08:98:B3:13:D8:00:94
+
+ X509v3 Basic Constraints:
+ CA:TRUE
+ Signature Algorithm: sha1WithRSAEncryption
+ 5e:30:c5:7b:30:3e:1e:16:cd:ba:66:f1:2a:19:13:8a:1a:00:
+ 08:f4:1e:8c:e4:3d:57:13:65:96:bf:07:58:55:52:37:3e:aa:
+ 2c:19:de:ee:c3:92:6e:79:f3:06:0e:9a:7b:e0:02:50:c3:ef:
+ 3b:84:ea:8f:e0:f0:16:a6:a6:67:8b:be:73:0e:5d:f7:88:39:
+ d3:d4:df:85:ad:7c:c1:4f:fa:55:55:6f:c2:48:4e:8e:82:fa:
+ 72:3b:8e:9d:dc:f7:2e:9d:47:8e:e5:c9:a2:ee:b1:76:94:15:
+ 7c:7a:62:bc:06:45:fa:61:2e:33:8c:18:3e:e9:d5:90:a5:a6:
+ 80:5a
+-----BEGIN CERTIFICATE-----
+MIIC8jCCAlugAwIBAgIJAIgImLMT2ACUMA0GCSqGSIb3DQEBBQUAMFoxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIEwJDQTEPMA0GA1UEChMGQXBhY2hlMRkwFwYDVQQLExBQ
+dWxzYXIgSW5jdWJhdG9yMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTgwMjE3MDEz
+NzMzWhcNMjEwMjE2MDEzNzMzWjBaMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
+DzANBgNVBAoTBkFwYWNoZTEZMBcGA1UECxMQUHVsc2FyIEluY3ViYXRvcjESMBAG
+A1UEAxMJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqFo2l
+sRlhNFQHAmBObVSSCP37I3mcBb8U97yq2ytCpDV0huMArYsYeXN98tF03XS8uKJM
+gMnzgM6/+G2X9QVP9LKZUOjYsMRXoOfcgld1KqICIXb3N8LcfEw2pnNv3HVIcq36
+mAJwsl6ig8zDjSCnHrzXHsHRfjk1S/W+a8EP+QIDAQABo4G/MIG8MB0GA1UdDgQW
+BBTUes0PRBsWKSUU7aLvEw+nRgl49jCBjAYDVR0jBIGEMIGBgBTUes0PRBsWKSUU
+7aLvEw+nRgl49qFepFwwWjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQ8wDQYD
+VQQKEwZBcGFjaGUxGTAXBgNVBAsTEFB1bHNhciBJbmN1YmF0b3IxEjAQBgNVBAMT
+CWxvY2FsaG9zdIIJAIgImLMT2ACUMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF
+BQADgYEAXjDFezA+HhbNumbxKhkTihoACPQejOQ9VxNllr8HWFVSNz6qLBne7sOS
+bnnzBg6ae+ACUMPvO4Tqj+DwFqamZ4u+cw5d94g509Tfha18wU/6VVVvwkhOjoL6
+cjuOndz3Lp1HjuXJou6xdpQVfHpivAZF+mEuM4wYPunVkKWmgFo=
+-----END CERTIFICATE-----
diff --git a/integration-tests/certs/client-cert.pem b/integration-tests/certs/client-cert.pem
new file mode 100644
index 0000000..61847f2
--- /dev/null
+++ b/integration-tests/certs/client-cert.pem
@@ -0,0 +1,73 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 88:08:98:b3:13:d8:00:99
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, ST=CA, O=Apache, OU=Pulsar Incubator, CN=localhost
+ Validity
+ Not Before: Feb 17 02:50:05 2018 GMT
+ Not After : Nov 16 00:00:00 2030 GMT
+ Subject: C=US, ST=CA, O=Apache, OU=Apache Pulsar, CN=superUser
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:cd:43:7d:98:40:f9:b0:5b:bc:ae:db:c0:0b:ad:
+ 26:90:96:e0:62:38:ed:68:b1:70:46:3b:de:44:f9:
+ 14:51:86:10:eb:ca:90:e7:88:e8:f9:91:85:e0:dd:
+ b5:b4:14:b9:78:e3:86:d5:54:6d:68:ec:14:92:b4:
+ f8:22:5b:05:3d:ed:31:25:65:08:05:84:ca:e6:0c:
+ 21:12:58:32:c7:1a:60:a3:4f:d2:4a:9e:28:19:7c:
+ 45:84:00:8c:89:dc:de:8a:e5:4f:88:91:cc:a4:f1:
+ 81:45:4c:7d:c2:ff:e2:c1:89:c6:12:73:95:e2:36:
+ bd:db:ae:8b:5a:68:6a:90:51:de:2b:88:5f:aa:67:
+ f4:a8:e3:63:dc:be:19:82:cc:9d:7f:e6:8d:fb:82:
+ be:22:01:3d:56:13:3b:5b:04:b4:e8:c5:18:e6:2e:
+ 0d:fa:ba:4a:8d:e8:c6:5a:a1:51:9a:4a:62:d7:af:
+ dd:b4:fc:e2:d5:cd:ae:99:6c:5c:61:56:0b:d7:0c:
+ 1a:77:5c:f5:3a:6a:54:b5:9e:33:ac:a9:75:28:9a:
+ 76:af:d0:7a:57:00:1b:91:13:31:fd:42:88:21:47:
+ 05:10:01:2f:59:bb:c7:3a:d9:e1:58:4c:1b:6c:71:
+ b6:98:ef:dd:03:82:58:a3:32:dc:90:a1:b6:a6:1e:
+ e1:0b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 53:7C:D5:D1:52:97:9A:D6:D5:EA:EC:B6:0C:9B:43:39:19:73:F6:2C
+ X509v3 Authority Key Identifier:
+ keyid:D4:7A:CD:0F:44:1B:16:29:25:14:ED:A2:EF:13:0F:A7:46:09:78:F6
+
+ Signature Algorithm: sha1WithRSAEncryption
+ e4:03:82:ff:be:df:7c:73:2a:c5:8f:7d:87:ab:95:b1:2b:e5:
+ f7:41:22:4f:28:54:84:7a:cc:fe:70:89:0f:48:e5:8a:17:e1:
+ 44:ad:12:e9:a1:3a:c7:84:55:f0:7c:29:52:0a:a1:ab:cc:5b:
+ 31:e5:b2:37:73:3a:8d:f2:f1:fb:e8:f6:a2:b9:ef:11:10:f8:
+ 31:43:8f:af:ce:09:f4:cb:96:0e:d4:58:42:6e:86:ab:b9:03:
+ 19:8b:4a:6e:ef:50:c0:7e:c9:0b:1d:2b:42:bf:eb:d0:06:05:
+ 84:ea:5a:8a:22:5c:56:fa:da:2a:9f:8a:b2:90:66:8c:5e:01:
+ 87:45
+-----BEGIN CERTIFICATE-----
+MIIDLjCCApegAwIBAgIJAIgImLMT2ACZMA0GCSqGSIb3DQEBBQUAMFoxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIEwJDQTEPMA0GA1UEChMGQXBhY2hlMRkwFwYDVQQLExBQ
+dWxzYXIgSW5jdWJhdG9yMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTgwMjE3MDI1
+MDA1WhcNMzAxMTE2MDAwMDAwWjBXMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
+DzANBgNVBAoTBkFwYWNoZTEWMBQGA1UECxMNQXBhY2hlIFB1bHNhcjESMBAGA1UE
+AxMJc3VwZXJVc2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUN9
+mED5sFu8rtvAC60mkJbgYjjtaLFwRjveRPkUUYYQ68qQ54jo+ZGF4N21tBS5eOOG
+1VRtaOwUkrT4IlsFPe0xJWUIBYTK5gwhElgyxxpgo0/SSp4oGXxFhACMidzeiuVP
+iJHMpPGBRUx9wv/iwYnGEnOV4ja9266LWmhqkFHeK4hfqmf0qONj3L4Zgsydf+aN
++4K+IgE9VhM7WwS06MUY5i4N+rpKjejGWqFRmkpi16/dtPzi1c2umWxcYVYL1wwa
+d1z1OmpUtZ4zrKl1KJp2r9B6VwAbkRMx/UKIIUcFEAEvWbvHOtnhWEwbbHG2mO/d
+A4JYozLckKG2ph7hCwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf
+Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUU3zV0VKX
+mtbV6uy2DJtDORlz9iwwHwYDVR0jBBgwFoAU1HrND0QbFiklFO2i7xMPp0YJePYw
+DQYJKoZIhvcNAQEFBQADgYEA5AOC/77ffHMqxY99h6uVsSvl90EiTyhUhHrM/nCJ
+D0jlihfhRK0S6aE6x4RV8HwpUgqhq8xbMeWyN3M6jfLx++j2ornvERD4MUOPr84J
+9MuWDtRYQm6Gq7kDGYtKbu9QwH7JCx0rQr/r0AYFhOpaiiJcVvraKp+KspBmjF4B
+h0U=
+-----END CERTIFICATE-----
diff --git a/integration-tests/certs/client-key.pem b/integration-tests/certs/client-key.pem
new file mode 100644
index 0000000..3835b3e
--- /dev/null
+++ b/integration-tests/certs/client-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDNQ32YQPmwW7yu
+28ALrSaQluBiOO1osXBGO95E+RRRhhDrypDniOj5kYXg3bW0FLl444bVVG1o7BSS
+tPgiWwU97TElZQgFhMrmDCESWDLHGmCjT9JKnigZfEWEAIyJ3N6K5U+Ikcyk8YFF
+TH3C/+LBicYSc5XiNr3brotaaGqQUd4riF+qZ/So42PcvhmCzJ1/5o37gr4iAT1W
+EztbBLToxRjmLg36ukqN6MZaoVGaSmLXr920/OLVza6ZbFxhVgvXDBp3XPU6alS1
+njOsqXUomnav0HpXABuREzH9QoghRwUQAS9Zu8c62eFYTBtscbaY790DglijMtyQ
+obamHuELAgMBAAECggEBALGnokJuqiz7mTj2NSdl+6TVEOuyPbiJKpV/J4cm1XEh
+ye9qaTQcCRhH3UmcWrG75jM9KevloLRY8A1x1/lUMhtA+XJWGTU9k6a8BLut3nT4
+3X87jNTMQgSczEXNe9WudmZcxhN7rVVtOOdTpt1pP0cnCWna5HTf0D8cuLvM975j
+r1YGTjKsCF1W+tp6ZAIIMfJkUI2qBRKvSxVCSs1vZBraox3yUVnq9oRLHxZZoqOd
+d51G5phRtn6ReVPBdT8fGUBEGg3jKxTu2/vLQMUyHy0hyCAM20gzOP4FIc2g+QZU
+y42byAuc89m0OrdRWsmzHCOxcq9DwY9npaz1RscR/2ECgYEA9bHJQ0Y1afpS5gn2
+KnXenRIw9oal1utQZnohCEJ4um+K/BCEHtDnI825LPNf34IKM2rSmssvHrYN51o0
+92j9lHHXsf6MVluwsTsIu8MtNaJ1BLt96dub4ScGT6vvzObKTwsajUfIHk+FNsKq
+zps8yh1q0qyyfAcvR82+Xr6JIsMCgYEA1d+RHGewi/Ub/GCG99A1KFKsgbiIJnWB
+IFmrcyPWignhzDUcw2SV9XqAzeK8EOIHNq3e5U/tkA7aCWxtLb5UsQ8xvmwQY2cy
+X2XvSdIhO4K2PgRLgjlzZ8RHSULglqyjB2i6TjwjFl8TsRzYr6JlV6+2cMujw4Bl
+g3a8gz071BkCgYBLP7BMkmw5kRliqxph1sffg3rLhmG0eU2elTkYtoMTVqZSnRxZ
+89FW/eMBCWkLo2BMbyMhlalQ1qFbgh1GyTkhBdzx/uwsZtiu7021dAmcq6z7ThE6
+VrBfPPyJ2jcPon/DxbrUGnAIGILMSsLVlGYB4RCehZYEto6chz8O9Xw60QKBgCnd
+us1BqviqwZC04JbQJie/j09RbS2CIQXRJ9PBNzUMXCwaVYgWP5ivI1mqQcBYTqsw
+fAqNi+aAUcQ4emLS+Ec0vzsUclzTDbRJAv+DZ8f7fWtEcfeLAYFVldLMiaRVJRDF
+OnsoIII3mGY6TFyNQKNanS8VXfheQQDsFFjoera5AoGBALXYEXkESXpw4LT6qJFz
+ktQuTZDfS6LtR14/+NkYL9c5wBC4Otkg4bNbT8xGlUjethRfpkm8xRTB6zfC1/p/
+Cg6YU1cwqlkRurAhE3PEv1dCc1IDbzou8xnwqHrd6sGPDQmQ3aEtU5eJhDZKIZfx
+nQqPGK92+Jtne7+W1mFZooxs
+-----END PRIVATE KEY-----
diff --git a/integration-tests/client.conf b/integration-tests/client.conf
new file mode 100644
index 0000000..011a6dd
--- /dev/null
+++ b/integration-tests/client.conf
@@ -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.
+#
+
+# Pulsar Client configuration
+webServiceUrl=https://localhost:8443/
+brokerServiceUrl=pulsar+ssl://localhost:6651/
+tlsAllowInsecureConnection=false
+tlsTrustCertsFilePath=/pulsar/certs/cacert.pem
+authPlugin=org.apache.pulsar.client.impl.auth.AuthenticationTls
+authParams=tlsCertFile:/pulsar/certs/client-cert.pem,tlsKeyFile:/pulsar/certs/client-key.pem
+
diff --git a/integration-tests/standalone.conf b/integration-tests/standalone.conf
new file mode 100644
index 0000000..d81f493
--- /dev/null
+++ b/integration-tests/standalone.conf
@@ -0,0 +1,280 @@
+#
+# 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.
+#
+
+### --- General broker settings --- ###
+
+# Zookeeper quorum connection string
+zookeeperServers=
+
+# Deprecated. Global zookeeper quorum connection string
+globalZookeeperServers=
+
+# Configuration Store connection string
+configurationStoreServers=
+
+brokerServicePort=6650
+brokerServicePortTls=6651
+
+# Port to use to server HTTP request
+webServicePort=8080
+webServicePortTls=8443
+
+# Hostname or IP address the service binds on, default is 0.0.0.0.
+bindAddress=0.0.0.0
+
+# Hostname or IP address the service advertises to the outside world. If not set, the value of InetAddress.getLocalHost().getHostName() is used.
+advertisedAddress=localhost
+
+# Name of the cluster to which this broker belongs to
+clusterName=standalone
+
+# Zookeeper session timeout in milliseconds
+zooKeeperSessionTimeoutMillis=30000
+
+# Time to wait for broker graceful shutdown. After this time elapses, the process will be killed
+brokerShutdownTimeoutMs=3000
+
+# Enable backlog quota check. Enforces action on topic when the quota is reached
+backlogQuotaCheckEnabled=true
+
+# How often to check for topics that have reached the quota
+backlogQuotaCheckIntervalInSeconds=60
+
+# Default per-topic backlog quota limit
+backlogQuotaDefaultLimitGB=10
+
+# Enable the deletion of inactive topics
+brokerDeleteInactiveTopicsEnabled=true
+
+# How often to check for inactive topics
+brokerDeleteInactiveTopicsFrequencySeconds=60
+
+# How frequently to proactively check and purge expired messages
+messageExpiryCheckIntervalInMinutes=5
+
+# Enable check for minimum allowed client library version
+clientLibraryVersionCheckEnabled=false
+
+# Allow client libraries with no version information
+clientLibraryVersionCheckAllowUnversioned=true
+
+# Path for the file used to determine the rotation status for the broker when responding
+# to service discovery health checks
+statusFilePath=/usr/local/apache/htdocs
+
+# Max number of unacknowledged messages allowed to receive messages by a consumer on a shared subscription. Broker will stop sending
+# messages to consumer once, this limit reaches until consumer starts acknowledging messages back
+# Using a value of 0, is disabling unackeMessage limit check and consumer can receive messages without any restriction
+maxUnackedMessagesPerConsumer=50000
+
+### --- Authentication --- ###
+
+# Enable TLS
+tlsEnabled=true
+tlsCertificateFilePath=/pulsar/certs/broker-cert.pem
+tlsKeyFilePath=/pulsar/certs/broker-key.pem
+tlsTrustCertsFilePath=/pulsar/certs/cacert.pem
+tlsAllowInsecureConnection=false
+
+anonymousUserRole=anonymous
+
+# Enable authentication
+authenticationEnabled=true
+
+# Autentication provider name list, which is comma separated list of class names
+authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderTls,org.apache.pulsar.broker.authentication.AuthenticationProviderToken
+
+# Enforce authorization
+authorizationEnabled=true
+
+tokenSecretKey=file:///pulsar/tokens/secret.key
+
+# Role names that are treated as "super-user", meaning they will be able to do all admin
+# operations and publish/consume from all topics
+superUserRoles=localhost,superUser
+
+# Authentication settings of the broker itself. Used when the broker connects to other brokers,
+# either in same or other clusters
+brokerClientAuthenticationPlugin=
+brokerClientAuthenticationParameters=
+
+### --- BookKeeper Client --- ###
+
+# Authentication plugin to use when connecting to bookies
+bookkeeperClientAuthenticationPlugin=
+
+# BookKeeper auth plugin implementatation specifics parameters name and values
+bookkeeperClientAuthenticationParametersName=
+bookkeeperClientAuthenticationParameters=
+
+# Timeout for BK add / read operations
+bookkeeperClientTimeoutInSeconds=30
+
+# Speculative reads are initiated if a read request doesn't complete within a certain time
+# Using a value of 0, is disabling the speculative reads
+bookkeeperClientSpeculativeReadTimeoutInMillis=0
+
+# Enable bookies health check. Bookies that have more than the configured number of failure within
+# the interval will be quarantined for some time. During this period, new ledgers won't be created
+# on these bookies
+bookkeeperClientHealthCheckEnabled=true
+bookkeeperClientHealthCheckIntervalSeconds=60
+bookkeeperClientHealthCheckErrorThresholdPerInterval=5
+bookkeeperClientHealthCheckQuarantineTimeInSeconds=1800
+
+# Enable rack-aware bookie selection policy. BK will chose bookies from different racks when
+# forming a new bookie ensemble
+bookkeeperClientRackawarePolicyEnabled=true
+
+# Enable region-aware bookie selection policy. BK will chose bookies from
+# different regions and racks when forming a new bookie ensemble
+# If enabled, the value of bookkeeperClientRackawarePolicyEnabled is ignored
+bookkeeperClientRegionawarePolicyEnabled=false
+
+# Enable/disable reordering read sequence on reading entries.
+bookkeeperClientReorderReadSequenceEnabled=false
+
+# Enable bookie isolation by specifying a list of bookie groups to choose from. Any bookie
+# outside the specified groups will not be used by the broker
+bookkeeperClientIsolationGroups=
+
+### --- Managed Ledger --- ###
+
+# Number of bookies to use when creating a ledger
+managedLedgerDefaultEnsembleSize=1
+
+# Number of copies to store for each message
+managedLedgerDefaultWriteQuorum=1
+
+# Number of guaranteed copies (acks to wait before write is complete)
+managedLedgerDefaultAckQuorum=1
+
+# Amount of memory to use for caching data payload in managed ledger. This memory
+# is allocated from JVM direct memory and it's shared across all the topics
+# running in the same broker
+managedLedgerCacheSizeMB=1024
+
+# Threshold to which bring down the cache level when eviction is triggered
+managedLedgerCacheEvictionWatermark=0.9
+
+# Rate limit the amount of writes generated by consumer acking the messages
+managedLedgerDefaultMarkDeleteRateLimit=0.1
+
+# Max number of entries to append to a ledger before triggering a rollover
+# A ledger rollover is triggered on these conditions
+# * Either the max rollover time has been reached
+# * or max entries have been written to the ledged and at least min-time
+# has passed
+managedLedgerMaxEntriesPerLedger=50000
+
+# Minimum time between ledger rollover for a topic
+managedLedgerMinLedgerRolloverTimeMinutes=10
+
+# Maximum time before forcing a ledger rollover for a topic
+managedLedgerMaxLedgerRolloverTimeMinutes=240
+
+# Max number of entries to append to a cursor ledger
+managedLedgerCursorMaxEntriesPerLedger=50000
+
+# Max time before triggering a rollover on a cursor ledger
+managedLedgerCursorRolloverTimeInSeconds=14400
+
+
+
+### --- Load balancer --- ###
+
+# Enable load balancer
+loadBalancerEnabled=false
+
+# Strategy to assign a new bundle
+loadBalancerPlacementStrategy=weightedRandomSelection
+
+# Percentage of change to trigger load report update
+loadBalancerReportUpdateThresholdPercentage=10
+
+# maximum interval to update load report
+loadBalancerReportUpdateMaxIntervalMinutes=15
+
+# Frequency of report to collect
+loadBalancerHostUsageCheckIntervalMinutes=1
+
+# Load shedding interval. Broker periodically checks whether some traffic should be offload from
+# some over-loaded broker to other under-loaded brokers
+loadBalancerSheddingIntervalMinutes=30
+
+# Prevent the same topics to be shed and moved to other broker more that once within this timeframe
+loadBalancerSheddingGracePeriodMinutes=30
+
+# Usage threshold to determine a broker as under-loaded
+loadBalancerBrokerUnderloadedThresholdPercentage=1
+
+# Usage threshold to determine a broker as over-loaded
+loadBalancerBrokerOverloadedThresholdPercentage=85
+
+# Interval to update namespace bundle resource quotat
+loadBalancerResourceQuotaUpdateIntervalMinutes=15
+
+# Usage threshold to determine a broker is having just right level of load
+loadBalancerBrokerComfortLoadLevelPercentage=65
+
+# enable/disable namespace bundle auto split
+loadBalancerAutoBundleSplitEnabled=false
+
+# interval to detect & split hot namespace bundle
+loadBalancerNamespaceBundleSplitIntervalMinutes=15
+
+# maximum topics in a bundle, otherwise bundle split will be triggered
+loadBalancerNamespaceBundleMaxTopics=1000
+
+# maximum sessions (producers + consumers) in a bundle, otherwise bundle split will be triggered
+loadBalancerNamespaceBundleMaxSessions=1000
+
+# maximum msgRate (in + out) in a bundle, otherwise bundle split will be triggered
+loadBalancerNamespaceBundleMaxMsgRate=1000
+
+# maximum bandwidth (in + out) in a bundle, otherwise bundle split will be triggered
+loadBalancerNamespaceBundleMaxBandwidthMbytes=100
+
+# maximum number of bundles in a namespace
+loadBalancerNamespaceMaximumBundles=128
+
+### --- Replication --- ###
+
+# Enable replication metrics
+replicationMetricsEnabled=true
+
+# Max number of connections to open for each broker in a remote cluster
+# More connections host-to-host lead to better throughput over high-latency
+# links.
+replicationConnectionsPerBroker=16
+
+# Replicator producer queue size
+replicationProducerQueueSize=1000
+
+# Default message retention time
+defaultRetentionTimeInMinutes=0
+
+# Default retention size
+defaultRetentionSizeInMB=0
+
+# How often to check whether the connections are still alive
+keepAliveIntervalSeconds=30
+
+# How often broker checks for inactive topics to be deleted (topics with no subscriptions and no one connected)
+brokerServicePurgeInactiveFrequencyInSeconds=60
diff --git a/pulsar-test-service-start.sh b/pulsar-test-service-start.sh
new file mode 100755
index 0000000..47735ec
--- /dev/null
+++ b/pulsar-test-service-start.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+#
+# 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.
+#
+
+set -e
+
+SRC_DIR=$(git rev-parse --show-toplevel)
+cd $SRC_DIR
+
+IMAGE_NAME=pulsar-client-go-test:latest
+
+if [[ -f /.dockerenv ]]; then
+ # When running tests inside docker
+ PULSAR_ADMIN=/pulsar/bin/pulsar-admin
+ /pulsar/bin/pulsar-daemon start standalone --no-functions-worker --no-stream-storage
+else
+ docker build -t ${IMAGE_NAME} .
+
+ docker kill pulsar-client-go-test || true
+ docker run -d --rm --name pulsar-client-go-test \
+ -p 8080:8080 \
+ -p 6650:6650 \
+ -p 8443:8843 \
+ -p 6651:6651 \
+ ${IMAGE_NAME} \
+ /pulsar/bin/pulsar standalone \
+ --no-functions-worker --no-stream-storage
+
+ PULSAR_ADMIN="docker exec -it pulsar-client-go-test /pulsar/bin/pulsar-admin"
+fi
+
+echo "-- Wait for Pulsar service to be ready"
+until curl http://localhost:8080/metrics > /dev/null 2>&1 ; do sleep 1; done
+
+echo "-- Pulsar service is ready -- Configure permissions"
+
+# Create "standalone" cluster
+$PULSAR_ADMIN clusters create \
+ standalone \
+ --url http://localhost:8080/ \
+ --url-secure https://localhost:8443/ \
+ --broker-url pulsar://localhost:6650/ \
+ --broker-url-secure pulsar+ssl://localhost:6651/
+
+# Create "public" tenant
+$PULSAR_ADMIN tenants create public -r "anonymous" -c "standalone"
+
+# Create "public/default" with no auth required
+$PULSAR_ADMIN namespaces create public/default
+$PULSAR_ADMIN namespaces grant-permission public/default \
+ --actions produce,consume \
+ --role "anonymous"
+
+# Create "private" tenant
+$PULSAR_ADMIN tenants create private
+
+# Create "private/auth" with required authentication
+$PULSAR_ADMIN namespaces create private/auth
+$PULSAR_ADMIN namespaces grant-permission private/auth \
+ --actions produce,consume \
+ --role "token-principal"
+
+echo "-- Ready to start tests"
diff --git a/pulsar-test-service-stop.sh b/pulsar-test-service-stop.sh
new file mode 100755
index 0000000..eafccd9
--- /dev/null
+++ b/pulsar-test-service-stop.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+#
+# 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.
+#
+
+set -e
+
+SRC_DIR=$(git rev-parse --show-toplevel)
+cd $SRC_DIR
+
+IMAGE_NAME=pulsar-client-go-test:latest
+
+if [[ -f /.dockerenv ]]; then
+ # When running tests inside docker
+ /pulsar/bin/pulsar-daemon stop standalone
+else
+ docker kill pulsar-client-go-test
+fi
+
+echo "Stopped Test Pulsar Service"
[pulsar-client-go] 26/38: Use logrus in perf producer/consumer
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit e077250d12080dc8688c058df47f4e602b6088a8
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Sat May 4 13:51:38 2019 -0700
Use logrus in perf producer/consumer
---
perf/perf-consumer.go | 9 ++++-----
perf/perf-producer.go | 25 ++++++++++++-------------
2 files changed, 16 insertions(+), 18 deletions(-)
diff --git a/perf/perf-consumer.go b/perf/perf-consumer.go
index 4ffa36f..e6fdf77 100644
--- a/perf/perf-consumer.go
+++ b/perf/perf-consumer.go
@@ -22,10 +22,9 @@ package main
import (
"context"
"encoding/json"
- "fmt"
"pulsar-client-go-native/pulsar"
"github.com/spf13/cobra"
- "log"
+ log "github.com/sirupsen/logrus"
"sync/atomic"
"time"
)
@@ -55,9 +54,9 @@ func initConsumer() {
func consume() {
b, _ := json.MarshalIndent(clientArgs, "", " ")
- fmt.Println("Client config: ", string(b))
+ log.Info("Client config: ", string(b))
b, _ = json.MarshalIndent(consumeArgs, "", " ")
- fmt.Println("Consumer config: ", string(b))
+ log.Info("Consumer config: ", string(b))
client, err := pulsar.NewClient(pulsar.ClientOptions{
URL: clientArgs.ServiceUrl,
@@ -107,7 +106,7 @@ func consume() {
msgRate := float64(currentMsgReceived) / float64(10)
bytesRate := float64(currentBytesReceived) / float64(10)
- log.Printf(`Stats - Consume rate: %6.1f msg/s - %6.1f Mbps`,
+ log.Infof(`Stats - Consume rate: %6.1f msg/s - %6.1f Mbps`,
msgRate, bytesRate*8/1024/1024)
}
}
diff --git a/perf/perf-producer.go b/perf/perf-producer.go
index 8b5c0fd..c40af30 100644
--- a/perf/perf-producer.go
+++ b/perf/perf-producer.go
@@ -22,21 +22,20 @@ package main
import (
"context"
"encoding/json"
- "fmt"
"github.com/beefsack/go-rate"
"github.com/bmizerany/perks/quantile"
"github.com/spf13/cobra"
- "log"
+ log "github.com/sirupsen/logrus"
"pulsar-client-go-native/pulsar"
"time"
)
type ProduceArgs struct {
- Topic string
- Rate int
- Batching bool
- MessageSize int
- ProducerQueueSize int
+ Topic string
+ Rate int
+ BatchingTimeMillis int
+ MessageSize int
+ ProducerQueueSize int
}
var produceArgs ProduceArgs
@@ -53,16 +52,16 @@ var cmdProduce = &cobra.Command{
func initProducer() {
cmdProduce.Flags().IntVarP(&produceArgs.Rate, "rate", "r", 100, "Publish rate. Set to 0 to go unthrottled")
- cmdProduce.Flags().BoolVarP(&produceArgs.Batching, "batching", "b", true, "Enable batching")
+ cmdProduce.Flags().IntVarP(&produceArgs.BatchingTimeMillis, "batching-time", "b", 1, "Batching grouping time in millis")
cmdProduce.Flags().IntVarP(&produceArgs.MessageSize, "size", "s", 1024, "Message size")
cmdProduce.Flags().IntVarP(&produceArgs.ProducerQueueSize, "queue-size", "q", 1000, "Produce queue size")
}
func produce() {
b, _ := json.MarshalIndent(clientArgs, "", " ")
- fmt.Println("Client config: ", string(b))
+ log.Info("Client config: ", string(b))
b, _ = json.MarshalIndent(produceArgs, "", " ")
- fmt.Println("Producer config: ", string(b))
+ log.Info("Producer config: ", string(b))
client, err := pulsar.NewClient(pulsar.ClientOptions{
URL: clientArgs.ServiceUrl,
@@ -77,7 +76,7 @@ func produce() {
producer, err := client.CreateProducer(pulsar.ProducerOptions{
Topic: produceArgs.Topic,
MaxPendingMessages: produceArgs.ProducerQueueSize,
- BatchingMaxPublishDelay: 1 * time.Millisecond,
+ BatchingMaxPublishDelay: time.Millisecond * time.Duration(produceArgs.BatchingTimeMillis),
SendTimeout: 0,
BlockIfQueueFull: true,
})
@@ -110,7 +109,7 @@ func produce() {
Payload: payload,
}, func(msgID pulsar.MessageID, message *pulsar.ProducerMessage, e error) {
if e != nil {
- log.Fatal("Failed to publish", e)
+ log.WithError(e).Fatal("Failed to publish")
}
latency := time.Since(start).Seconds()
@@ -128,7 +127,7 @@ func produce() {
select {
case <-tick.C:
messageRate := float64(messagesPublished) / float64(10)
- log.Printf(`Stats - Publish rate: %6.1f msg/s - %6.1f Mbps - Latency ms: 50%% %5.1f - 95%% %5.1f - 99%% %5.1f - 99.9%% %5.1f - max %6.1f`,
+ log.Infof(`Stats - Publish rate: %6.1f msg/s - %6.1f Mbps - Latency ms: 50%% %5.1f - 95%% %5.1f - 99%% %5.1f - 99.9%% %5.1f - max %6.1f`,
messageRate,
messageRate*float64(produceArgs.MessageSize)/1024/1024*8,
q.Query(0.5)*1000,
[pulsar-client-go] 07/38: Removed internalClose method
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit d8a1dccf72b6ebfa47d1f12b129096eb42418d6a
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Sat Mar 30 11:41:13 2019 -0700
Removed internalClose method
---
pulsar/impl/connection.go | 34 ++++++++++++++++------------------
pulsar/impl/connection_reader.go | 8 ++++----
2 files changed, 20 insertions(+), 22 deletions(-)
diff --git a/pulsar/impl/connection.go b/pulsar/impl/connection.go
index 2f09690..365f1b3 100644
--- a/pulsar/impl/connection.go
+++ b/pulsar/impl/connection.go
@@ -95,7 +95,7 @@ func (c *connection) connect() (ok bool) {
c.cnx, err = net.Dial("tcp", c.physicalAddr)
if err != nil {
c.log.WithError(err).Warn("Failed to connect to broker.")
- c.internalClose()
+ c.Close()
return false
} else {
c.log = c.log.WithField("laddr", c.cnx.LocalAddr())
@@ -193,7 +193,7 @@ func (c *connection) writeCommand(cmd proto.Message) {
if _, err := c.cnx.Write(c.writeBuffer.ReadableSlice()); err != nil {
c.log.WithError(err).Warn("Failed to write on connection")
- c.internalClose()
+ c.Close()
}
}
@@ -271,7 +271,7 @@ func (c *connection) sendPing() {
// We have not received a response to the previous Ping request, the
// connection to broker is stale
c.log.Info("Detected stale connection to broker")
- c.internalClose()
+ c.Close()
return
}
@@ -288,21 +288,6 @@ func (c *connection) handlePing() {
}
func (c *connection) Close() {
- // TODO
-}
-
-func (c *connection) changeState(state connectionState) {
- c.Lock()
- c.state = state
- c.cond.Broadcast()
- c.Unlock()
-}
-
-func (c *connection) newRequestId() uint64 {
- return atomic.AddUint64(&c.requestIdGenerator, 1)
-}
-
-func (c *connection) internalClose() {
c.Lock()
defer c.Unlock()
@@ -313,6 +298,19 @@ func (c *connection) internalClose() {
c.log.Info("Connection closed")
c.cnx.Close()
c.pingTicker.Stop()
+ close(c.incomingRequests)
c.cnx = nil
}
}
+
+func (c *connection) changeState(state connectionState) {
+ c.Lock()
+ c.state = state
+ c.cond.Broadcast()
+ c.Unlock()
+}
+
+func (c *connection) newRequestId() uint64 {
+ return atomic.AddUint64(&c.requestIdGenerator, 1)
+}
+
diff --git a/pulsar/impl/connection_reader.go b/pulsar/impl/connection_reader.go
index 5bb87c6..3b45dc4 100644
--- a/pulsar/impl/connection_reader.go
+++ b/pulsar/impl/connection_reader.go
@@ -27,7 +27,7 @@ func (r *connectionReader) readFromConnection() {
cmd, headersAndPayload, err := r.readSingleCommand()
if err != nil {
r.cnx.log.WithError(err).Info("Error reading from connection")
- r.cnx.internalClose()
+ r.cnx.Close()
break
}
@@ -53,7 +53,7 @@ func (r *connectionReader) readSingleCommand() (cmd *pb.BaseCommand, headersAndP
frameSize := r.buffer.ReadUint32()
if frameSize > MaxFrameSize {
r.cnx.log.Warnf("Received too big frame size. size=%d", frameSize)
- r.cnx.internalClose()
+ r.cnx.Close()
return nil, nil, errors.New("Frame size too big")
}
@@ -96,7 +96,7 @@ func (r *connectionReader) readAtLeast(size uint32) (ok bool) {
n, err := io.ReadAtLeast(r.cnx.cnx, r.buffer.WritableSlice(), int(size))
if err != nil {
- r.cnx.internalClose()
+ r.cnx.Close()
return false
}
@@ -109,7 +109,7 @@ func (r *connectionReader) deserializeCmd(data []byte) (*pb.BaseCommand, error)
err := proto.Unmarshal(data, cmd)
if err != nil {
r.cnx.log.WithError(err).Warn("Failed to parse protobuf command")
- r.cnx.internalClose()
+ r.cnx.Close()
return nil, err
} else {
return cmd, nil
[pulsar-client-go] 27/38: Fixed releasing of semaphore for each
send request
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit b329bbff4d8a86c12c3b673d8ee7c612439ec6ae
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Sat May 4 15:45:02 2019 -0700
Fixed releasing of semaphore for each send request
---
pulsar/impl_partition_producer.go | 2 +-
pulsar/producer_test.go | 53 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 53 insertions(+), 2 deletions(-)
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index 7b32fdc..5f3f671 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -313,11 +313,11 @@ func (p *partitionProducer) ReceivedSendReceipt(response *pb.CommandSendReceipt)
// The ack was indeed for the expected item in the queue, we can remove it and trigger the callback
p.pendingQueue.Poll()
- p.publishSemaphore.Release()
for _, i := range pi.sendRequests {
sr := i.(*sendRequest)
atomic.StoreInt64(&p.lastSequenceID, int64(pi.sequenceId))
if sr.callback != nil {
+ p.publishSemaphore.Release()
sr.callback(nil, sr.msg, nil)
}
}
diff --git a/pulsar/producer_test.go b/pulsar/producer_test.go
index fa197b4..f7455ce 100644
--- a/pulsar/producer_test.go
+++ b/pulsar/producer_test.go
@@ -2,8 +2,12 @@ package pulsar
import (
"context"
+ log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
+ "pulsar-client-go-native/pulsar/impl/util"
+ "sync"
"testing"
+ "time"
)
func TestSimpleProducer(t *testing.T) {
@@ -34,6 +38,53 @@ func TestSimpleProducer(t *testing.T) {
assert.NoError(t, err)
}
+func TestProducerAsyncSend(t *testing.T) {
+ client, err := NewClient(ClientOptions{
+ URL: serviceUrl,
+ })
+ assert.NoError(t, err)
+
+ producer, err := client.CreateProducer(ProducerOptions{
+ Topic: newTopicName(),
+ BatchingMaxPublishDelay: 1 * time.Second,
+ })
+
+ assert.NoError(t, err)
+ assert.NotNil(t, producer)
+
+ wg := sync.WaitGroup{}
+ wg.Add(10)
+ errors := util.NewBlockingQueue(10)
+
+ for i := 0; i < 10; i++ {
+ producer.SendAsync(context.Background(), &ProducerMessage{
+ Payload: []byte("hello"),
+ }, func(id MessageID, message *ProducerMessage, e error) {
+ if e != nil {
+ log.WithError(e).Error("Failed to publish")
+ errors.Put(e)
+ } else {
+ log.Info("Published message ", id)
+ }
+ wg.Done()
+ })
+
+ assert.NoError(t, err)
+ }
+
+ producer.Flush()
+
+ wg.Wait()
+
+ assert.Equal(t, 0, errors.Size())
+
+ err = producer.Close()
+ assert.NoError(t, err)
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
+
func TestProducerCompression(t *testing.T) {
type testProvider struct {
@@ -108,4 +159,4 @@ func TestProducerLastSequenceID(t *testing.T) {
err = client.Close()
assert.NoError(t, err)
-}
\ No newline at end of file
+}
[pulsar-client-go] 01/38: Initial commit
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit d74beea1bccf552ef81854b5ab559a64019d7ba8
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Mon May 6 15:13:04 2019 -0700
Initial commit
---
README.md | 0
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29
[pulsar-client-go] 15/38: Handle cases with no-batching
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 9522dd53c29f25b2f5b86c4ec3fecc8c4955133e
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Wed Apr 10 16:32:23 2019 -0700
Handle cases with no-batching
---
pulsar/impl/batch_builder.go | 16 ++++++++--
pulsar/impl/commands.go | 2 +-
pulsar/impl_partition_producer.go | 66 +++++++++++++++++++++++++--------------
pulsar/producer.go | 6 ++--
4 files changed, 61 insertions(+), 29 deletions(-)
diff --git a/pulsar/impl/batch_builder.go b/pulsar/impl/batch_builder.go
index 7a16155..e8c0af8 100644
--- a/pulsar/impl/batch_builder.go
+++ b/pulsar/impl/batch_builder.go
@@ -61,8 +61,16 @@ func (bb *BatchBuilder) hasSpace(payload []byte) bool {
}
func (bb *BatchBuilder) Add(metadata *pb.SingleMessageMetadata, sequenceId uint64, payload []byte,
- callback interface{}) bool {
- if bb.hasSpace(payload) {
+ callback interface{}, replicateTo []string, ) bool {
+ if replicateTo != nil && bb.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 bb.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 bb.hasSpace(payload) {
// The current batch is full. Producer has to call Flush() to
return false
}
@@ -72,10 +80,11 @@ func (bb *BatchBuilder) Add(metadata *pb.SingleMessageMetadata, sequenceId uint6
bb.msgMetadata.PublishTime = proto.Uint64(TimestampMillis(time.Now()))
bb.msgMetadata.SequenceId = proto.Uint64(sequenceId)
bb.msgMetadata.ProducerName = &bb.producerName
+ bb.msgMetadata.ReplicateTo = replicateTo
bb.cmdSend.Send.SequenceId = proto.Uint64(sequenceId)
}
- serializeSingleMessage(bb.buffer, metadata, payload)
+ addSingleMessageToBatch(bb.buffer, metadata, payload)
bb.numMessages += 1
bb.callbacks = append(bb.callbacks, callback)
@@ -86,6 +95,7 @@ func (bb *BatchBuilder) reset() {
bb.numMessages = 0
bb.buffer.Clear()
bb.callbacks = []interface{}{}
+ bb.msgMetadata.ReplicateTo = nil
}
func (bb *BatchBuilder) Flush() (batchData []byte, sequenceId uint64, callbacks []interface{}) {
diff --git a/pulsar/impl/commands.go b/pulsar/impl/commands.go
index 6b1c840..08f8124 100644
--- a/pulsar/impl/commands.go
+++ b/pulsar/impl/commands.go
@@ -36,7 +36,7 @@ func baseCommand(cmdType pb.BaseCommand_Type, msg proto.Message) *pb.BaseCommand
return cmd
}
-func serializeSingleMessage(wb Buffer, smm *pb.SingleMessageMetadata, payload []byte) {
+func addSingleMessageToBatch(wb Buffer, smm *pb.SingleMessageMetadata, payload []byte) {
serialized, err := proto.Marshal(smm)
if err != nil {
log.WithError(err).Fatal("Protobuf serialization error")
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index 5f50296..d0cd8cf 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -158,6 +158,8 @@ func (p *partitionProducer) runEventsLoop() {
p.internalSend(v)
case *connectionClosed:
p.reconnectToBroker()
+ case *closeProducer:
+ p.internalClose(v)
}
case _ = <-p.batchFlushTicker.C:
@@ -179,30 +181,38 @@ func (p *partitionProducer) internalSend(request *sendRequest) {
msg := request.msg
- if msg.ReplicationClusters == nil {
- smm := &pb.SingleMessageMetadata{
- PayloadSize: proto.Int(len(msg.Payload)),
- }
+ sendAsBatch := !p.options.DisableBatching && request.msg.ReplicationClusters == nil
+ smm := &pb.SingleMessageMetadata{
+ PayloadSize: proto.Int(len(msg.Payload)),
+ }
- if msg.EventTime != nil {
- smm.EventTime = proto.Uint64(impl.TimestampMillis(*msg.EventTime))
- }
+ if msg.EventTime != nil {
+ smm.EventTime = proto.Uint64(impl.TimestampMillis(*msg.EventTime))
+ }
- if msg.Key != "" {
- smm.PartitionKey = &msg.Key
- }
+ if msg.Key != "" {
+ smm.PartitionKey = &msg.Key
+ }
- if msg.Properties != nil {
- smm.Properties = impl.ConvertFromStringMap(msg.Properties)
- }
+ if msg.Properties != nil {
+ smm.Properties = impl.ConvertFromStringMap(msg.Properties)
+ }
- sequenceId := impl.GetAndAdd(p.sequenceIdGenerator, 1)
- for ; p.batchBuilder.Add(smm, sequenceId, msg.Payload, request) == false; {
+ sequenceId := impl.GetAndAdd(p.sequenceIdGenerator, 1)
+
+ if sendAsBatch {
+ for ; p.batchBuilder.Add(smm, sequenceId, msg.Payload, request, msg.ReplicationClusters) == false; {
// The current batch is full.. flush it and retry
p.internalFlush()
}
} else {
- p.log.Panic("TODO: serialize into single message")
+ // Send individually
+ p.batchBuilder.Add(smm, sequenceId, msg.Payload, request, msg.ReplicationClusters)
+ p.internalFlush()
+ }
+
+ if request.flushImmediately {
+ p.internalFlush()
}
}
@@ -228,10 +238,10 @@ func (p *partitionProducer) Send(ctx context.Context, msg *ProducerMessage) erro
var err error
- p.SendAsync(ctx, msg, func(ID MessageID, message *ProducerMessage, e error) {
+ p.internalSendAsync(ctx, msg, func(ID MessageID, message *ProducerMessage, e error) {
err = e
wg.Done()
- })
+ }, true)
// When sending synchronously we flush immediately to avoid
// the increased latency and reduced throughput of batching
@@ -246,7 +256,13 @@ func (p *partitionProducer) Send(ctx context.Context, msg *ProducerMessage) erro
func (p *partitionProducer) SendAsync(ctx context.Context, msg *ProducerMessage,
callback func(MessageID, *ProducerMessage, error)) {
p.publishSemaphore.Acquire()
- p.eventsChan <- &sendRequest{ctx, msg, callback}
+ p.eventsChan <- &sendRequest{ctx, msg, callback, false}
+}
+
+func (p *partitionProducer) internalSendAsync(ctx context.Context, msg *ProducerMessage,
+ callback func(MessageID, *ProducerMessage, error), flushImmediately bool) {
+ p.publishSemaphore.Acquire()
+ p.eventsChan <- &sendRequest{ctx, msg, callback, flushImmediately}
}
func (p *partitionProducer) ReceivedSendReceipt(response *pb.CommandSendReceipt) {
@@ -264,7 +280,7 @@ func (p *partitionProducer) ReceivedSendReceipt(response *pb.CommandSendReceipt)
// The ack was indeed for the expected item in the queue, we can remove it and trigger the callback
p.pendingQueue.Poll()
p.publishSemaphore.Release()
- for _ ,i := range pi.sendRequest {
+ for _, i := range pi.sendRequest {
sr := i.(*sendRequest)
sr.callback(nil, sr.msg, nil)
}
@@ -285,7 +301,11 @@ func (p *partitionProducer) Close() error {
}
type sendRequest struct {
- ctx context.Context
- msg *ProducerMessage
- callback func(MessageID, *ProducerMessage, error)
+ ctx context.Context
+ msg *ProducerMessage
+ callback func(MessageID, *ProducerMessage, error)
+ flushImmediately bool
}
+
+type closeProducer struct {
+}
\ No newline at end of file
diff --git a/pulsar/producer.go b/pulsar/producer.go
index 0e59e66..8eaf340 100644
--- a/pulsar/producer.go
+++ b/pulsar/producer.go
@@ -130,7 +130,8 @@ type ProducerOptions struct {
// partition index where the message should be routed to
MessageRouter func(Message, TopicMetadata) int
- // Control whether automatic batching of messages is enabled for the producer. Default: false [No batching]
+ // Control 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,
@@ -138,7 +139,8 @@ type ProducerOptions struct {
// contents.
//
// When enabled default batch delay is set to 1 ms and default batch size is 1000 messages
- Batching bool
+ // Setting `DisableBatching: true` will make the producer to send messages individually
+ DisableBatching bool
// Set 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
[pulsar-client-go] 12/38: Queue sending requests and trigger
callbacks
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 7851714fb75ab9e62f50f064f9db948d6956f890
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Wed Apr 10 14:26:11 2019 -0700
Queue sending requests and trigger callbacks
---
pulsar/impl/batch_builder.go | 15 ++++++---
pulsar/impl/connection.go | 25 +++++++++++----
pulsar/impl/util/semaphore.go | 11 +++++++
pulsar/impl_partition_producer.go | 65 +++++++++++++++++++++++++++++++--------
pulsar/message.go | 2 +-
5 files changed, 95 insertions(+), 23 deletions(-)
diff --git a/pulsar/impl/batch_builder.go b/pulsar/impl/batch_builder.go
index 53bf081..7a16155 100644
--- a/pulsar/impl/batch_builder.go
+++ b/pulsar/impl/batch_builder.go
@@ -27,6 +27,7 @@ type BatchBuilder struct {
cmdSend *pb.BaseCommand
msgMetadata *pb.MessageMetadata
+ callbacks []interface{}
}
func NewBatchBuilder(maxMessages uint, producerName string, producerId uint64) *BatchBuilder {
@@ -46,6 +47,7 @@ func NewBatchBuilder(maxMessages uint, producerName string, producerId uint64) *
msgMetadata: &pb.MessageMetadata{
ProducerName: &producerName,
},
+ callbacks: []interface{}{},
}
}
@@ -58,7 +60,8 @@ func (bb *BatchBuilder) hasSpace(payload []byte) bool {
return bb.numMessages > 0 && (bb.buffer.ReadableBytes()+msgSize) > MaxBatchSize
}
-func (bb *BatchBuilder) Add(metadata *pb.SingleMessageMetadata, sequenceId uint64, payload []byte) bool {
+func (bb *BatchBuilder) Add(metadata *pb.SingleMessageMetadata, sequenceId uint64, payload []byte,
+ callback interface{}) bool {
if bb.hasSpace(payload) {
// The current batch is full. Producer has to call Flush() to
return false
@@ -75,19 +78,21 @@ func (bb *BatchBuilder) Add(metadata *pb.SingleMessageMetadata, sequenceId uint6
serializeSingleMessage(bb.buffer, metadata, payload)
bb.numMessages += 1
+ bb.callbacks = append(bb.callbacks, callback)
return true
}
func (bb *BatchBuilder) reset() {
bb.numMessages = 0
bb.buffer.Clear()
+ bb.callbacks = []interface{}{}
}
-func (bb *BatchBuilder) Flush() []byte {
+func (bb *BatchBuilder) Flush() (batchData []byte, sequenceId uint64, callbacks []interface{}) {
log.Debug("BatchBuilder flush: messages: ", bb.numMessages)
if bb.numMessages == 0 {
// No-Op for empty batch
- return nil
+ return nil, 0, nil
}
bb.msgMetadata.NumMessagesInBatch = proto.Int32(int32(bb.numMessages))
@@ -96,6 +101,8 @@ func (bb *BatchBuilder) Flush() []byte {
buffer := NewBuffer(4096)
serializeBatch(buffer, bb.cmdSend, bb.msgMetadata, bb.buffer.ReadableSlice())
+ callbacks = bb.callbacks
+ sequenceId = bb.cmdSend.Send.GetSequenceId()
bb.reset()
- return buffer.ReadableSlice()
+ return buffer.ReadableSlice(), sequenceId, callbacks
}
diff --git a/pulsar/impl/connection.go b/pulsar/impl/connection.go
index 18a3b63..fa32889 100644
--- a/pulsar/impl/connection.go
+++ b/pulsar/impl/connection.go
@@ -16,13 +16,15 @@ import (
// a consumer) that can register itself to get notified
// when the connection is closed.
type ConnectionListener interface {
+ ReceivedSendReceipt(response *pb.CommandSendReceipt)
+
ConnectionClosed()
}
type Connection interface {
SendRequest(requestId uint64, req *pb.BaseCommand, callback func(command *pb.BaseCommand))
WriteData(data []byte)
- RegisterListener(listener ConnectionListener)
+ RegisterListener(id uint64, listener ConnectionListener)
Close()
}
@@ -65,7 +67,7 @@ type connection struct {
incomingRequests chan *request
writeRequests chan []byte
pendingReqs map[uint64]*request
- listeners []ConnectionListener
+ listeners map[uint64]ConnectionListener
}
func newConnection(logicalAddr *url.URL, physicalAddr *url.URL) *connection {
@@ -81,7 +83,7 @@ func newConnection(logicalAddr *url.URL, physicalAddr *url.URL) *connection {
incomingRequests: make(chan *request),
writeRequests: make(chan []byte),
- listeners: make([]ConnectionListener, 0),
+ listeners: make(map[uint64]ConnectionListener),
}
cnx.reader = newConnectionReader(cnx)
cnx.cond = sync.NewCond(cnx)
@@ -263,8 +265,9 @@ func (c *connection) receivedCommand(cmd *pb.BaseCommand, headersAndPayload []by
case pb.BaseCommand_ERROR:
case pb.BaseCommand_CLOSE_PRODUCER:
case pb.BaseCommand_CLOSE_CONSUMER:
+
case pb.BaseCommand_SEND_RECEIPT:
- c.log.Info("Got SEND_RECEIPT: ", cmd.GetSendReceipt())
+ c.handleSendReceipt(cmd.GetSendReceipt())
case pb.BaseCommand_SEND_ERROR:
@@ -310,6 +313,16 @@ func (c *connection) handleResponse(requestId uint64, response *pb.BaseCommand)
request.callback(response)
}
+func (c *connection) handleSendReceipt(response *pb.CommandSendReceipt) {
+ c.log.Debug("Got SEND_RECEIPT: ", response)
+ producerId := response.GetProducerId()
+ if producer, ok := c.listeners[producerId]; ok {
+ producer.ReceivedSendReceipt(response)
+ } else {
+ c.log.WithField("producerId", producerId).Warn("Got unexpected send receipt for message: ", response.MessageId)
+ }
+}
+
func (c *connection) sendPing() {
if c.lastDataReceivedTime.Add(2 * keepAliveInterval).Before(time.Now()) {
// We have not received a response to the previous Ping request, the
@@ -331,11 +344,11 @@ func (c *connection) handlePing() {
c.writeCommand(baseCommand(pb.BaseCommand_PONG, &pb.CommandPong{}))
}
-func (c *connection) RegisterListener(listener ConnectionListener) {
+func (c *connection) RegisterListener(id uint64, listener ConnectionListener) {
c.Lock()
defer c.Unlock()
- c.listeners = append(c.listeners, listener)
+ c.listeners[id] = listener
}
func (c *connection) Close() {
diff --git a/pulsar/impl/util/semaphore.go b/pulsar/impl/util/semaphore.go
new file mode 100644
index 0000000..9df8cd1
--- /dev/null
+++ b/pulsar/impl/util/semaphore.go
@@ -0,0 +1,11 @@
+package util
+
+type Semaphore chan bool
+
+func (s Semaphore) Acquire() {
+ s <- true
+}
+
+func (s Semaphore) Release() {
+ <-s
+}
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index 60ae76c..cdd34d5 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -5,6 +5,7 @@ import (
"github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
"pulsar-client-go-native/pulsar/impl"
+ "pulsar-client-go-native/pulsar/impl/util"
pb "pulsar-client-go-native/pulsar/pulsar_proto"
"sync"
"time"
@@ -27,6 +28,9 @@ type partitionProducer struct {
// Channel where app is posting messages to be published
eventsChan chan interface{}
+
+ publishSemaphore util.Semaphore
+ pendingQueue util.BlockingQueue
}
const defaultBatchingMaxPublishDelay = 10 * time.Millisecond
@@ -40,6 +44,13 @@ func newPartitionProducer(client *client, topic string, options *ProducerOptions
batchingMaxPublishDelay = defaultBatchingMaxPublishDelay
}
+ var maxPendingMessages int
+ if options.MaxPendingMessages == 0 {
+ maxPendingMessages = 1000
+ } else {
+ maxPendingMessages = options.MaxPendingMessages
+ }
+
p := &partitionProducer{
log: log.WithField("topic", topic),
client: client,
@@ -48,6 +59,8 @@ func newPartitionProducer(client *client, topic string, options *ProducerOptions
producerId: client.rpcClient.NewProducerId(),
eventsChan: make(chan interface{}),
batchFlushTicker: time.NewTicker(batchingMaxPublishDelay),
+ publishSemaphore: make(util.Semaphore, maxPendingMessages),
+ pendingQueue: util.NewBlockingQueue(maxPendingMessages),
}
if options.Name != "" {
@@ -61,7 +74,7 @@ func newPartitionProducer(client *client, topic string, options *ProducerOptions
} else {
p.log = p.log.WithField("name", *p.producerName)
p.log.Info("Created producer")
- go p.run()
+ go p.runEventsLoop()
return p, nil
}
}
@@ -99,7 +112,7 @@ func (p *partitionProducer) grabCnx() error {
p.sequenceIdGenerator = &nextSequenceId
}
p.cnx = res.Cnx
- p.cnx.RegisterListener(p)
+ p.cnx.RegisterListener(p.producerId, p)
p.log.WithField("cnx", res.Cnx).Debug("Connected producer")
return nil
}
@@ -128,8 +141,7 @@ func (p *partitionProducer) reconnectToBroker() {
}
}
-
-func (p *partitionProducer) run() {
+func (p *partitionProducer) runEventsLoop() {
for {
select {
case i := <-p.eventsChan:
@@ -177,7 +189,7 @@ func (p *partitionProducer) internalSend(request *sendRequest) {
}
sequenceId := impl.GetAndAdd(p.sequenceIdGenerator, 1)
- for ; p.batchBuilder.Add(smm, sequenceId, msg.Payload) == false; {
+ for ; p.batchBuilder.Add(smm, sequenceId, msg.Payload, request) == false; {
// The current batch is full.. flush it and retry
p.internalFlush()
}
@@ -186,12 +198,19 @@ func (p *partitionProducer) internalSend(request *sendRequest) {
}
}
+type pendingItem struct {
+ batchData []byte
+ sequenceId uint64
+ sendRequest []interface{}
+}
+
func (p *partitionProducer) internalFlush() {
- batchData := p.batchBuilder.Flush()
+ batchData, sequenceId, callbacks := p.batchBuilder.Flush()
if batchData == nil {
return
}
+ p.pendingQueue.Put(&pendingItem{batchData, sequenceId, callbacks})
p.cnx.WriteData(batchData)
}
@@ -216,14 +235,30 @@ func (p *partitionProducer) Send(ctx context.Context, msg *ProducerMessage) erro
return err
}
-type sendRequest struct {
- ctx context.Context
- msg *ProducerMessage
- callback func(MessageID, *ProducerMessage, error)
+func (p *partitionProducer) SendAsync(ctx context.Context, msg *ProducerMessage,
+ callback func(MessageID, *ProducerMessage, error)) {
+ p.publishSemaphore.Acquire()
+ p.eventsChan <- &sendRequest{ctx, msg, callback}
}
-func (p *partitionProducer) SendAsync(ctx context.Context, msg *ProducerMessage, callback func(MessageID, *ProducerMessage, error)) {
- p.eventsChan <- &sendRequest{ctx, msg, callback}
+func (p *partitionProducer) ReceivedSendReceipt(response *pb.CommandSendReceipt) {
+ pi := p.pendingQueue.Peek().(*pendingItem)
+
+ if pi == nil {
+ p.log.Warnf("Received ack for %v although the pending queue is empty", response.GetMessageId())
+ return
+ } else if pi.sequenceId != response.GetSequenceId() {
+ p.log.Warnf("Received ack for %v on sequenceId %v - expected: %v", response.GetMessageId(),
+ response.GetSequenceId(), pi.sequenceId)
+ return
+ }
+
+ // The ack was indeed for the expected item in the queue, we can remove it and trigger the callback
+ p.pendingQueue.Poll()
+ for _ ,i := range pi.sendRequest {
+ sr := i.(*sendRequest)
+ sr.callback(nil, sr.msg, nil)
+ }
}
func (p *partitionProducer) LastSequenceID() int64 {
@@ -239,3 +274,9 @@ func (p *partitionProducer) Close() error {
p.log.Info("Closing producer")
return nil
}
+
+type sendRequest struct {
+ ctx context.Context
+ msg *ProducerMessage
+ callback func(MessageID, *ProducerMessage, error)
+}
diff --git a/pulsar/message.go b/pulsar/message.go
index 12bc269..e987ad1 100644
--- a/pulsar/message.go
+++ b/pulsar/message.go
@@ -82,7 +82,7 @@ func DeserializeMessageID(data []byte) MessageID {
}
var (
-// MessageID that points to the earliest message avaialable in a topic
+// MessageID that points to the earliest message available in a topic
// TODO: EarliestMessage MessageID = earliestMessageID()
// MessageID that points to the latest message
[pulsar-client-go] 02/38: Initial import
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 84cb32ea75fbc322d107995620681e0d6feff202
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Wed Mar 27 09:34:18 2019 -0700
Initial import
---
.gitignore | 1 +
pulsar/client.go | 111 +
pulsar/consumer.go | 179 ++
pulsar/error.go | 80 +
pulsar/impl/batch_builder.go | 23 +
pulsar/impl/buffer.go | 119 ++
pulsar/impl/buffer_test.go | 19 +
pulsar/impl/closable.go | 5 +
pulsar/impl/commands.go | 33 +
pulsar/impl/connection.go | 293 +++
pulsar/impl/connection_pool.go | 54 +
pulsar/impl/connection_reader.go | 117 +
pulsar/impl/default_router.go | 26 +
pulsar/impl/lookup_service.go | 62 +
pulsar/impl/rpc_client.go | 71 +
pulsar/impl/topic_name.go | 88 +
pulsar/impl/topic_name_test.go | 68 +
pulsar/impl_client.go | 98 +
pulsar/impl_partition_producer.go | 88 +
pulsar/impl_producer.go | 123 ++
pulsar/message.go | 90 +
pulsar/producer.go | 187 ++
pulsar/pulsar_proto/PulsarApi.pb.go | 4043 +++++++++++++++++++++++++++++++++++
pulsar/reader.go | 84 +
24 files changed, 6062 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..723ef36
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.idea
\ No newline at end of file
diff --git a/pulsar/client.go b/pulsar/client.go
new file mode 100644
index 0000000..21db637
--- /dev/null
+++ b/pulsar/client.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 (
+ "time"
+)
+
+func NewClient(options ClientOptions) (Client, error) {
+ return newClient(options)
+}
+
+// Opaque interface that represents the authentication credentials
+type Authentication interface {}
+
+// Create new Authentication provider with specified auth token
+func NewAuthenticationToken(token string) Authentication {
+ // TODO: return newAuthenticationToken(token)
+ return nil
+}
+
+// Create new Authentication provider with specified auth token supplier
+func NewAuthenticationTokenSupplier(tokenSupplier func() string) Authentication {
+ // TODO: return newAuthenticationTokenSupplier(tokenSupplier)
+ return nil
+}
+
+// Create new Authentication provider with specified TLS certificate and private key
+func NewAuthenticationTLS(certificatePath string, privateKeyPath string) Authentication {
+ // TODO: return newAuthenticationTLS(certificatePath, privateKeyPath)
+ return nil
+}
+
+// Create new Athenz Authentication provider with configuration in JSON form
+func NewAuthenticationAthenz(authParams string) Authentication {
+ // TODO: return newAuthenticationAthenz(authParams)
+ return nil
+}
+
+// Builder interface that 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
+
+ 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 authentication provider. (default: no authentication)
+ // Example: `Authentication: NewAuthenticationTLS("my-cert.pem", "my-key.pem")`
+ Authentication
+
+ // 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
+}
+
+type Client interface {
+ // Create the producer instance
+ // This method will block until the producer is created successfully
+ CreateProducer(ProducerOptions) (Producer, error)
+
+ // Create 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)
+
+ // Create a Reader instance.
+ // This method will block until the reader is created successfully.
+ CreateReader(ReaderOptions) (Reader, error)
+
+ // Fetch 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 the Client and free associated resources
+ Close() error
+}
diff --git a/pulsar/consumer.go b/pulsar/consumer.go
new file mode 100644
index 0000000..b32e5fc
--- /dev/null
+++ b/pulsar/consumer.go
@@ -0,0 +1,179 @@
+//
+// 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"
+)
+
+// Pair of a Consumer and Message
+type ConsumerMessage struct {
+ Consumer
+ Message
+}
+
+// Types of subscription supported by Pulsar
+type SubscriptionType int
+
+const (
+ // There can be only 1 consumer on the same topic with the same subscription name
+ Exclusive SubscriptionType = iota
+
+ // 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
+
+ // 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
+)
+
+type InitialPosition int
+
+const (
+ // Latest position which means the start consuming position will be the last message
+ Latest InitialPosition = iota
+
+ // Earliest position which means the start consuming position will be the first message
+ Earliest
+)
+
+// ConsumerBuilder is used to configure and create instances of Consumer
+type ConsumerOptions struct {
+ // Specify the topic this consumer will subscribe on.
+ // Either a topic, a list of topics or a topics pattern are required when subscribing
+ Topic string
+
+ // Specify 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
+
+ // Specify 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
+
+ // Specify the subscription name for this consumer
+ // This argument is required when subscribing
+ SubscriptionName string
+
+ // Attach a set of application defined properties to the consumer
+ // This properties will be visible in the topic stats
+ Properties map[string]string
+
+ // Set the timeout for unacked messages
+ // Message not acknowledged within the give time, will be replayed by the broker to the same or a different consumer
+ // Default is 0, which means message are not being replayed based on ack time
+ AckTimeout time.Duration
+
+ // Select the subscription type to be used when subscribing to the topic.
+ // Default is `Exclusive`
+ Type SubscriptionType
+
+ // InitialPosition at which the cursor will be set when subscribe
+ // Default is `Latest`
+ SubscriptionInitPos InitialPosition
+
+ // Sets a `MessageChannel` for the consumer
+ // When a message is received, it will be pushed to the channel for consumption
+ MessageChannel chan ConsumerMessage
+
+ // 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.
+ // Set to -1 to disable prefetching in consumer
+ ReceiverQueueSize int
+
+ // Set the max total receiver queue size across partitions.
+ // This setting will be used to reduce the receiver queue size for individual partitions
+ // ReceiverQueueSize(int) if the total exceeds this value (default: 50000).
+ MaxTotalReceiverQueueSizeAcrossPartitions int
+
+ // Set the consumer name.
+ Name string
+
+ // 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
+}
+
+// An interface that abstracts behavior of Pulsar's consumer
+type Consumer interface {
+ // Get the topic for the consumer
+ Topic() string
+
+ // Get a subscription for the consumer
+ Subscription() string
+
+ // Unsubscribe the consumer
+ Unsubscribe() error
+
+ // Receives a single message.
+ // This calls blocks until a message is available.
+ Receive(context.Context) (Message, error)
+
+ // Ack the consumption of a single message
+ Ack(Message) error
+
+ // Ack the consumption of a single message, identified by its MessageID
+ AckID(MessageID) error
+
+ // Ack the reception of all the messages in the stream up to (and including) the provided message.
+ // This method will block until the acknowledge has been sent to the broker. After that, the messages will not be
+ // re-delivered to this consumer.
+ //
+ // Cumulative acknowledge cannot be used when the consumer type is set to ConsumerShared.
+ //
+ // It's equivalent to calling asyncAcknowledgeCumulative(Message) and waiting for the callback to be triggered.
+ AckCumulative(Message) error
+
+ // Ack the reception of all the messages in the stream up to (and including) the provided message.
+ // This method will block until the acknowledge has been sent to the broker. After that, the messages will not be
+ // re-delivered to this consumer.
+ //
+ // Cumulative acknowledge cannot be used when the consumer type is set to ConsumerShared.
+ //
+ // It's equivalent to calling asyncAcknowledgeCumulative(MessageID) and waiting for the callback to be triggered.
+ AckCumulativeID(MessageID) error
+
+ // Close the consumer and stop the broker to push more messages
+ Close() error
+
+ // Reset 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(msgID MessageID) error
+
+ // Redelivers all the unacknowledged messages. In Failover mode, the request is ignored if the consumer is not
+ // active for the given topic. In Shared mode, the consumers messages to be redelivered are distributed across all
+ // the connected consumers. This is a non blocking call and doesn't throw an exception. In case the connection
+ // breaks, the messages are redelivered after reconnect.
+ RedeliverUnackedMessages()
+}
diff --git a/pulsar/error.go b/pulsar/error.go
new file mode 100644
index 0000000..929b250
--- /dev/null
+++ b/pulsar/error.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 pulsar
+import "C"
+import "fmt"
+
+type Result int
+
+const (
+ UnknownError Result = 1 // Unknown error happened on broker
+ InvalidConfiguration Result = 2 // Invalid configuration
+ TimeoutError Result = 3 // Operation timed out
+ LookupError Result = 4 // Broker lookup failed
+ ConnectError Result = 5 // Failed to connect to broker
+ ReadError Result = 6 // Failed to read from socket
+ AuthenticationError Result = 7 // Authentication failed on broker
+ AuthorizationError Result = 8 // Client is not authorized to create producer/consumer
+ ErrorGettingAuthenticationData Result = 9 // Client cannot find authorization data
+ BrokerMetadataError Result = 10 // Broker failed in updating metadata
+ BrokerPersistenceError Result = 11 // Broker failed to persist entry
+ ChecksumError Result = 12 // Corrupt message checksum failure
+ ConsumerBusy Result = 13 // Exclusive consumer is already connected
+ NotConnectedError Result = 14 // Producer/Consumer is not currently connected to broker
+ AlreadyClosedError Result = 15 // Producer/Consumer is already closed and not accepting any operation
+ InvalidMessage Result = 16 // Error in publishing an already used message
+ ConsumerNotInitialized Result = 17 // Consumer is not initialized
+ ProducerNotInitialized Result = 18 // Producer is not initialized
+ TooManyLookupRequestException Result = 19 // Too Many concurrent LookupRequest
+ InvalidTopicName Result = 20 // Invalid topic name
+ InvalidUrl Result = 21 // Client Initialized with Invalid Broker Url (VIP Url passed to Client Constructor)
+ ServiceUnitNotReady Result = 22 // Service Unit unloaded between client did lookup and producer/consumer got created
+ OperationNotSupported Result = 23
+ ProducerBlockedQuotaExceededError Result = 24 // Producer is blocked
+ ProducerBlockedQuotaExceededException Result = 25 // Producer is getting exception
+ ProducerQueueIsFull Result = 26 // Producer queue is full
+ MessageTooBig Result = 27 // Trying to send a messages exceeding the max size
+ TopicNotFound Result = 28 // Topic not found
+ SubscriptionNotFound Result = 29 // Subscription not found
+ ConsumerNotFound Result = 30 // Consumer not found
+ UnsupportedVersionError Result = 31 // Error when an older client/version doesn't support a required feature
+ TopicTerminated Result = 32 // Topic was already terminated
+ CryptoError Result = 33 // Error when crypto operation fails
+)
+
+type Error struct {
+ msg string
+ result 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: %d", msg, result),
+ result: result,
+ }
+}
\ No newline at end of file
diff --git a/pulsar/impl/batch_builder.go b/pulsar/impl/batch_builder.go
new file mode 100644
index 0000000..7eb2030
--- /dev/null
+++ b/pulsar/impl/batch_builder.go
@@ -0,0 +1,23 @@
+package impl
+
+type BatchBuilder struct {
+ buffer Buffer
+}
+
+func NewBatchBuilder() *BatchBuilder {
+ return &BatchBuilder{
+ buffer: NewBuffer(4096),
+ }
+}
+
+func (bb *BatchBuilder) isFull() bool {
+ return false
+}
+
+func (bb *BatchBuilder) hasSpace(size int) bool {
+ return false
+}
+
+func (bb *BatchBuilder) Flush() []byte {
+ return nil
+}
diff --git a/pulsar/impl/buffer.go b/pulsar/impl/buffer.go
new file mode 100644
index 0000000..8e81f0c
--- /dev/null
+++ b/pulsar/impl/buffer.go
@@ -0,0 +1,119 @@
+package impl
+
+import "encoding/binary"
+
+type Buffer interface {
+ ReadableBytes() uint32
+
+ WritableBytes() uint32
+
+ Capacity() uint32
+
+ IsWritable() bool
+
+ Read(size uint32) []byte
+
+ ReadableSlice() []byte
+
+ WritableSlice() []byte
+
+ // Advance the writer index when data was written in a slice
+ WrittenBytes(size uint32)
+
+ // Copy the available portion of data at the beginning of the buffer
+ MoveToFront()
+
+ ReadUint32() uint32
+
+ WriteUint32(n uint32)
+
+ Write(s []byte)
+
+ Resize(newSize uint32)
+
+ Clear()
+}
+
+type buffer struct {
+ data []byte
+
+ readerIdx uint32
+ writerIdx uint32
+}
+
+func NewBuffer(size int) Buffer {
+ return &buffer{
+ data: make([]byte, size),
+ readerIdx: 0,
+ writerIdx: 0,
+ }
+}
+
+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 {
+ res := b.data[b.readerIdx : b.readerIdx+size]
+ b.readerIdx += size
+ return res
+}
+
+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) 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) ReadUint32() uint32 {
+ return binary.BigEndian.Uint32(b.Read(4))
+}
+
+func (b *buffer) WriteUint32(n uint32) {
+ binary.BigEndian.PutUint32(b.WritableSlice(), n)
+ b.writerIdx += 4
+}
+
+func (b *buffer) Write(s []byte) {
+ copy(b.WritableSlice(), s)
+ b.writerIdx += uint32(len(s))
+}
+
+func (b *buffer) Clear() {
+ b.readerIdx = 0
+ b.writerIdx = 0
+}
diff --git a/pulsar/impl/buffer_test.go b/pulsar/impl/buffer_test.go
new file mode 100644
index 0000000..1d72196
--- /dev/null
+++ b/pulsar/impl/buffer_test.go
@@ -0,0 +1,19 @@
+package impl
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestBuffer(t *testing.T) {
+ b := NewBuffer(1024)
+ assert.Equal(t, uint32(0), b.ReadableBytes())
+ assert.Equal(t, uint32(1024), b.WritableBytes())
+ assert.Equal(t, uint32(1024), b.Capacity())
+
+ b.Write([]byte("hello"))
+ assert.Equal(t, uint32(5), b.ReadableBytes())
+ assert.Equal(t, uint32(1019), b.WritableBytes())
+ assert.Equal(t, uint32(1024), b.Capacity())
+}
diff --git a/pulsar/impl/closable.go b/pulsar/impl/closable.go
new file mode 100644
index 0000000..c483901
--- /dev/null
+++ b/pulsar/impl/closable.go
@@ -0,0 +1,5 @@
+package impl
+
+type Closable interface {
+ Close() error
+}
diff --git a/pulsar/impl/commands.go b/pulsar/impl/commands.go
new file mode 100644
index 0000000..90760e1
--- /dev/null
+++ b/pulsar/impl/commands.go
@@ -0,0 +1,33 @@
+package impl
+
+import (
+ "github.com/golang/protobuf/proto"
+ log "github.com/sirupsen/logrus"
+ pb "pulsar-client-go-native/pulsar/pulsar_proto"
+)
+
+const MaxFrameSize = 5 * 1024 * 1024
+
+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)
+ break
+ case pb.BaseCommand_LOOKUP:
+ cmd.LookupTopic = msg.(*pb.CommandLookupTopic)
+ break
+
+ case pb.BaseCommand_PARTITIONED_METADATA:
+ cmd.PartitionMetadata = msg.(*pb.CommandPartitionedTopicMetadata)
+ break
+
+ default:
+ log.Panic("Missing command type: ", cmdType)
+ }
+
+ return cmd
+}
+
diff --git a/pulsar/impl/connection.go b/pulsar/impl/connection.go
new file mode 100644
index 0000000..6379f6a
--- /dev/null
+++ b/pulsar/impl/connection.go
@@ -0,0 +1,293 @@
+package impl
+
+import (
+ "errors"
+ "github.com/golang/protobuf/proto"
+ log "github.com/sirupsen/logrus"
+ "net"
+ pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ "sync"
+ "sync/atomic"
+)
+
+type Connection interface {
+ SendRequest(requestId uint64, req *pb.BaseCommand, callback func(command *pb.BaseCommand))
+ Close()
+}
+
+type connectionState int
+
+const (
+ connectionInit connectionState = iota
+ connectionConnecting
+ connectionTcpConnected
+ connectionReady
+ connectionClosed
+)
+
+type request struct {
+ id uint64
+ cmd *pb.BaseCommand
+ callback func(command *pb.BaseCommand)
+}
+
+type connection struct {
+ sync.Mutex
+ cond *sync.Cond
+ state connectionState
+
+ logicalAddr string
+ physicalAddr string
+ cnx net.Conn
+
+ writeBuffer Buffer
+ reader *connectionReader
+
+ log *log.Entry
+
+ requestIdGenerator uint64
+
+ incomingRequests chan *request
+ pendingReqs map[uint64]*request
+}
+
+func newConnection(logicalAddr string, physicalAddr string) *connection {
+ cnx := &connection{
+ state: connectionInit,
+ logicalAddr: logicalAddr,
+ physicalAddr: physicalAddr,
+ writeBuffer: NewBuffer(4096),
+ log: log.WithField("raddr", physicalAddr),
+ pendingReqs: make(map[uint64]*request),
+ }
+ cnx.reader = newConnectionReader(cnx)
+ cnx.cond = sync.NewCond(cnx)
+ return cnx
+}
+
+func (c *connection) start() {
+ // Each connection gets its own goroutine that will
+ go func() {
+ if c.connect() {
+ if c.doHandshake() {
+ c.run()
+ } else {
+ c.changeState(connectionClosed)
+ }
+ } else {
+ c.changeState(connectionClosed)
+ }
+ }()
+}
+
+func (c *connection) connect() (ok bool) {
+ c.log.Info("Connecting to broker")
+
+ var err error
+ c.cnx, err = net.Dial("tcp", c.physicalAddr)
+ if err != nil {
+ c.log.WithError(err).Warn("Failed to connect to broker.")
+ c.internalClose()
+ return false
+ } else {
+ c.log = c.log.WithField("laddr", c.cnx.LocalAddr())
+ c.log.Info("TCP connection established")
+ c.state = connectionTcpConnected
+ return true
+ }
+}
+
+func (c *connection) doHandshake() (ok bool) {
+ // Send 'Connect' command to initiate handshake
+ version := int32(pb.ProtocolVersion_v13)
+ c.writeCommand(baseCommand(pb.BaseCommand_CONNECT, &pb.CommandConnect{
+ ProtocolVersion: &version,
+ ClientVersion: proto.String("Pulsar Go 0.1"),
+ // AuthMethodName: "token",
+ // AuthData: authData,
+ }))
+
+ cmd, _, err := c.reader.readSingleCommand()
+ if err != nil {
+ c.log.WithError(err).Warn("Failed to perform initial handshake")
+ return false
+ }
+
+ if cmd.Connected == nil {
+ c.log.Warnf("Failed to perform initial handshake - Expecting 'Connected' cmd, got '%s'",
+ cmd.Type)
+ return false
+ }
+
+ c.log.Info("Connection is ready")
+ c.changeState(connectionReady)
+ return true
+}
+
+func (c *connection) waitUntilReady() error {
+ c.Lock()
+ defer c.Unlock()
+
+ for {
+ switch c.state {
+ case connectionInit:
+ case connectionConnecting:
+ case connectionTcpConnected:
+ // Wait for the state to change
+ c.cond.Wait()
+ break
+
+ case connectionReady:
+ return nil
+
+ case connectionClosed:
+ return errors.New("connection error")
+ }
+ }
+}
+
+func (c *connection) run() {
+ // All reads come from the reader goroutine
+ go c.reader.readFromConnection()
+
+ for {
+ select {
+ case req := <-c.incomingRequests:
+ c.pendingReqs[req.id] = req
+ c.writeCommand(req.cmd)
+ }
+ }
+}
+
+func (c *connection) writeCommand(cmd proto.Message) {
+ // Wire format
+ // [FRAME_SIZE] [CMD_SIZE][CMD]
+ cmdSize := uint32(proto.Size(cmd))
+ frameSize := cmdSize + 4
+ bufferSize := frameSize + 4
+
+ c.writeBuffer.Clear()
+ if c.writeBuffer.WritableBytes() < bufferSize {
+ c.writeBuffer.Resize(c.writeBuffer.Capacity() * 2)
+ }
+
+ c.writeBuffer.WriteUint32(frameSize)
+ c.writeBuffer.WriteUint32(cmdSize)
+ serialized, err := proto.Marshal(cmd)
+ if err != nil {
+ c.log.WithError(err).Fatal("Protobuf serialization error")
+ }
+
+ c.writeBuffer.Write(serialized)
+
+ if _, err := c.cnx.Write(c.writeBuffer.ReadableSlice()); err != nil {
+ c.log.WithError(err).Warn("Failed to write on connection")
+ c.internalClose()
+ }
+}
+
+func (c *connection) receivedCommand(cmd *pb.BaseCommand, headersAndPayload []byte) {
+ c.log.Infof("Received command: %s -- payload: %v", cmd, headersAndPayload)
+
+ switch *cmd.Type {
+ case pb.BaseCommand_SUCCESS:
+ c.handleResponse(*cmd.Success.RequestId, cmd)
+ break
+
+ case pb.BaseCommand_PRODUCER_SUCCESS:
+ c.handleResponse(*cmd.ProducerSuccess.RequestId, cmd)
+ break
+
+ case pb.BaseCommand_PARTITIONED_METADATA_RESPONSE:
+ c.handleResponse(*cmd.PartitionMetadataResponse.RequestId, cmd)
+ break
+
+ case pb.BaseCommand_LOOKUP_RESPONSE:
+ c.handleResponse(*cmd.LookupTopicResponse.RequestId, cmd)
+ break
+
+ case pb.BaseCommand_CONSUMER_STATS_RESPONSE:
+ c.handleResponse(*cmd.ConsumerStatsResponse.RequestId, cmd)
+ break
+
+ case pb.BaseCommand_GET_LAST_MESSAGE_ID_RESPONSE:
+ c.handleResponse(*cmd.GetLastMessageIdResponse.RequestId, cmd)
+ break
+
+ case pb.BaseCommand_GET_TOPICS_OF_NAMESPACE_RESPONSE:
+ c.handleResponse(*cmd.GetTopicsOfNamespaceResponse.RequestId, cmd)
+ break
+
+ case pb.BaseCommand_GET_SCHEMA_RESPONSE:
+ c.handleResponse(*cmd.GetSchemaResponse.RequestId, cmd)
+ break
+
+ case pb.BaseCommand_ERROR:
+ break
+
+ case pb.BaseCommand_CLOSE_PRODUCER:
+ case pb.BaseCommand_CLOSE_CONSUMER:
+
+ case pb.BaseCommand_SEND_RECEIPT:
+ break
+ case pb.BaseCommand_SEND_ERROR:
+ break
+
+ case pb.BaseCommand_MESSAGE:
+ break
+
+ case pb.BaseCommand_PONG:
+
+ case pb.BaseCommand_ACTIVE_CONSUMER_CHANGE:
+ // TODO
+ break
+
+ default:
+ c.log.Errorf("Received invalid command type: %s", cmd.Type)
+ c.Close()
+ }
+}
+
+func (c *connection) SendRequest(requestId uint64, req *pb.BaseCommand, callback func(command *pb.BaseCommand)) {
+ c.pendingReqs[requestId] = &request{
+ id: requestId,
+ cmd: req,
+ callback: callback,
+ }
+ c.writeCommand(req)
+}
+
+func (c *connection) handleResponse(requestId uint64, response *pb.BaseCommand) {
+ request, ok := c.pendingReqs[requestId]
+ if !ok {
+ c.log.Warnf("Received unexpected response for request %d of type %s", requestId, response.Type)
+ return
+ }
+
+ delete(c.pendingReqs, requestId)
+ request.callback(response)
+}
+
+func (c *connection) Close() {
+ // TODO
+}
+
+func (c *connection) changeState(state connectionState) {
+ c.Lock()
+ c.state = state
+ c.cond.Broadcast()
+ c.Unlock()
+}
+
+func (c *connection) newRequestId() uint64 {
+ return atomic.AddUint64(&c.requestIdGenerator, 1)
+}
+
+func (c *connection) internalClose() {
+ c.state = connectionClosed
+ c.cond.Broadcast()
+
+ if c.cnx != nil {
+ c.cnx.Close()
+ }
+}
diff --git a/pulsar/impl/connection_pool.go b/pulsar/impl/connection_pool.go
new file mode 100644
index 0000000..676f205
--- /dev/null
+++ b/pulsar/impl/connection_pool.go
@@ -0,0 +1,54 @@
+package impl
+
+import (
+ "sync"
+)
+
+type ConnectionPool interface {
+ GetConnection(logicalAddr string, physicalAddr string) (Connection, error)
+
+ // Close all the connections in the pool
+ Close()
+}
+
+type connectionPool struct {
+ pool sync.Map
+}
+
+func NewConnectionPool() ConnectionPool {
+ return &connectionPool{}
+}
+
+func (p *connectionPool) GetConnection(logicalAddr string, physicalAddr string) (Connection, error) {
+ cachedCnx, found := p.pool.Load(logicalAddr)
+ if found {
+ cnx := cachedCnx.(*connection)
+ if err := cnx.waitUntilReady(); err != nil {
+ // Connection is ready to be used
+ return cnx, nil
+ } else {
+ // The cached connection is failed
+ p.pool.Delete(logicalAddr)
+ }
+ }
+
+ // Try to create a new connection
+ newCnx, wasCached := p.pool.LoadOrStore(logicalAddr, newConnection(logicalAddr, physicalAddr))
+ cnx := newCnx.(*connection)
+ if !wasCached {
+ cnx.start()
+ }
+
+ if err := cnx.waitUntilReady(); err != nil {
+ return nil, err
+ } else {
+ return cnx, nil
+ }
+}
+
+func (p *connectionPool) Close() {
+ p.pool.Range(func(key, value interface{}) bool {
+ value.(Connection).Close()
+ return true
+ })
+}
diff --git a/pulsar/impl/connection_reader.go b/pulsar/impl/connection_reader.go
new file mode 100644
index 0000000..5bb87c6
--- /dev/null
+++ b/pulsar/impl/connection_reader.go
@@ -0,0 +1,117 @@
+package impl
+
+import (
+ "bufio"
+ "github.com/golang/protobuf/proto"
+ "github.com/pkg/errors"
+ "io"
+ pb "pulsar-client-go-native/pulsar/pulsar_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 {
+ r.cnx.log.WithError(err).Info("Error reading from connection")
+ r.cnx.internalClose()
+ break
+ }
+
+ // Process
+ r.cnx.log.Debug("Got command! ", cmd, " with payload ", headersAndPayload)
+ r.cnx.receivedCommand(cmd, headersAndPayload)
+ }
+}
+
+func (r *connectionReader) readSingleCommand() (cmd *pb.BaseCommand, headersAndPayload []byte, 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 !r.readAtLeast(4) {
+ return nil, nil, errors.New("Short read when reading frame size")
+ }
+ }
+
+ // We have enough to read frame size
+ frameSize := r.buffer.ReadUint32()
+ if frameSize > MaxFrameSize {
+ r.cnx.log.Warnf("Received too big frame size. size=%d", frameSize)
+ r.cnx.internalClose()
+ return nil, nil, errors.New("Frame size too big")
+ }
+
+ // Next, we read the rest of the frame
+ if r.buffer.ReadableBytes() < frameSize {
+ if !r.readAtLeast(frameSize) {
+ return nil, nil, errors.New("Short read when reading frame")
+ }
+ }
+
+ // 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 = make([]byte, headersAndPayloadSize)
+ copy(headersAndPayload, r.buffer.Read(headersAndPayloadSize))
+ }
+ return cmd, headersAndPayload, nil
+}
+
+func (r *connectionReader) readAtLeast(size uint32) (ok bool) {
+ 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 {
+ r.cnx.internalClose()
+ return false
+ }
+
+ r.buffer.WrittenBytes(uint32(n))
+ return true
+}
+
+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.internalClose()
+ return nil, err
+ } else {
+ return cmd, nil
+ }
+}
diff --git a/pulsar/impl/default_router.go b/pulsar/impl/default_router.go
new file mode 100644
index 0000000..bb5ca73
--- /dev/null
+++ b/pulsar/impl/default_router.go
@@ -0,0 +1,26 @@
+package impl
+
+import (
+ "time"
+)
+
+type defaultRouter struct {
+ partitionIdx uint32
+ maxBatchingDelay time.Duration
+}
+
+func NewDefaultRouter(maxBatchingDelay time.Duration) func(uint32) int {
+ // TODO: XXX
+ //state := &defaultRouter{
+ // partitionIdx: rand.Uint32(),
+ // maxBatchingDelay: maxBatchingDelay,
+ //}
+
+ return func(numPartitions uint32) int {
+ if numPartitions == 1 {
+ return 0
+ }
+
+ return -1
+ }
+}
diff --git a/pulsar/impl/lookup_service.go b/pulsar/impl/lookup_service.go
new file mode 100644
index 0000000..0ebf424
--- /dev/null
+++ b/pulsar/impl/lookup_service.go
@@ -0,0 +1,62 @@
+package impl
+
+import (
+ log "github.com/sirupsen/logrus"
+ "net/url"
+ pb "pulsar-client-go-native/pulsar/pulsar_proto"
+)
+
+type LookupResult struct {
+ LogicalAddr *url.URL
+ PhysicalAddr *url.URL
+}
+
+type LookupService interface {
+ Lookup(topic string) (*LookupResult, error)
+}
+
+type lookupService struct {
+ rpcClient RpcClient
+}
+
+func NewLookupService(rpcClient RpcClient) LookupService {
+ return &lookupService{
+ rpcClient: rpcClient,
+ }
+}
+
+func (ls *lookupService) Lookup(topic string) (*LookupResult, error) {
+ // Follow brokers redirect up to certain number of times
+ for i := 0; i < 20; i++ {
+ id := ls.rpcClient.NewRequestId()
+ res, err := ls.rpcClient.RequestToAnyBroker(id, pb.BaseCommand_LOOKUP, &pb.CommandLookupTopic{
+ RequestId: &id,
+ Topic: &topic,
+ })
+
+ if err != nil {
+ return nil, err
+ }
+
+ log.Infof("Got lookup response: %s", res)
+ lr := res.Response.LookupTopicResponse
+ switch *lr.Response {
+ case pb.CommandLookupTopicResponse_Redirect:
+ log.WithField("topic", topic).Infof("Follow redirect to broker. %v / %v - Use proxy: %v",
+ lr.BrokerServiceUrl, lr.BrokerServiceUrlTls, lr.ProxyThroughServiceUrl)
+ break
+
+ case pb.CommandLookupTopicResponse_Connect:
+ log.WithField("topic", topic).Infof("Successfully looked up topic on broker. %s / %s - Use proxy: %t",
+ lr.GetBrokerServiceUrl(), lr.GetBrokerServiceUrlTls(), lr.GetProxyThroughServiceUrl())
+ return nil, nil
+
+ case pb.CommandLookupTopicResponse_Failed:
+ log.WithField("topic", topic).Warn("Failed to lookup topic",
+ lr.Error.String())
+ return nil, nil
+ }
+ }
+
+ return nil, nil
+}
diff --git a/pulsar/impl/rpc_client.go b/pulsar/impl/rpc_client.go
new file mode 100644
index 0000000..fd76569
--- /dev/null
+++ b/pulsar/impl/rpc_client.go
@@ -0,0 +1,71 @@
+package impl
+
+import (
+ "github.com/golang/protobuf/proto"
+ "net/url"
+ pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ "sync"
+ "sync/atomic"
+)
+
+type RpcResult struct {
+ Response *pb.BaseCommand
+ Cnx Connection
+}
+
+type RpcClient interface {
+ // Create a new unique request id
+ NewRequestId() 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 string, physicalAddr string, requestId uint64,
+ cmdType pb.BaseCommand_Type, message proto.Message) (*RpcResult, error)
+}
+
+type rpcClient struct {
+ hostPort string
+ pool ConnectionPool
+ requestIdGenerator uint64
+}
+
+func NewRpcClient(serviceUrl *url.URL, pool ConnectionPool) RpcClient {
+ return &rpcClient{
+ hostPort: serviceUrl.Host,
+ pool: pool,
+ }
+}
+
+func (c *rpcClient) RequestToAnyBroker(requestId uint64, cmdType pb.BaseCommand_Type, message proto.Message) (*RpcResult, error) {
+ return c.Request(c.hostPort, c.hostPort, requestId, cmdType, message)
+}
+
+func (c *rpcClient) Request(logicalAddr string, physicalAddr string, requestId uint64,
+ cmdType pb.BaseCommand_Type, message proto.Message) (*RpcResult, error) {
+ // TODO: Add retry logic in case of connection issues
+ cnx, err := c.pool.GetConnection(logicalAddr, physicalAddr)
+ if err != nil {
+ return nil, err
+ }
+
+ wg := sync.WaitGroup{}
+ wg.Add(1)
+
+ rpcResult := &RpcResult{
+ Cnx: cnx,
+ }
+
+ // TODO: Handle errors with disconnections
+ cnx.SendRequest(requestId, baseCommand(cmdType, message), func(response *pb.BaseCommand) {
+ rpcResult.Response = response
+ wg.Done()
+ })
+
+ wg.Wait()
+ return rpcResult, nil
+}
+
+func (c *rpcClient) NewRequestId() uint64 {
+ return atomic.AddUint64(&c.requestIdGenerator, 1)
+}
diff --git a/pulsar/impl/topic_name.go b/pulsar/impl/topic_name.go
new file mode 100644
index 0000000..2bafeb2
--- /dev/null
+++ b/pulsar/impl/topic_name.go
@@ -0,0 +1,88 @@
+package impl
+
+import (
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+type TopicName struct {
+ Name string
+ Namespace string
+ Partition int
+}
+
+const (
+ publicTenant = "public"
+ defaultNamespace = "default"
+ partitionedTopicSuffix = "-partition-"
+)
+
+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:
+ // - <topic>
+ // - <property>/<namespace>/<topic>
+ parts := strings.Split(topic, "/")
+ if len(parts) == 3 {
+ 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 <tenant>/<namespace>/<topic> or <topic>")
+ }
+ }
+
+ 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)
+ }
+
+ rest := parts[1]
+ var err error
+
+ // The rest of the name can be in different forms:
+ // new: tenant/namespace/<localName>
+ // legacy: tenant/cluster/namespace/<localName>
+ // Examples of localName:
+ // 1. some/name/xyz//
+ // 2. /xyz-123/feeder-2
+ parts = strings.SplitN(rest, "/", 4)
+ if len(parts) == 3 {
+ // New topic name without cluster name
+ tn.Namespace = parts[0] + "/" + parts[1]
+ } 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])
+ } 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 getPartitionIndex(topic string) (int, error) {
+ if strings.Contains(topic, partitionedTopicSuffix) {
+ idx := strings.LastIndex(topic, "-") + 1
+ return strconv.Atoi(topic[idx:])
+ } else {
+ return -1, nil
+ }
+}
diff --git a/pulsar/impl/topic_name_test.go b/pulsar/impl/topic_name_test.go
new file mode 100644
index 0000000..b4d6184
--- /dev/null
+++ b/pulsar/impl/topic_name_test.go
@@ -0,0 +1,68 @@
+package impl
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestParseTopicName(t *testing.T) {
+ topic, err := ParseTopicName("persistent://my-tenant/my-ns/my-topic")
+
+ assert.Nil(t, err)
+ assert.Equal(t, "persistent://my-tenant/my-ns/my-topic", topic.Name)
+ assert.Equal(t, "my-tenant/my-ns", topic.Namespace)
+ assert.Equal(t, -1, topic.Partition)
+
+ topic, err = ParseTopicName("my-topic")
+ assert.Nil(t, err)
+ assert.Equal(t, "persistent://public/default/my-topic", topic.Name)
+ assert.Equal(t, "public/default", topic.Namespace)
+ assert.Equal(t, -1, topic.Partition)
+
+ topic, err = ParseTopicName("my-tenant/my-namespace/my-topic")
+ assert.Nil(t, err)
+ assert.Equal(t, "persistent://my-tenant/my-namespace/my-topic", topic.Name)
+ assert.Equal(t, "my-tenant/my-namespace", topic.Namespace)
+ assert.Equal(t, -1, topic.Partition)
+
+ topic, err = ParseTopicName("non-persistent://my-tenant/my-namespace/my-topic")
+ assert.Nil(t, err)
+ assert.Equal(t, "non-persistent://my-tenant/my-namespace/my-topic", topic.Name)
+ assert.Equal(t, "my-tenant/my-namespace", topic.Namespace)
+ assert.Equal(t, -1, topic.Partition)
+
+
+ topic, err = ParseTopicName("my-topic-partition-5")
+ assert.Nil(t, err)
+ assert.Equal(t, "persistent://public/default/my-topic-partition-5", topic.Name)
+ assert.Equal(t, "public/default", topic.Namespace)
+ assert.Equal(t, 5, topic.Partition)
+
+ // V1 topic name
+ topic, err = ParseTopicName("persistent://my-tenant/my-cluster/my-ns/my-topic")
+ assert.Nil(t, err)
+ assert.Equal(t, "persistent://my-tenant/my-cluster/my-ns/my-topic", topic.Name)
+ assert.Equal(t, "my-tenant/my-cluster/my-ns", topic.Namespace)
+ assert.Equal(t, -1, topic.Partition)
+}
+
+func TestParseTopicNameErrors(t *testing.T) {
+ _, err := ParseTopicName("invalid://my-tenant/my-ns/my-topic")
+ assert.NotNil(t, err)
+
+ _, err = ParseTopicName("invalid://my-tenant/my-ns/my-topic-partition-xyz")
+ assert.NotNil(t, err)
+
+ _, err = ParseTopicName("my-tenant/my-ns/my-topic-partition-xyz/invalid")
+ assert.NotNil(t, err)
+
+ _, err = ParseTopicName("persistent://my-tenant")
+ assert.NotNil(t, err)
+
+ _, err = ParseTopicName("persistent://my-tenant/my-namespace")
+ assert.NotNil(t, err)
+
+ _, err = ParseTopicName("persistent://my-tenant/my-cluster/my-ns/my-topic-partition-xyz/invalid")
+ assert.NotNil(t, err)
+}
diff --git a/pulsar/impl_client.go b/pulsar/impl_client.go
new file mode 100644
index 0000000..e143601
--- /dev/null
+++ b/pulsar/impl_client.go
@@ -0,0 +1,98 @@
+package pulsar
+
+import (
+ "fmt"
+ log "github.com/sirupsen/logrus"
+ "net/url"
+ "pulsar-client-go-native/pulsar/impl"
+ pb "pulsar-client-go-native/pulsar/pulsar_proto"
+)
+
+type client struct {
+ options ClientOptions
+
+ cnxPool impl.ConnectionPool
+ rpcClient impl.RpcClient
+ lookupService impl.LookupService
+
+ handlers map[impl.Closable]bool
+}
+
+func newClient(options ClientOptions) (Client, error) {
+ if options.URL == "" {
+ return nil, newError(InvalidConfiguration, "URL is required for client")
+ }
+
+ url, err := url.Parse(options.URL)
+ if err != nil {
+ log.WithError(err).Error("Failed to parse service URL")
+ return nil, newError(InvalidConfiguration, "Invalid service URL")
+ }
+
+ if url.Scheme != "pulsar" {
+ return nil, newError(InvalidConfiguration, fmt.Sprintf("Invalid URL scheme '%s'", url.Scheme))
+ }
+
+ c := &client{
+ cnxPool: impl.NewConnectionPool(),
+ }
+ c.rpcClient = impl.NewRpcClient(url, c.cnxPool)
+ c.lookupService = impl.NewLookupService(c.rpcClient)
+ return c, nil
+}
+
+func (client *client) CreateProducer(options ProducerOptions) (Producer, error) {
+ producer, err := newProducer(client, options)
+ if err == nil {
+ client.handlers[producer] = true
+ }
+ return producer, err
+}
+
+func (client *client) Subscribe(options ConsumerOptions) (Consumer, error) {
+ // TODO: Implement consumer
+ return nil, nil
+}
+
+func (client *client) CreateReader(options ReaderOptions) (Reader, error) {
+ // TODO: Implement reader
+ return nil, nil
+}
+
+func (client *client) TopicPartitions(topic string) ([]string, error) {
+ topicName, err := impl.ParseTopicName(topic)
+ if err != nil {
+ return nil, err
+ }
+
+ id := client.rpcClient.NewRequestId()
+ res, err := client.rpcClient.RequestToAnyBroker(id, pb.BaseCommand_PARTITIONED_METADATA,
+ &pb.CommandPartitionedTopicMetadata{
+ RequestId: &id,
+ Topic: &topicName.Name,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ r := res.Response.PartitionMetadataResponse
+ if r.Error != nil {
+ return nil, newError(LookupError, r.GetError().String())
+ }
+
+ partitions := make([]string, r.GetPartitions())
+ for i := 0; i < int(r.GetPartitions()); i++ {
+ partitions[i] = fmt.Sprintf("%s-partition-%d", topic, i)
+ }
+ return partitions, nil
+}
+
+func (client *client) Close() error {
+ for handler := range client.handlers {
+ if err := handler.Close(); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
new file mode 100644
index 0000000..bb96a27
--- /dev/null
+++ b/pulsar/impl_partition_producer.go
@@ -0,0 +1,88 @@
+package pulsar
+
+import (
+ "context"
+ log "github.com/sirupsen/logrus"
+ "pulsar-client-go-native/pulsar/impl"
+ pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ "sync"
+)
+
+type partitionProducer struct {
+ client *client
+ topic string
+ log *log.Entry
+ mutex sync.Mutex
+ cond *sync.Cond
+}
+
+func newPartitionProducer(client *client, topic string, options *ProducerOptions) (*partitionProducer, error) {
+
+ p := &partitionProducer{
+ log: log.WithField("topic", topic),
+ }
+
+ err := p.grabCnx()
+ if err != nil {
+ log.WithError(err).Errorf("Failed to create producer")
+ return nil, err
+ } else {
+ log.Info("Created producer")
+ 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
+ }
+
+ id := p.client.rpcClient.NewRequestId()
+ p.client.rpcClient.Request(lr.LogicalAddr.Host, lr.PhysicalAddr.Host, id, pb.BaseCommand_PRODUCER, *pb.CommandProducer{
+
+ })
+
+ var cnx impl.Connection
+ cnx, err = p.client.cnxPool.GetConnection(lr.LogicalAddr.Host, lr.PhysicalAddr.Host)
+ if err != nil {
+ p.log.WithError(err).Warn("Failed to get connection")
+ return err
+ }
+
+ cnx.
+
+ return nil
+}
+
+func (p *partitionProducer) run() {
+
+}
+
+func (p *partitionProducer) Topic() string {
+ return ""
+}
+
+func (p *partitionProducer) Name() string {
+ return ""
+}
+
+func (p *partitionProducer) Send(context.Context, ProducerMessage) error {
+ return nil
+}
+
+func (p *partitionProducer) SendAsync(context.Context, ProducerMessage, func(ProducerMessage, error)) {
+}
+
+func (p *partitionProducer) LastSequenceID() int64 {
+ return -1
+}
+
+func (p *partitionProducer) Flush() error {
+ return nil
+}
+
+func (p *partitionProducer) Close() error {
+ return nil
+}
diff --git a/pulsar/impl_producer.go b/pulsar/impl_producer.go
new file mode 100644
index 0000000..f2332ea
--- /dev/null
+++ b/pulsar/impl_producer.go
@@ -0,0 +1,123 @@
+package pulsar
+
+import (
+ "context"
+ "pulsar-client-go-native/pulsar/impl"
+ "sync"
+)
+
+type producer struct {
+ topic string
+ producers []Producer
+ messageRouter func(ProducerMessage, TopicMetadata) int
+}
+
+func newProducer(client *client, options ProducerOptions) (*producer, error) {
+ if options.Topic == "" {
+ return nil, newError(InvalidTopicName, "Topic name is required for producer")
+ }
+
+ p := &producer{
+ topic: options.Topic,
+ }
+
+ if options.MessageRouter == nil {
+ internalRouter := impl.NewDefaultRouter(options.BatchingMaxPublishDelay)
+ p.messageRouter = func(message ProducerMessage, metadata TopicMetadata) int {
+ return internalRouter(metadata.NumPartitions())
+ }
+ }
+
+ partitions, err := client.TopicPartitions(options.Topic)
+ if err != nil {
+ return nil, err
+ }
+
+ numPartitions := len(partitions)
+ p.producers = make([]Producer, numPartitions)
+
+ type ProducerError struct {
+ partition int
+ Producer
+ error
+ }
+
+ c := make(chan ProducerError, numPartitions)
+
+ for i := 0; i < numPartitions; i++ {
+ partition := i
+ go func() {
+ prod, err := newPartitionProducer(client, &options)
+ c <- ProducerError{partition, prod, err}
+ }()
+ }
+
+ for i := 0; i < numPartitions; i++ {
+ pe := <-c
+ err = pe.error
+ p.producers[pe.partition] = pe.Producer
+ }
+
+ 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 nil, err
+ } else {
+ return p, nil
+ }
+}
+
+func (p *producer) Topic() string {
+ return p.topic
+}
+
+func (p *producer) Name() string {
+ return p.producers[0].Name()
+}
+
+func (p *producer) NumPartitions() uint32 {
+ return uint32(len(p.producers))
+}
+
+func (p *producer) Send(ctx context.Context, msg ProducerMessage) error {
+ wg := sync.WaitGroup{}
+ wg.Add(1)
+
+ var err error
+
+ p.SendAsync(ctx, msg, func(message ProducerMessage, e error) {
+ err = e
+ wg.Done()
+ })
+
+ wg.Wait()
+ return err
+}
+
+func (p *producer) SendAsync(ctx context.Context, msg ProducerMessage, callback func(ProducerMessage, error)) {
+ partition := p.messageRouter(msg, p)
+ p.producers[partition].SendAsync(ctx, msg, callback)
+}
+
+func (p *producer) LastSequenceID() int64 {
+ var maxSeq int64 = -1
+ for _, pp := range p.producers {
+ s := pp.LastSequenceID()
+ if s > maxSeq {
+ maxSeq = s
+ }
+ }
+ return maxSeq
+}
+
+func (p *producer) Flush() error {
+ return nil
+}
+
+func (p *producer) Close() error {
+ return nil
+}
diff --git a/pulsar/message.go b/pulsar/message.go
new file mode 100644
index 0000000..b829b96
--- /dev/null
+++ b/pulsar/message.go
@@ -0,0 +1,90 @@
+//
+// 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"
+
+type ProducerMessage struct {
+ // Payload for the message
+ Payload []byte
+
+ // Sets the key of the message for routing policy
+ Key string
+
+ // Attach application defined properties on the message
+ Properties map[string]string
+
+ // Set the event time for a given message
+ EventTime time.Time
+
+ // Override the replication clusters for this message.
+ ReplicationClusters []string
+
+ // Set the sequence id to assign to the current message
+ SequenceID int64
+}
+
+type Message interface {
+ // Get the topic from which this message originated from
+ Topic() string
+
+ // Return the properties attached to the message.
+ // Properties are application defined key/value pairs that will be attached to the message
+ Properties() map[string]string
+
+ // Get the payload of the message
+ Payload() []byte
+
+ // Get 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
+
+ // Get the publish time of this message. The publish time is the timestamp that a client publish the message.
+ PublishTime() time.Time
+
+ // Get the event time associated with this message. It is typically set by the applications via
+ // `ProducerMessage.EventTime`.
+ // If there isn't any event time associated with this event, it will be nil.
+ EventTime() *time.Time
+
+ // Get the key of the message, if any
+ Key() string
+}
+
+// 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
+}
+
+// Reconstruct a MessageID object from its serialized representation
+func DeserializeMessageID(data []byte) MessageID {
+ // TODO
+ //return deserializeMessageId(data)
+ return nil
+}
+
+var (
+ // MessageID that points to the earliest message avaialable in a topic
+ //EarliestMessage MessageID = earliestMessageID()
+
+ // MessageID that points to the latest message
+ //LatestMessage MessageID = latestMessageID()
+)
diff --git a/pulsar/producer.go b/pulsar/producer.go
new file mode 100644
index 0000000..90769cb
--- /dev/null
+++ b/pulsar/producer.go
@@ -0,0 +1,187 @@
+//
+// 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"
+)
+
+type MessageRoutingMode int
+
+const (
+ // Publish messages across all partitions in round-robin.
+ RoundRobinDistribution MessageRoutingMode = iota
+
+ // The producer will chose one single partition and publish all the messages into that partition
+ UseSinglePartition
+
+ // Use custom message router implementation that will be called to determine the partition for a particular message.
+ CustomPartition
+)
+
+type HashingScheme int
+
+const (
+ JavaStringHash HashingScheme = iota // Java String.hashCode() equivalent
+ Murmur3_32Hash // Use Murmur3 hashing function
+ BoostHash // C++ based boost::hash
+)
+
+type CompressionType int
+
+const (
+ NoCompression CompressionType = iota
+ LZ4
+ ZLib
+ ZSTD
+)
+
+type TopicMetadata interface {
+ // Get the number of partitions for the specific topic
+ NumPartitions() uint32
+}
+
+type ProducerOptions struct {
+ // Specify the topic this producer will be publishing on.
+ // This argument is required when constructing the producer.
+ Topic string
+
+ // Specify a name for the producer
+ // If not assigned, the system will generate a globally unique name which can be access with
+ // Producer.ProducerName().
+ // When specifying a name, it is up to the user to ensure that, for a given topic, the producer name is unique
+ // across all Pulsar's clusters. Brokers will enforce that only a single producer a given name can be publishing on
+ // a topic.
+ Name string
+
+ // Attach a set of application defined properties to the producer
+ // This properties will be visible in the topic stats
+ Properties map[string]string
+
+ // Set the send timeout (default: 30 seconds)
+ // If a message is not acknowledged by the server before the sendTimeout expires, an error will be reported.
+ // Setting the timeout to -1, will set the timeout to infinity, which can be useful when using Pulsar's message
+ // deduplication feature.
+ SendTimeout time.Duration
+
+ // Set the max size of the queue holding the messages pending to receive an acknowledgment from the broker.
+ // When the queue is full, by default, all calls to Producer.send() and Producer.sendAsync() will fail
+ // unless `BlockIfQueueFull` is set to true. Use BlockIfQueueFull(boolean) to change the blocking behavior.
+ MaxPendingMessages int
+
+ // Set the number of max pending messages across all the partitions
+ // This setting will be used to lower the max pending messages for each partition
+ // `MaxPendingMessages(int)`, if the total exceeds the configured value.
+ MaxPendingMessagesAcrossPartitions int
+
+ // Set whether the `Producer.Send()` and `Producer.sendAsync()` operations should block when the outgoing
+ // message queue is full. Default is `false`. If set to `false`, send operations will immediately fail with
+ // `ProducerQueueIsFullError` when there is no space left in pending queue.
+ BlockIfQueueFull bool
+
+ // Set the message routing mode for the partitioned producer.
+ // Default routing mode is round-robin routing.
+ //
+ // This logic is applied when the application is not setting a key ProducerMessage#setKey(String) on a
+ // particular message.
+ MessageRoutingMode
+
+ // Change the `HashingScheme` used to chose the partition on where to publish a particular message.
+ // Standard hashing functions available are:
+ //
+ // - `JavaStringHash` : Java String.hashCode() equivalent
+ // - `Murmur3_32Hash` : Use Murmur3 hashing function.
+ // https://en.wikipedia.org/wiki/MurmurHash">https://en.wikipedia.org/wiki/MurmurHash
+ // - `BoostHash` : C++ based boost::hash
+ //
+ // Default is `JavaStringHash`.
+ HashingScheme
+
+ // Set 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
+
+ // Set 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(Message, TopicMetadata) int
+
+ // Control whether automatic batching of messages is enabled for the producer. Default: false [No batching]
+ //
+ // 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
+ Batching bool
+
+ // Set 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
+
+ // Set 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 batch interval has elapsed
+ BatchingMaxMessages uint
+}
+
+// The producer is used to publish messages on a topic
+type Producer interface {
+ // return the topic to which producer is publishing to
+ Topic() string
+
+ // 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) error
+
+ // Send a message in asynchronous mode
+ // The callback will report back the message being published and
+ // the eventual error in publishing
+ SendAsync(context.Context, ProducerMessage, func(ProducerMessage, error))
+
+ // 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() error
+}
diff --git a/pulsar/pulsar_proto/PulsarApi.pb.go b/pulsar/pulsar_proto/PulsarApi.pb.go
new file mode 100644
index 0000000..cb82acd
--- /dev/null
+++ b/pulsar/pulsar_proto/PulsarApi.pb.go
@@ -0,0 +1,4043 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: PulsarApi.proto
+
+package pulsar_proto
+
+import proto "github.com/golang/protobuf/proto"
+import fmt "fmt"
+import math "math"
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+
+type CompressionType int32
+
+const (
+ CompressionType_NONE CompressionType = 0
+ CompressionType_LZ4 CompressionType = 1
+ CompressionType_ZLIB CompressionType = 2
+ CompressionType_ZSTD CompressionType = 3
+)
+
+var CompressionType_name = map[int32]string{
+ 0: "NONE",
+ 1: "LZ4",
+ 2: "ZLIB",
+ 3: "ZSTD",
+}
+var CompressionType_value = map[string]int32{
+ "NONE": 0,
+ "LZ4": 1,
+ "ZLIB": 2,
+ "ZSTD": 3,
+}
+
+func (x CompressionType) Enum() *CompressionType {
+ p := new(CompressionType)
+ *p = x
+ return p
+}
+func (x CompressionType) String() string {
+ return proto.EnumName(CompressionType_name, int32(x))
+}
+func (x *CompressionType) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(CompressionType_value, data, "CompressionType")
+ if err != nil {
+ return err
+ }
+ *x = CompressionType(value)
+ return nil
+}
+func (CompressionType) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{0}
+}
+
+type ServerError int32
+
+const (
+ ServerError_UnknownError ServerError = 0
+ ServerError_MetadataError ServerError = 1
+ ServerError_PersistenceError ServerError = 2
+ ServerError_AuthenticationError ServerError = 3
+ ServerError_AuthorizationError ServerError = 4
+ ServerError_ConsumerBusy ServerError = 5
+ // other consumers are connected
+ ServerError_ServiceNotReady ServerError = 6
+ ServerError_ProducerBlockedQuotaExceededError ServerError = 7
+ ServerError_ProducerBlockedQuotaExceededException ServerError = 8
+ ServerError_ChecksumError ServerError = 9
+ ServerError_UnsupportedVersionError ServerError = 10
+ ServerError_TopicNotFound ServerError = 11
+ ServerError_SubscriptionNotFound ServerError = 12
+ ServerError_ConsumerNotFound ServerError = 13
+ ServerError_TooManyRequests ServerError = 14
+ ServerError_TopicTerminatedError ServerError = 15
+ ServerError_ProducerBusy ServerError = 16
+ ServerError_InvalidTopicName ServerError = 17
+ ServerError_IncompatibleSchema ServerError = 18
+)
+
+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",
+}
+var 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,
+}
+
+func (x ServerError) Enum() *ServerError {
+ p := new(ServerError)
+ *p = x
+ return p
+}
+func (x ServerError) String() string {
+ return proto.EnumName(ServerError_name, int32(x))
+}
+func (x *ServerError) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(ServerError_value, data, "ServerError")
+ if err != nil {
+ return err
+ }
+ *x = ServerError(value)
+ return nil
+}
+func (ServerError) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{1}
+}
+
+type AuthMethod int32
+
+const (
+ AuthMethod_AuthMethodNone AuthMethod = 0
+ AuthMethod_AuthMethodYcaV1 AuthMethod = 1
+ AuthMethod_AuthMethodAthens AuthMethod = 2
+)
+
+var AuthMethod_name = map[int32]string{
+ 0: "AuthMethodNone",
+ 1: "AuthMethodYcaV1",
+ 2: "AuthMethodAthens",
+}
+var 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 proto.EnumName(AuthMethod_name, int32(x))
+}
+func (x *AuthMethod) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(AuthMethod_value, data, "AuthMethod")
+ if err != nil {
+ return err
+ }
+ *x = AuthMethod(value)
+ return nil
+}
+func (AuthMethod) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{2}
+}
+
+// Each protocol version identify new features that are
+// incrementally added to the protocol
+type ProtocolVersion int32
+
+const (
+ ProtocolVersion_v0 ProtocolVersion = 0
+ ProtocolVersion_v1 ProtocolVersion = 1
+ ProtocolVersion_v2 ProtocolVersion = 2
+ ProtocolVersion_v3 ProtocolVersion = 3
+ ProtocolVersion_v4 ProtocolVersion = 4
+ ProtocolVersion_v5 ProtocolVersion = 5
+ ProtocolVersion_v6 ProtocolVersion = 6
+ ProtocolVersion_v7 ProtocolVersion = 7
+ ProtocolVersion_v8 ProtocolVersion = 8
+ ProtocolVersion_v9 ProtocolVersion = 9
+ ProtocolVersion_v10 ProtocolVersion = 10
+ ProtocolVersion_v11 ProtocolVersion = 11
+ ProtocolVersion_v12 ProtocolVersion = 12
+ // Added CommandActiveConsumerChange
+ // Added CommandGetTopicsOfNamespace
+ ProtocolVersion_v13 ProtocolVersion = 13
+)
+
+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",
+}
+var 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,
+}
+
+func (x ProtocolVersion) Enum() *ProtocolVersion {
+ p := new(ProtocolVersion)
+ *p = x
+ return p
+}
+func (x ProtocolVersion) String() string {
+ return proto.EnumName(ProtocolVersion_name, int32(x))
+}
+func (x *ProtocolVersion) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(ProtocolVersion_value, data, "ProtocolVersion")
+ if err != nil {
+ return err
+ }
+ *x = ProtocolVersion(value)
+ return nil
+}
+func (ProtocolVersion) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{3}
+}
+
+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
+)
+
+var Schema_Type_name = map[int32]string{
+ 0: "None",
+ 1: "String",
+ 2: "Json",
+ 3: "Protobuf",
+ 4: "Avro",
+}
+var Schema_Type_value = map[string]int32{
+ "None": 0,
+ "String": 1,
+ "Json": 2,
+ "Protobuf": 3,
+ "Avro": 4,
+}
+
+func (x Schema_Type) Enum() *Schema_Type {
+ p := new(Schema_Type)
+ *p = x
+ return p
+}
+func (x Schema_Type) String() string {
+ return proto.EnumName(Schema_Type_name, int32(x))
+}
+func (x *Schema_Type) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(Schema_Type_value, data, "Schema_Type")
+ if err != nil {
+ return err
+ }
+ *x = Schema_Type(value)
+ return nil
+}
+func (Schema_Type) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{0, 0}
+}
+
+type CommandSubscribe_SubType int32
+
+const (
+ CommandSubscribe_Exclusive CommandSubscribe_SubType = 0
+ CommandSubscribe_Shared CommandSubscribe_SubType = 1
+ CommandSubscribe_Failover CommandSubscribe_SubType = 2
+)
+
+var CommandSubscribe_SubType_name = map[int32]string{
+ 0: "Exclusive",
+ 1: "Shared",
+ 2: "Failover",
+}
+var CommandSubscribe_SubType_value = map[string]int32{
+ "Exclusive": 0,
+ "Shared": 1,
+ "Failover": 2,
+}
+
+func (x CommandSubscribe_SubType) Enum() *CommandSubscribe_SubType {
+ p := new(CommandSubscribe_SubType)
+ *p = x
+ return p
+}
+func (x CommandSubscribe_SubType) String() string {
+ return proto.EnumName(CommandSubscribe_SubType_name, int32(x))
+}
+func (x *CommandSubscribe_SubType) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(CommandSubscribe_SubType_value, data, "CommandSubscribe_SubType")
+ if err != nil {
+ return err
+ }
+ *x = CommandSubscribe_SubType(value)
+ return nil
+}
+func (CommandSubscribe_SubType) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{9, 0}
+}
+
+type CommandSubscribe_InitialPosition int32
+
+const (
+ CommandSubscribe_Latest CommandSubscribe_InitialPosition = 0
+ CommandSubscribe_Earliest CommandSubscribe_InitialPosition = 1
+)
+
+var CommandSubscribe_InitialPosition_name = map[int32]string{
+ 0: "Latest",
+ 1: "Earliest",
+}
+var 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 proto.EnumName(CommandSubscribe_InitialPosition_name, int32(x))
+}
+func (x *CommandSubscribe_InitialPosition) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(CommandSubscribe_InitialPosition_value, data, "CommandSubscribe_InitialPosition")
+ if err != nil {
+ return err
+ }
+ *x = CommandSubscribe_InitialPosition(value)
+ return nil
+}
+func (CommandSubscribe_InitialPosition) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{9, 1}
+}
+
+type CommandPartitionedTopicMetadataResponse_LookupType int32
+
+const (
+ CommandPartitionedTopicMetadataResponse_Success CommandPartitionedTopicMetadataResponse_LookupType = 0
+ CommandPartitionedTopicMetadataResponse_Failed CommandPartitionedTopicMetadataResponse_LookupType = 1
+)
+
+var CommandPartitionedTopicMetadataResponse_LookupType_name = map[int32]string{
+ 0: "Success",
+ 1: "Failed",
+}
+var 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 proto.EnumName(CommandPartitionedTopicMetadataResponse_LookupType_name, int32(x))
+}
+func (x *CommandPartitionedTopicMetadataResponse_LookupType) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(CommandPartitionedTopicMetadataResponse_LookupType_value, data, "CommandPartitionedTopicMetadataResponse_LookupType")
+ if err != nil {
+ return err
+ }
+ *x = CommandPartitionedTopicMetadataResponse_LookupType(value)
+ return nil
+}
+func (CommandPartitionedTopicMetadataResponse_LookupType) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{11, 0}
+}
+
+type CommandLookupTopicResponse_LookupType int32
+
+const (
+ CommandLookupTopicResponse_Redirect CommandLookupTopicResponse_LookupType = 0
+ CommandLookupTopicResponse_Connect CommandLookupTopicResponse_LookupType = 1
+ CommandLookupTopicResponse_Failed CommandLookupTopicResponse_LookupType = 2
+)
+
+var CommandLookupTopicResponse_LookupType_name = map[int32]string{
+ 0: "Redirect",
+ 1: "Connect",
+ 2: "Failed",
+}
+var 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 proto.EnumName(CommandLookupTopicResponse_LookupType_name, int32(x))
+}
+func (x *CommandLookupTopicResponse_LookupType) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(CommandLookupTopicResponse_LookupType_value, data, "CommandLookupTopicResponse_LookupType")
+ if err != nil {
+ return err
+ }
+ *x = CommandLookupTopicResponse_LookupType(value)
+ return nil
+}
+func (CommandLookupTopicResponse_LookupType) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{13, 0}
+}
+
+type CommandAck_AckType int32
+
+const (
+ CommandAck_Individual CommandAck_AckType = 0
+ CommandAck_Cumulative CommandAck_AckType = 1
+)
+
+var CommandAck_AckType_name = map[int32]string{
+ 0: "Individual",
+ 1: "Cumulative",
+}
+var 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 proto.EnumName(CommandAck_AckType_name, int32(x))
+}
+func (x *CommandAck_AckType) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(CommandAck_AckType_value, data, "CommandAck_AckType")
+ if err != nil {
+ return err
+ }
+ *x = CommandAck_AckType(value)
+ return nil
+}
+func (CommandAck_AckType) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{19, 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
+)
+
+var CommandAck_ValidationError_name = map[int32]string{
+ 0: "UncompressedSizeCorruption",
+ 1: "DecompressionError",
+ 2: "ChecksumMismatch",
+ 3: "BatchDeSerializeError",
+ 4: "DecryptionError",
+}
+var 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 proto.EnumName(CommandAck_ValidationError_name, int32(x))
+}
+func (x *CommandAck_ValidationError) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(CommandAck_ValidationError_value, data, "CommandAck_ValidationError")
+ if err != nil {
+ return err
+ }
+ *x = CommandAck_ValidationError(value)
+ return nil
+}
+func (CommandAck_ValidationError) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{19, 1}
+}
+
+type CommandGetTopicsOfNamespace_Mode int32
+
+const (
+ CommandGetTopicsOfNamespace_PERSISTENT CommandGetTopicsOfNamespace_Mode = 0
+ CommandGetTopicsOfNamespace_NON_PERSISTENT CommandGetTopicsOfNamespace_Mode = 1
+ CommandGetTopicsOfNamespace_ALL CommandGetTopicsOfNamespace_Mode = 2
+)
+
+var CommandGetTopicsOfNamespace_Mode_name = map[int32]string{
+ 0: "PERSISTENT",
+ 1: "NON_PERSISTENT",
+ 2: "ALL",
+}
+var 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 proto.EnumName(CommandGetTopicsOfNamespace_Mode_name, int32(x))
+}
+func (x *CommandGetTopicsOfNamespace_Mode) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(CommandGetTopicsOfNamespace_Mode_value, data, "CommandGetTopicsOfNamespace_Mode")
+ if err != nil {
+ return err
+ }
+ *x = CommandGetTopicsOfNamespace_Mode(value)
+ return nil
+}
+func (CommandGetTopicsOfNamespace_Mode) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{37, 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
+)
+
+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",
+}
+var 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,
+}
+
+func (x BaseCommand_Type) Enum() *BaseCommand_Type {
+ p := new(BaseCommand_Type)
+ *p = x
+ return p
+}
+func (x BaseCommand_Type) String() string {
+ return proto.EnumName(BaseCommand_Type_name, int32(x))
+}
+func (x *BaseCommand_Type) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(BaseCommand_Type_value, data, "BaseCommand_Type")
+ if err != nil {
+ return err
+ }
+ *x = BaseCommand_Type(value)
+ return nil
+}
+func (BaseCommand_Type) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{41, 0}
+}
+
+type Schema struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Schema) Reset() { *m = Schema{} }
+func (m *Schema) String() string { return proto.CompactTextString(m) }
+func (*Schema) ProtoMessage() {}
+func (*Schema) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{0}
+}
+func (m *Schema) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Schema.Unmarshal(m, b)
+}
+func (m *Schema) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Schema.Marshal(b, m, deterministic)
+}
+func (dst *Schema) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Schema.Merge(dst, src)
+}
+func (m *Schema) XXX_Size() int {
+ return xxx_messageInfo_Schema.Size(m)
+}
+func (m *Schema) XXX_DiscardUnknown() {
+ xxx_messageInfo_Schema.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Schema proto.InternalMessageInfo
+
+func (m *Schema) GetName() string {
+ if m != nil && m.Name != nil {
+ return *m.Name
+ }
+ return ""
+}
+
+func (m *Schema) GetSchemaData() []byte {
+ if m != nil {
+ return m.SchemaData
+ }
+ return nil
+}
+
+func (m *Schema) GetType() Schema_Type {
+ if m != nil && m.Type != nil {
+ return *m.Type
+ }
+ return Schema_None
+}
+
+func (m *Schema) GetProperties() []*KeyValue {
+ if m != nil {
+ return m.Properties
+ }
+ return nil
+}
+
+type MessageIdData struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *MessageIdData) Reset() { *m = MessageIdData{} }
+func (m *MessageIdData) String() string { return proto.CompactTextString(m) }
+func (*MessageIdData) ProtoMessage() {}
+func (*MessageIdData) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{1}
+}
+func (m *MessageIdData) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_MessageIdData.Unmarshal(m, b)
+}
+func (m *MessageIdData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_MessageIdData.Marshal(b, m, deterministic)
+}
+func (dst *MessageIdData) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_MessageIdData.Merge(dst, src)
+}
+func (m *MessageIdData) XXX_Size() int {
+ return xxx_messageInfo_MessageIdData.Size(m)
+}
+func (m *MessageIdData) XXX_DiscardUnknown() {
+ xxx_messageInfo_MessageIdData.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MessageIdData proto.InternalMessageInfo
+
+const Default_MessageIdData_Partition int32 = -1
+const Default_MessageIdData_BatchIndex int32 = -1
+
+func (m *MessageIdData) GetLedgerId() uint64 {
+ if m != nil && m.LedgerId != nil {
+ return *m.LedgerId
+ }
+ return 0
+}
+
+func (m *MessageIdData) GetEntryId() uint64 {
+ if m != nil && m.EntryId != nil {
+ return *m.EntryId
+ }
+ return 0
+}
+
+func (m *MessageIdData) GetPartition() int32 {
+ if m != nil && m.Partition != nil {
+ return *m.Partition
+ }
+ return Default_MessageIdData_Partition
+}
+
+func (m *MessageIdData) GetBatchIndex() int32 {
+ if m != nil && m.BatchIndex != nil {
+ return *m.BatchIndex
+ }
+ return Default_MessageIdData_BatchIndex
+}
+
+type KeyValue struct {
+ Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
+ Value *string `protobuf:"bytes,2,req,name=value" json:"value,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *KeyValue) Reset() { *m = KeyValue{} }
+func (m *KeyValue) String() string { return proto.CompactTextString(m) }
+func (*KeyValue) ProtoMessage() {}
+func (*KeyValue) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{2}
+}
+func (m *KeyValue) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_KeyValue.Unmarshal(m, b)
+}
+func (m *KeyValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_KeyValue.Marshal(b, m, deterministic)
+}
+func (dst *KeyValue) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_KeyValue.Merge(dst, src)
+}
+func (m *KeyValue) XXX_Size() int {
+ return xxx_messageInfo_KeyValue.Size(m)
+}
+func (m *KeyValue) XXX_DiscardUnknown() {
+ xxx_messageInfo_KeyValue.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_KeyValue proto.InternalMessageInfo
+
+func (m *KeyValue) GetKey() string {
+ if m != nil && m.Key != nil {
+ return *m.Key
+ }
+ return ""
+}
+
+func (m *KeyValue) GetValue() string {
+ if m != nil && m.Value != nil {
+ return *m.Value
+ }
+ return ""
+}
+
+type KeyLongValue struct {
+ Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
+ Value *uint64 `protobuf:"varint,2,req,name=value" json:"value,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *KeyLongValue) Reset() { *m = KeyLongValue{} }
+func (m *KeyLongValue) String() string { return proto.CompactTextString(m) }
+func (*KeyLongValue) ProtoMessage() {}
+func (*KeyLongValue) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{3}
+}
+func (m *KeyLongValue) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_KeyLongValue.Unmarshal(m, b)
+}
+func (m *KeyLongValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_KeyLongValue.Marshal(b, m, deterministic)
+}
+func (dst *KeyLongValue) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_KeyLongValue.Merge(dst, src)
+}
+func (m *KeyLongValue) XXX_Size() int {
+ return xxx_messageInfo_KeyLongValue.Size(m)
+}
+func (m *KeyLongValue) XXX_DiscardUnknown() {
+ xxx_messageInfo_KeyLongValue.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_KeyLongValue proto.InternalMessageInfo
+
+func (m *KeyLongValue) GetKey() string {
+ if m != nil && m.Key != nil {
+ return *m.Key
+ }
+ return ""
+}
+
+func (m *KeyLongValue) GetValue() uint64 {
+ if m != nil && m.Value != nil {
+ return *m.Value
+ }
+ return 0
+}
+
+type EncryptionKeys struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *EncryptionKeys) Reset() { *m = EncryptionKeys{} }
+func (m *EncryptionKeys) String() string { return proto.CompactTextString(m) }
+func (*EncryptionKeys) ProtoMessage() {}
+func (*EncryptionKeys) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{4}
+}
+func (m *EncryptionKeys) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_EncryptionKeys.Unmarshal(m, b)
+}
+func (m *EncryptionKeys) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_EncryptionKeys.Marshal(b, m, deterministic)
+}
+func (dst *EncryptionKeys) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_EncryptionKeys.Merge(dst, src)
+}
+func (m *EncryptionKeys) XXX_Size() int {
+ return xxx_messageInfo_EncryptionKeys.Size(m)
+}
+func (m *EncryptionKeys) XXX_DiscardUnknown() {
+ xxx_messageInfo_EncryptionKeys.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_EncryptionKeys proto.InternalMessageInfo
+
+func (m *EncryptionKeys) GetKey() string {
+ if m != nil && m.Key != nil {
+ return *m.Key
+ }
+ return ""
+}
+
+func (m *EncryptionKeys) GetValue() []byte {
+ if m != nil {
+ return m.Value
+ }
+ return nil
+}
+
+func (m *EncryptionKeys) GetMetadata() []*KeyValue {
+ if m != nil {
+ return m.Metadata
+ }
+ return nil
+}
+
+type MessageMetadata struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *MessageMetadata) Reset() { *m = MessageMetadata{} }
+func (m *MessageMetadata) String() string { return proto.CompactTextString(m) }
+func (*MessageMetadata) ProtoMessage() {}
+func (*MessageMetadata) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{5}
+}
+func (m *MessageMetadata) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_MessageMetadata.Unmarshal(m, b)
+}
+func (m *MessageMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_MessageMetadata.Marshal(b, m, deterministic)
+}
+func (dst *MessageMetadata) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_MessageMetadata.Merge(dst, src)
+}
+func (m *MessageMetadata) XXX_Size() int {
+ return xxx_messageInfo_MessageMetadata.Size(m)
+}
+func (m *MessageMetadata) XXX_DiscardUnknown() {
+ xxx_messageInfo_MessageMetadata.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MessageMetadata proto.InternalMessageInfo
+
+const Default_MessageMetadata_Compression CompressionType = CompressionType_NONE
+const Default_MessageMetadata_UncompressedSize uint32 = 0
+const Default_MessageMetadata_NumMessagesInBatch int32 = 1
+const Default_MessageMetadata_EventTime uint64 = 0
+const Default_MessageMetadata_PartitionKeyB64Encoded bool = false
+
+func (m *MessageMetadata) GetProducerName() string {
+ if m != nil && m.ProducerName != nil {
+ return *m.ProducerName
+ }
+ return ""
+}
+
+func (m *MessageMetadata) GetSequenceId() uint64 {
+ if m != nil && m.SequenceId != nil {
+ return *m.SequenceId
+ }
+ return 0
+}
+
+func (m *MessageMetadata) GetPublishTime() uint64 {
+ if m != nil && m.PublishTime != nil {
+ return *m.PublishTime
+ }
+ return 0
+}
+
+func (m *MessageMetadata) GetProperties() []*KeyValue {
+ if m != nil {
+ return m.Properties
+ }
+ return nil
+}
+
+func (m *MessageMetadata) GetReplicatedFrom() string {
+ if m != nil && m.ReplicatedFrom != nil {
+ return *m.ReplicatedFrom
+ }
+ return ""
+}
+
+func (m *MessageMetadata) GetPartitionKey() string {
+ if m != nil && m.PartitionKey != nil {
+ return *m.PartitionKey
+ }
+ return ""
+}
+
+func (m *MessageMetadata) GetReplicateTo() []string {
+ if m != nil {
+ return m.ReplicateTo
+ }
+ return nil
+}
+
+func (m *MessageMetadata) GetCompression() CompressionType {
+ if m != nil && m.Compression != nil {
+ return *m.Compression
+ }
+ return Default_MessageMetadata_Compression
+}
+
+func (m *MessageMetadata) GetUncompressedSize() uint32 {
+ if m != nil && m.UncompressedSize != nil {
+ return *m.UncompressedSize
+ }
+ return Default_MessageMetadata_UncompressedSize
+}
+
+func (m *MessageMetadata) GetNumMessagesInBatch() int32 {
+ if m != nil && m.NumMessagesInBatch != nil {
+ return *m.NumMessagesInBatch
+ }
+ return Default_MessageMetadata_NumMessagesInBatch
+}
+
+func (m *MessageMetadata) GetEventTime() uint64 {
+ if m != nil && m.EventTime != nil {
+ return *m.EventTime
+ }
+ return Default_MessageMetadata_EventTime
+}
+
+func (m *MessageMetadata) GetEncryptionKeys() []*EncryptionKeys {
+ if m != nil {
+ return m.EncryptionKeys
+ }
+ return nil
+}
+
+func (m *MessageMetadata) GetEncryptionAlgo() string {
+ if m != nil && m.EncryptionAlgo != nil {
+ return *m.EncryptionAlgo
+ }
+ return ""
+}
+
+func (m *MessageMetadata) GetEncryptionParam() []byte {
+ if m != nil {
+ return m.EncryptionParam
+ }
+ return nil
+}
+
+func (m *MessageMetadata) GetSchemaVersion() []byte {
+ if m != nil {
+ return m.SchemaVersion
+ }
+ return nil
+}
+
+func (m *MessageMetadata) GetPartitionKeyB64Encoded() bool {
+ if m != nil && m.PartitionKeyB64Encoded != nil {
+ return *m.PartitionKeyB64Encoded
+ }
+ return Default_MessageMetadata_PartitionKeyB64Encoded
+}
+
+type SingleMessageMetadata struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *SingleMessageMetadata) Reset() { *m = SingleMessageMetadata{} }
+func (m *SingleMessageMetadata) String() string { return proto.CompactTextString(m) }
+func (*SingleMessageMetadata) ProtoMessage() {}
+func (*SingleMessageMetadata) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{6}
+}
+func (m *SingleMessageMetadata) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_SingleMessageMetadata.Unmarshal(m, b)
+}
+func (m *SingleMessageMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_SingleMessageMetadata.Marshal(b, m, deterministic)
+}
+func (dst *SingleMessageMetadata) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_SingleMessageMetadata.Merge(dst, src)
+}
+func (m *SingleMessageMetadata) XXX_Size() int {
+ return xxx_messageInfo_SingleMessageMetadata.Size(m)
+}
+func (m *SingleMessageMetadata) XXX_DiscardUnknown() {
+ xxx_messageInfo_SingleMessageMetadata.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_SingleMessageMetadata proto.InternalMessageInfo
+
+const Default_SingleMessageMetadata_CompactedOut bool = false
+const Default_SingleMessageMetadata_EventTime uint64 = 0
+const Default_SingleMessageMetadata_PartitionKeyB64Encoded bool = false
+
+func (m *SingleMessageMetadata) GetProperties() []*KeyValue {
+ if m != nil {
+ return m.Properties
+ }
+ return nil
+}
+
+func (m *SingleMessageMetadata) GetPartitionKey() string {
+ if m != nil && m.PartitionKey != nil {
+ return *m.PartitionKey
+ }
+ return ""
+}
+
+func (m *SingleMessageMetadata) GetPayloadSize() int32 {
+ if m != nil && m.PayloadSize != nil {
+ return *m.PayloadSize
+ }
+ return 0
+}
+
+func (m *SingleMessageMetadata) GetCompactedOut() bool {
+ if m != nil && m.CompactedOut != nil {
+ return *m.CompactedOut
+ }
+ return Default_SingleMessageMetadata_CompactedOut
+}
+
+func (m *SingleMessageMetadata) GetEventTime() uint64 {
+ if m != nil && m.EventTime != nil {
+ return *m.EventTime
+ }
+ return Default_SingleMessageMetadata_EventTime
+}
+
+func (m *SingleMessageMetadata) GetPartitionKeyB64Encoded() bool {
+ if m != nil && m.PartitionKeyB64Encoded != nil {
+ return *m.PartitionKeyB64Encoded
+ }
+ return Default_SingleMessageMetadata_PartitionKeyB64Encoded
+}
+
+type CommandConnect struct {
+ 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"`
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandConnect) Reset() { *m = CommandConnect{} }
+func (m *CommandConnect) String() string { return proto.CompactTextString(m) }
+func (*CommandConnect) ProtoMessage() {}
+func (*CommandConnect) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{7}
+}
+func (m *CommandConnect) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandConnect.Unmarshal(m, b)
+}
+func (m *CommandConnect) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandConnect.Marshal(b, m, deterministic)
+}
+func (dst *CommandConnect) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandConnect.Merge(dst, src)
+}
+func (m *CommandConnect) XXX_Size() int {
+ return xxx_messageInfo_CommandConnect.Size(m)
+}
+func (m *CommandConnect) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandConnect.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandConnect proto.InternalMessageInfo
+
+const Default_CommandConnect_ProtocolVersion int32 = 0
+
+func (m *CommandConnect) GetClientVersion() string {
+ if m != nil && m.ClientVersion != nil {
+ return *m.ClientVersion
+ }
+ return ""
+}
+
+func (m *CommandConnect) GetAuthMethod() AuthMethod {
+ if m != nil && m.AuthMethod != nil {
+ return *m.AuthMethod
+ }
+ return AuthMethod_AuthMethodNone
+}
+
+func (m *CommandConnect) GetAuthMethodName() string {
+ if m != nil && m.AuthMethodName != nil {
+ return *m.AuthMethodName
+ }
+ return ""
+}
+
+func (m *CommandConnect) GetAuthData() []byte {
+ if m != nil {
+ return m.AuthData
+ }
+ return nil
+}
+
+func (m *CommandConnect) GetProtocolVersion() int32 {
+ if m != nil && m.ProtocolVersion != nil {
+ return *m.ProtocolVersion
+ }
+ return Default_CommandConnect_ProtocolVersion
+}
+
+func (m *CommandConnect) GetProxyToBrokerUrl() string {
+ if m != nil && m.ProxyToBrokerUrl != nil {
+ return *m.ProxyToBrokerUrl
+ }
+ return ""
+}
+
+func (m *CommandConnect) GetOriginalPrincipal() string {
+ if m != nil && m.OriginalPrincipal != nil {
+ return *m.OriginalPrincipal
+ }
+ return ""
+}
+
+func (m *CommandConnect) GetOriginalAuthData() string {
+ if m != nil && m.OriginalAuthData != nil {
+ return *m.OriginalAuthData
+ }
+ return ""
+}
+
+func (m *CommandConnect) GetOriginalAuthMethod() string {
+ if m != nil && m.OriginalAuthMethod != nil {
+ return *m.OriginalAuthMethod
+ }
+ return ""
+}
+
+type CommandConnected struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandConnected) Reset() { *m = CommandConnected{} }
+func (m *CommandConnected) String() string { return proto.CompactTextString(m) }
+func (*CommandConnected) ProtoMessage() {}
+func (*CommandConnected) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{8}
+}
+func (m *CommandConnected) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandConnected.Unmarshal(m, b)
+}
+func (m *CommandConnected) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandConnected.Marshal(b, m, deterministic)
+}
+func (dst *CommandConnected) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandConnected.Merge(dst, src)
+}
+func (m *CommandConnected) XXX_Size() int {
+ return xxx_messageInfo_CommandConnected.Size(m)
+}
+func (m *CommandConnected) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandConnected.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandConnected proto.InternalMessageInfo
+
+const Default_CommandConnected_ProtocolVersion int32 = 0
+
+func (m *CommandConnected) GetServerVersion() string {
+ if m != nil && m.ServerVersion != nil {
+ return *m.ServerVersion
+ }
+ return ""
+}
+
+func (m *CommandConnected) GetProtocolVersion() int32 {
+ if m != nil && m.ProtocolVersion != nil {
+ return *m.ProtocolVersion
+ }
+ return Default_CommandConnected_ProtocolVersion
+}
+
+type CommandSubscribe struct {
+ 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 wthether 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandSubscribe) Reset() { *m = CommandSubscribe{} }
+func (m *CommandSubscribe) String() string { return proto.CompactTextString(m) }
+func (*CommandSubscribe) ProtoMessage() {}
+func (*CommandSubscribe) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{9}
+}
+func (m *CommandSubscribe) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandSubscribe.Unmarshal(m, b)
+}
+func (m *CommandSubscribe) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandSubscribe.Marshal(b, m, deterministic)
+}
+func (dst *CommandSubscribe) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandSubscribe.Merge(dst, src)
+}
+func (m *CommandSubscribe) XXX_Size() int {
+ return xxx_messageInfo_CommandSubscribe.Size(m)
+}
+func (m *CommandSubscribe) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandSubscribe.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandSubscribe proto.InternalMessageInfo
+
+const Default_CommandSubscribe_Durable bool = true
+const Default_CommandSubscribe_InitialPosition CommandSubscribe_InitialPosition = CommandSubscribe_Latest
+
+func (m *CommandSubscribe) GetTopic() string {
+ if m != nil && m.Topic != nil {
+ return *m.Topic
+ }
+ return ""
+}
+
+func (m *CommandSubscribe) GetSubscription() string {
+ if m != nil && m.Subscription != nil {
+ return *m.Subscription
+ }
+ return ""
+}
+
+func (m *CommandSubscribe) GetSubType() CommandSubscribe_SubType {
+ if m != nil && m.SubType != nil {
+ return *m.SubType
+ }
+ return CommandSubscribe_Exclusive
+}
+
+func (m *CommandSubscribe) GetConsumerId() uint64 {
+ if m != nil && m.ConsumerId != nil {
+ return *m.ConsumerId
+ }
+ return 0
+}
+
+func (m *CommandSubscribe) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandSubscribe) GetConsumerName() string {
+ if m != nil && m.ConsumerName != nil {
+ return *m.ConsumerName
+ }
+ return ""
+}
+
+func (m *CommandSubscribe) GetPriorityLevel() int32 {
+ if m != nil && m.PriorityLevel != nil {
+ return *m.PriorityLevel
+ }
+ return 0
+}
+
+func (m *CommandSubscribe) GetDurable() bool {
+ if m != nil && m.Durable != nil {
+ return *m.Durable
+ }
+ return Default_CommandSubscribe_Durable
+}
+
+func (m *CommandSubscribe) GetStartMessageId() *MessageIdData {
+ if m != nil {
+ return m.StartMessageId
+ }
+ return nil
+}
+
+func (m *CommandSubscribe) GetMetadata() []*KeyValue {
+ if m != nil {
+ return m.Metadata
+ }
+ return nil
+}
+
+func (m *CommandSubscribe) GetReadCompacted() bool {
+ if m != nil && m.ReadCompacted != nil {
+ return *m.ReadCompacted
+ }
+ return false
+}
+
+func (m *CommandSubscribe) GetSchema() *Schema {
+ if m != nil {
+ return m.Schema
+ }
+ return nil
+}
+
+func (m *CommandSubscribe) GetInitialPosition() CommandSubscribe_InitialPosition {
+ if m != nil && m.InitialPosition != nil {
+ return *m.InitialPosition
+ }
+ return Default_CommandSubscribe_InitialPosition
+}
+
+type CommandPartitionedTopicMetadata struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandPartitionedTopicMetadata) Reset() { *m = CommandPartitionedTopicMetadata{} }
+func (m *CommandPartitionedTopicMetadata) String() string { return proto.CompactTextString(m) }
+func (*CommandPartitionedTopicMetadata) ProtoMessage() {}
+func (*CommandPartitionedTopicMetadata) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{10}
+}
+func (m *CommandPartitionedTopicMetadata) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandPartitionedTopicMetadata.Unmarshal(m, b)
+}
+func (m *CommandPartitionedTopicMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandPartitionedTopicMetadata.Marshal(b, m, deterministic)
+}
+func (dst *CommandPartitionedTopicMetadata) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandPartitionedTopicMetadata.Merge(dst, src)
+}
+func (m *CommandPartitionedTopicMetadata) XXX_Size() int {
+ return xxx_messageInfo_CommandPartitionedTopicMetadata.Size(m)
+}
+func (m *CommandPartitionedTopicMetadata) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandPartitionedTopicMetadata.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandPartitionedTopicMetadata proto.InternalMessageInfo
+
+func (m *CommandPartitionedTopicMetadata) GetTopic() string {
+ if m != nil && m.Topic != nil {
+ return *m.Topic
+ }
+ return ""
+}
+
+func (m *CommandPartitionedTopicMetadata) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandPartitionedTopicMetadata) GetOriginalPrincipal() string {
+ if m != nil && m.OriginalPrincipal != nil {
+ return *m.OriginalPrincipal
+ }
+ return ""
+}
+
+func (m *CommandPartitionedTopicMetadata) GetOriginalAuthData() string {
+ if m != nil && m.OriginalAuthData != nil {
+ return *m.OriginalAuthData
+ }
+ return ""
+}
+
+func (m *CommandPartitionedTopicMetadata) GetOriginalAuthMethod() string {
+ if m != nil && m.OriginalAuthMethod != nil {
+ return *m.OriginalAuthMethod
+ }
+ return ""
+}
+
+type CommandPartitionedTopicMetadataResponse struct {
+ Partitions *uint32 `protobuf:"varint,1,opt,name=partitions" json:"partitions,omitempty"`
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandPartitionedTopicMetadataResponse) Reset() {
+ *m = CommandPartitionedTopicMetadataResponse{}
+}
+func (m *CommandPartitionedTopicMetadataResponse) String() string { return proto.CompactTextString(m) }
+func (*CommandPartitionedTopicMetadataResponse) ProtoMessage() {}
+func (*CommandPartitionedTopicMetadataResponse) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{11}
+}
+func (m *CommandPartitionedTopicMetadataResponse) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandPartitionedTopicMetadataResponse.Unmarshal(m, b)
+}
+func (m *CommandPartitionedTopicMetadataResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandPartitionedTopicMetadataResponse.Marshal(b, m, deterministic)
+}
+func (dst *CommandPartitionedTopicMetadataResponse) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandPartitionedTopicMetadataResponse.Merge(dst, src)
+}
+func (m *CommandPartitionedTopicMetadataResponse) XXX_Size() int {
+ return xxx_messageInfo_CommandPartitionedTopicMetadataResponse.Size(m)
+}
+func (m *CommandPartitionedTopicMetadataResponse) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandPartitionedTopicMetadataResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandPartitionedTopicMetadataResponse proto.InternalMessageInfo
+
+func (m *CommandPartitionedTopicMetadataResponse) GetPartitions() uint32 {
+ if m != nil && m.Partitions != nil {
+ return *m.Partitions
+ }
+ return 0
+}
+
+func (m *CommandPartitionedTopicMetadataResponse) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandPartitionedTopicMetadataResponse) GetResponse() CommandPartitionedTopicMetadataResponse_LookupType {
+ if m != nil && m.Response != nil {
+ return *m.Response
+ }
+ return CommandPartitionedTopicMetadataResponse_Success
+}
+
+func (m *CommandPartitionedTopicMetadataResponse) GetError() ServerError {
+ if m != nil && m.Error != nil {
+ return *m.Error
+ }
+ return ServerError_UnknownError
+}
+
+func (m *CommandPartitionedTopicMetadataResponse) GetMessage() string {
+ if m != nil && m.Message != nil {
+ return *m.Message
+ }
+ return ""
+}
+
+type CommandLookupTopic struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandLookupTopic) Reset() { *m = CommandLookupTopic{} }
+func (m *CommandLookupTopic) String() string { return proto.CompactTextString(m) }
+func (*CommandLookupTopic) ProtoMessage() {}
+func (*CommandLookupTopic) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{12}
+}
+func (m *CommandLookupTopic) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandLookupTopic.Unmarshal(m, b)
+}
+func (m *CommandLookupTopic) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandLookupTopic.Marshal(b, m, deterministic)
+}
+func (dst *CommandLookupTopic) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandLookupTopic.Merge(dst, src)
+}
+func (m *CommandLookupTopic) XXX_Size() int {
+ return xxx_messageInfo_CommandLookupTopic.Size(m)
+}
+func (m *CommandLookupTopic) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandLookupTopic.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandLookupTopic proto.InternalMessageInfo
+
+const Default_CommandLookupTopic_Authoritative bool = false
+
+func (m *CommandLookupTopic) GetTopic() string {
+ if m != nil && m.Topic != nil {
+ return *m.Topic
+ }
+ return ""
+}
+
+func (m *CommandLookupTopic) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandLookupTopic) GetAuthoritative() bool {
+ if m != nil && m.Authoritative != nil {
+ return *m.Authoritative
+ }
+ return Default_CommandLookupTopic_Authoritative
+}
+
+func (m *CommandLookupTopic) GetOriginalPrincipal() string {
+ if m != nil && m.OriginalPrincipal != nil {
+ return *m.OriginalPrincipal
+ }
+ return ""
+}
+
+func (m *CommandLookupTopic) GetOriginalAuthData() string {
+ if m != nil && m.OriginalAuthData != nil {
+ return *m.OriginalAuthData
+ }
+ return ""
+}
+
+func (m *CommandLookupTopic) GetOriginalAuthMethod() string {
+ if m != nil && m.OriginalAuthMethod != nil {
+ return *m.OriginalAuthMethod
+ }
+ return ""
+}
+
+type CommandLookupTopicResponse struct {
+ BrokerServiceUrl *string `protobuf:"bytes,1,opt,name=brokerServiceUrl" json:"brokerServiceUrl,omitempty"`
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandLookupTopicResponse) Reset() { *m = CommandLookupTopicResponse{} }
+func (m *CommandLookupTopicResponse) String() string { return proto.CompactTextString(m) }
+func (*CommandLookupTopicResponse) ProtoMessage() {}
+func (*CommandLookupTopicResponse) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{13}
+}
+func (m *CommandLookupTopicResponse) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandLookupTopicResponse.Unmarshal(m, b)
+}
+func (m *CommandLookupTopicResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandLookupTopicResponse.Marshal(b, m, deterministic)
+}
+func (dst *CommandLookupTopicResponse) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandLookupTopicResponse.Merge(dst, src)
+}
+func (m *CommandLookupTopicResponse) XXX_Size() int {
+ return xxx_messageInfo_CommandLookupTopicResponse.Size(m)
+}
+func (m *CommandLookupTopicResponse) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandLookupTopicResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandLookupTopicResponse proto.InternalMessageInfo
+
+const Default_CommandLookupTopicResponse_Authoritative bool = false
+const Default_CommandLookupTopicResponse_ProxyThroughServiceUrl bool = false
+
+func (m *CommandLookupTopicResponse) GetBrokerServiceUrl() string {
+ if m != nil && m.BrokerServiceUrl != nil {
+ return *m.BrokerServiceUrl
+ }
+ return ""
+}
+
+func (m *CommandLookupTopicResponse) GetBrokerServiceUrlTls() string {
+ if m != nil && m.BrokerServiceUrlTls != nil {
+ return *m.BrokerServiceUrlTls
+ }
+ return ""
+}
+
+func (m *CommandLookupTopicResponse) GetResponse() CommandLookupTopicResponse_LookupType {
+ if m != nil && m.Response != nil {
+ return *m.Response
+ }
+ return CommandLookupTopicResponse_Redirect
+}
+
+func (m *CommandLookupTopicResponse) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandLookupTopicResponse) GetAuthoritative() bool {
+ if m != nil && m.Authoritative != nil {
+ return *m.Authoritative
+ }
+ return Default_CommandLookupTopicResponse_Authoritative
+}
+
+func (m *CommandLookupTopicResponse) GetError() ServerError {
+ if m != nil && m.Error != nil {
+ return *m.Error
+ }
+ return ServerError_UnknownError
+}
+
+func (m *CommandLookupTopicResponse) GetMessage() string {
+ if m != nil && m.Message != nil {
+ return *m.Message
+ }
+ return ""
+}
+
+func (m *CommandLookupTopicResponse) GetProxyThroughServiceUrl() bool {
+ if m != nil && m.ProxyThroughServiceUrl != nil {
+ return *m.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 {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandProducer) Reset() { *m = CommandProducer{} }
+func (m *CommandProducer) String() string { return proto.CompactTextString(m) }
+func (*CommandProducer) ProtoMessage() {}
+func (*CommandProducer) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{14}
+}
+func (m *CommandProducer) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandProducer.Unmarshal(m, b)
+}
+func (m *CommandProducer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandProducer.Marshal(b, m, deterministic)
+}
+func (dst *CommandProducer) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandProducer.Merge(dst, src)
+}
+func (m *CommandProducer) XXX_Size() int {
+ return xxx_messageInfo_CommandProducer.Size(m)
+}
+func (m *CommandProducer) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandProducer.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandProducer proto.InternalMessageInfo
+
+const Default_CommandProducer_Encrypted bool = false
+
+func (m *CommandProducer) GetTopic() string {
+ if m != nil && m.Topic != nil {
+ return *m.Topic
+ }
+ return ""
+}
+
+func (m *CommandProducer) GetProducerId() uint64 {
+ if m != nil && m.ProducerId != nil {
+ return *m.ProducerId
+ }
+ return 0
+}
+
+func (m *CommandProducer) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandProducer) GetProducerName() string {
+ if m != nil && m.ProducerName != nil {
+ return *m.ProducerName
+ }
+ return ""
+}
+
+func (m *CommandProducer) GetEncrypted() bool {
+ if m != nil && m.Encrypted != nil {
+ return *m.Encrypted
+ }
+ return Default_CommandProducer_Encrypted
+}
+
+func (m *CommandProducer) GetMetadata() []*KeyValue {
+ if m != nil {
+ return m.Metadata
+ }
+ return nil
+}
+
+func (m *CommandProducer) GetSchema() *Schema {
+ if m != nil {
+ return m.Schema
+ }
+ return nil
+}
+
+type CommandSend struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandSend) Reset() { *m = CommandSend{} }
+func (m *CommandSend) String() string { return proto.CompactTextString(m) }
+func (*CommandSend) ProtoMessage() {}
+func (*CommandSend) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{15}
+}
+func (m *CommandSend) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandSend.Unmarshal(m, b)
+}
+func (m *CommandSend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandSend.Marshal(b, m, deterministic)
+}
+func (dst *CommandSend) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandSend.Merge(dst, src)
+}
+func (m *CommandSend) XXX_Size() int {
+ return xxx_messageInfo_CommandSend.Size(m)
+}
+func (m *CommandSend) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandSend.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandSend proto.InternalMessageInfo
+
+const Default_CommandSend_NumMessages int32 = 1
+
+func (m *CommandSend) GetProducerId() uint64 {
+ if m != nil && m.ProducerId != nil {
+ return *m.ProducerId
+ }
+ return 0
+}
+
+func (m *CommandSend) GetSequenceId() uint64 {
+ if m != nil && m.SequenceId != nil {
+ return *m.SequenceId
+ }
+ return 0
+}
+
+func (m *CommandSend) GetNumMessages() int32 {
+ if m != nil && m.NumMessages != nil {
+ return *m.NumMessages
+ }
+ return Default_CommandSend_NumMessages
+}
+
+type CommandSendReceipt struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandSendReceipt) Reset() { *m = CommandSendReceipt{} }
+func (m *CommandSendReceipt) String() string { return proto.CompactTextString(m) }
+func (*CommandSendReceipt) ProtoMessage() {}
+func (*CommandSendReceipt) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{16}
+}
+func (m *CommandSendReceipt) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandSendReceipt.Unmarshal(m, b)
+}
+func (m *CommandSendReceipt) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandSendReceipt.Marshal(b, m, deterministic)
+}
+func (dst *CommandSendReceipt) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandSendReceipt.Merge(dst, src)
+}
+func (m *CommandSendReceipt) XXX_Size() int {
+ return xxx_messageInfo_CommandSendReceipt.Size(m)
+}
+func (m *CommandSendReceipt) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandSendReceipt.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandSendReceipt proto.InternalMessageInfo
+
+func (m *CommandSendReceipt) GetProducerId() uint64 {
+ if m != nil && m.ProducerId != nil {
+ return *m.ProducerId
+ }
+ return 0
+}
+
+func (m *CommandSendReceipt) GetSequenceId() uint64 {
+ if m != nil && m.SequenceId != nil {
+ return *m.SequenceId
+ }
+ return 0
+}
+
+func (m *CommandSendReceipt) GetMessageId() *MessageIdData {
+ if m != nil {
+ return m.MessageId
+ }
+ return nil
+}
+
+type CommandSendError struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandSendError) Reset() { *m = CommandSendError{} }
+func (m *CommandSendError) String() string { return proto.CompactTextString(m) }
+func (*CommandSendError) ProtoMessage() {}
+func (*CommandSendError) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{17}
+}
+func (m *CommandSendError) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandSendError.Unmarshal(m, b)
+}
+func (m *CommandSendError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandSendError.Marshal(b, m, deterministic)
+}
+func (dst *CommandSendError) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandSendError.Merge(dst, src)
+}
+func (m *CommandSendError) XXX_Size() int {
+ return xxx_messageInfo_CommandSendError.Size(m)
+}
+func (m *CommandSendError) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandSendError.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandSendError proto.InternalMessageInfo
+
+func (m *CommandSendError) GetProducerId() uint64 {
+ if m != nil && m.ProducerId != nil {
+ return *m.ProducerId
+ }
+ return 0
+}
+
+func (m *CommandSendError) GetSequenceId() uint64 {
+ if m != nil && m.SequenceId != nil {
+ return *m.SequenceId
+ }
+ return 0
+}
+
+func (m *CommandSendError) GetError() ServerError {
+ if m != nil && m.Error != nil {
+ return *m.Error
+ }
+ return ServerError_UnknownError
+}
+
+func (m *CommandSendError) GetMessage() string {
+ if m != nil && m.Message != nil {
+ return *m.Message
+ }
+ return ""
+}
+
+type CommandMessage struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandMessage) Reset() { *m = CommandMessage{} }
+func (m *CommandMessage) String() string { return proto.CompactTextString(m) }
+func (*CommandMessage) ProtoMessage() {}
+func (*CommandMessage) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{18}
+}
+func (m *CommandMessage) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandMessage.Unmarshal(m, b)
+}
+func (m *CommandMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandMessage.Marshal(b, m, deterministic)
+}
+func (dst *CommandMessage) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandMessage.Merge(dst, src)
+}
+func (m *CommandMessage) XXX_Size() int {
+ return xxx_messageInfo_CommandMessage.Size(m)
+}
+func (m *CommandMessage) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandMessage.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandMessage proto.InternalMessageInfo
+
+const Default_CommandMessage_RedeliveryCount uint32 = 0
+
+func (m *CommandMessage) GetConsumerId() uint64 {
+ if m != nil && m.ConsumerId != nil {
+ return *m.ConsumerId
+ }
+ return 0
+}
+
+func (m *CommandMessage) GetMessageId() *MessageIdData {
+ if m != nil {
+ return m.MessageId
+ }
+ return nil
+}
+
+func (m *CommandMessage) GetRedeliveryCount() uint32 {
+ if m != nil && m.RedeliveryCount != nil {
+ return *m.RedeliveryCount
+ }
+ return Default_CommandMessage_RedeliveryCount
+}
+
+type CommandAck struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandAck) Reset() { *m = CommandAck{} }
+func (m *CommandAck) String() string { return proto.CompactTextString(m) }
+func (*CommandAck) ProtoMessage() {}
+func (*CommandAck) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{19}
+}
+func (m *CommandAck) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandAck.Unmarshal(m, b)
+}
+func (m *CommandAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandAck.Marshal(b, m, deterministic)
+}
+func (dst *CommandAck) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandAck.Merge(dst, src)
+}
+func (m *CommandAck) XXX_Size() int {
+ return xxx_messageInfo_CommandAck.Size(m)
+}
+func (m *CommandAck) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandAck.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandAck proto.InternalMessageInfo
+
+func (m *CommandAck) GetConsumerId() uint64 {
+ if m != nil && m.ConsumerId != nil {
+ return *m.ConsumerId
+ }
+ return 0
+}
+
+func (m *CommandAck) GetAckType() CommandAck_AckType {
+ if m != nil && m.AckType != nil {
+ return *m.AckType
+ }
+ return CommandAck_Individual
+}
+
+func (m *CommandAck) GetMessageId() []*MessageIdData {
+ if m != nil {
+ return m.MessageId
+ }
+ return nil
+}
+
+func (m *CommandAck) GetValidationError() CommandAck_ValidationError {
+ if m != nil && m.ValidationError != nil {
+ return *m.ValidationError
+ }
+ return CommandAck_UncompressedSizeCorruption
+}
+
+func (m *CommandAck) GetProperties() []*KeyLongValue {
+ if m != nil {
+ return m.Properties
+ }
+ return nil
+}
+
+// changes on active consumer
+type CommandActiveConsumerChange struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandActiveConsumerChange) Reset() { *m = CommandActiveConsumerChange{} }
+func (m *CommandActiveConsumerChange) String() string { return proto.CompactTextString(m) }
+func (*CommandActiveConsumerChange) ProtoMessage() {}
+func (*CommandActiveConsumerChange) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{20}
+}
+func (m *CommandActiveConsumerChange) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandActiveConsumerChange.Unmarshal(m, b)
+}
+func (m *CommandActiveConsumerChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandActiveConsumerChange.Marshal(b, m, deterministic)
+}
+func (dst *CommandActiveConsumerChange) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandActiveConsumerChange.Merge(dst, src)
+}
+func (m *CommandActiveConsumerChange) XXX_Size() int {
+ return xxx_messageInfo_CommandActiveConsumerChange.Size(m)
+}
+func (m *CommandActiveConsumerChange) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandActiveConsumerChange.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandActiveConsumerChange proto.InternalMessageInfo
+
+const Default_CommandActiveConsumerChange_IsActive bool = false
+
+func (m *CommandActiveConsumerChange) GetConsumerId() uint64 {
+ if m != nil && m.ConsumerId != nil {
+ return *m.ConsumerId
+ }
+ return 0
+}
+
+func (m *CommandActiveConsumerChange) GetIsActive() bool {
+ if m != nil && m.IsActive != nil {
+ return *m.IsActive
+ }
+ return Default_CommandActiveConsumerChange_IsActive
+}
+
+type CommandFlow struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandFlow) Reset() { *m = CommandFlow{} }
+func (m *CommandFlow) String() string { return proto.CompactTextString(m) }
+func (*CommandFlow) ProtoMessage() {}
+func (*CommandFlow) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{21}
+}
+func (m *CommandFlow) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandFlow.Unmarshal(m, b)
+}
+func (m *CommandFlow) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandFlow.Marshal(b, m, deterministic)
+}
+func (dst *CommandFlow) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandFlow.Merge(dst, src)
+}
+func (m *CommandFlow) XXX_Size() int {
+ return xxx_messageInfo_CommandFlow.Size(m)
+}
+func (m *CommandFlow) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandFlow.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandFlow proto.InternalMessageInfo
+
+func (m *CommandFlow) GetConsumerId() uint64 {
+ if m != nil && m.ConsumerId != nil {
+ return *m.ConsumerId
+ }
+ return 0
+}
+
+func (m *CommandFlow) GetMessagePermits() uint32 {
+ if m != nil && m.MessagePermits != nil {
+ return *m.MessagePermits
+ }
+ return 0
+}
+
+type CommandUnsubscribe struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandUnsubscribe) Reset() { *m = CommandUnsubscribe{} }
+func (m *CommandUnsubscribe) String() string { return proto.CompactTextString(m) }
+func (*CommandUnsubscribe) ProtoMessage() {}
+func (*CommandUnsubscribe) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{22}
+}
+func (m *CommandUnsubscribe) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandUnsubscribe.Unmarshal(m, b)
+}
+func (m *CommandUnsubscribe) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandUnsubscribe.Marshal(b, m, deterministic)
+}
+func (dst *CommandUnsubscribe) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandUnsubscribe.Merge(dst, src)
+}
+func (m *CommandUnsubscribe) XXX_Size() int {
+ return xxx_messageInfo_CommandUnsubscribe.Size(m)
+}
+func (m *CommandUnsubscribe) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandUnsubscribe.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandUnsubscribe proto.InternalMessageInfo
+
+func (m *CommandUnsubscribe) GetConsumerId() uint64 {
+ if m != nil && m.ConsumerId != nil {
+ return *m.ConsumerId
+ }
+ return 0
+}
+
+func (m *CommandUnsubscribe) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+// Reset an existing consumer to a particular message id
+type CommandSeek struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandSeek) Reset() { *m = CommandSeek{} }
+func (m *CommandSeek) String() string { return proto.CompactTextString(m) }
+func (*CommandSeek) ProtoMessage() {}
+func (*CommandSeek) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{23}
+}
+func (m *CommandSeek) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandSeek.Unmarshal(m, b)
+}
+func (m *CommandSeek) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandSeek.Marshal(b, m, deterministic)
+}
+func (dst *CommandSeek) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandSeek.Merge(dst, src)
+}
+func (m *CommandSeek) XXX_Size() int {
+ return xxx_messageInfo_CommandSeek.Size(m)
+}
+func (m *CommandSeek) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandSeek.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandSeek proto.InternalMessageInfo
+
+func (m *CommandSeek) GetConsumerId() uint64 {
+ if m != nil && m.ConsumerId != nil {
+ return *m.ConsumerId
+ }
+ return 0
+}
+
+func (m *CommandSeek) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandSeek) GetMessageId() *MessageIdData {
+ if m != nil {
+ return m.MessageId
+ }
+ return nil
+}
+
+// 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 {
+ ConsumerId *uint64 `protobuf:"varint,1,req,name=consumer_id,json=consumerId" json:"consumer_id,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandReachedEndOfTopic) Reset() { *m = CommandReachedEndOfTopic{} }
+func (m *CommandReachedEndOfTopic) String() string { return proto.CompactTextString(m) }
+func (*CommandReachedEndOfTopic) ProtoMessage() {}
+func (*CommandReachedEndOfTopic) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{24}
+}
+func (m *CommandReachedEndOfTopic) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandReachedEndOfTopic.Unmarshal(m, b)
+}
+func (m *CommandReachedEndOfTopic) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandReachedEndOfTopic.Marshal(b, m, deterministic)
+}
+func (dst *CommandReachedEndOfTopic) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandReachedEndOfTopic.Merge(dst, src)
+}
+func (m *CommandReachedEndOfTopic) XXX_Size() int {
+ return xxx_messageInfo_CommandReachedEndOfTopic.Size(m)
+}
+func (m *CommandReachedEndOfTopic) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandReachedEndOfTopic.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandReachedEndOfTopic proto.InternalMessageInfo
+
+func (m *CommandReachedEndOfTopic) GetConsumerId() uint64 {
+ if m != nil && m.ConsumerId != nil {
+ return *m.ConsumerId
+ }
+ return 0
+}
+
+type CommandCloseProducer struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandCloseProducer) Reset() { *m = CommandCloseProducer{} }
+func (m *CommandCloseProducer) String() string { return proto.CompactTextString(m) }
+func (*CommandCloseProducer) ProtoMessage() {}
+func (*CommandCloseProducer) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{25}
+}
+func (m *CommandCloseProducer) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandCloseProducer.Unmarshal(m, b)
+}
+func (m *CommandCloseProducer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandCloseProducer.Marshal(b, m, deterministic)
+}
+func (dst *CommandCloseProducer) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandCloseProducer.Merge(dst, src)
+}
+func (m *CommandCloseProducer) XXX_Size() int {
+ return xxx_messageInfo_CommandCloseProducer.Size(m)
+}
+func (m *CommandCloseProducer) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandCloseProducer.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandCloseProducer proto.InternalMessageInfo
+
+func (m *CommandCloseProducer) GetProducerId() uint64 {
+ if m != nil && m.ProducerId != nil {
+ return *m.ProducerId
+ }
+ return 0
+}
+
+func (m *CommandCloseProducer) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+type CommandCloseConsumer struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandCloseConsumer) Reset() { *m = CommandCloseConsumer{} }
+func (m *CommandCloseConsumer) String() string { return proto.CompactTextString(m) }
+func (*CommandCloseConsumer) ProtoMessage() {}
+func (*CommandCloseConsumer) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{26}
+}
+func (m *CommandCloseConsumer) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandCloseConsumer.Unmarshal(m, b)
+}
+func (m *CommandCloseConsumer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandCloseConsumer.Marshal(b, m, deterministic)
+}
+func (dst *CommandCloseConsumer) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandCloseConsumer.Merge(dst, src)
+}
+func (m *CommandCloseConsumer) XXX_Size() int {
+ return xxx_messageInfo_CommandCloseConsumer.Size(m)
+}
+func (m *CommandCloseConsumer) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandCloseConsumer.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandCloseConsumer proto.InternalMessageInfo
+
+func (m *CommandCloseConsumer) GetConsumerId() uint64 {
+ if m != nil && m.ConsumerId != nil {
+ return *m.ConsumerId
+ }
+ return 0
+}
+
+func (m *CommandCloseConsumer) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+type CommandRedeliverUnacknowledgedMessages struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandRedeliverUnacknowledgedMessages) Reset() {
+ *m = CommandRedeliverUnacknowledgedMessages{}
+}
+func (m *CommandRedeliverUnacknowledgedMessages) String() string { return proto.CompactTextString(m) }
+func (*CommandRedeliverUnacknowledgedMessages) ProtoMessage() {}
+func (*CommandRedeliverUnacknowledgedMessages) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{27}
+}
+func (m *CommandRedeliverUnacknowledgedMessages) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandRedeliverUnacknowledgedMessages.Unmarshal(m, b)
+}
+func (m *CommandRedeliverUnacknowledgedMessages) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandRedeliverUnacknowledgedMessages.Marshal(b, m, deterministic)
+}
+func (dst *CommandRedeliverUnacknowledgedMessages) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandRedeliverUnacknowledgedMessages.Merge(dst, src)
+}
+func (m *CommandRedeliverUnacknowledgedMessages) XXX_Size() int {
+ return xxx_messageInfo_CommandRedeliverUnacknowledgedMessages.Size(m)
+}
+func (m *CommandRedeliverUnacknowledgedMessages) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandRedeliverUnacknowledgedMessages.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandRedeliverUnacknowledgedMessages proto.InternalMessageInfo
+
+func (m *CommandRedeliverUnacknowledgedMessages) GetConsumerId() uint64 {
+ if m != nil && m.ConsumerId != nil {
+ return *m.ConsumerId
+ }
+ return 0
+}
+
+func (m *CommandRedeliverUnacknowledgedMessages) GetMessageIds() []*MessageIdData {
+ if m != nil {
+ return m.MessageIds
+ }
+ return nil
+}
+
+type CommandSuccess struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandSuccess) Reset() { *m = CommandSuccess{} }
+func (m *CommandSuccess) String() string { return proto.CompactTextString(m) }
+func (*CommandSuccess) ProtoMessage() {}
+func (*CommandSuccess) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{28}
+}
+func (m *CommandSuccess) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandSuccess.Unmarshal(m, b)
+}
+func (m *CommandSuccess) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandSuccess.Marshal(b, m, deterministic)
+}
+func (dst *CommandSuccess) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandSuccess.Merge(dst, src)
+}
+func (m *CommandSuccess) XXX_Size() int {
+ return xxx_messageInfo_CommandSuccess.Size(m)
+}
+func (m *CommandSuccess) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandSuccess.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandSuccess proto.InternalMessageInfo
+
+func (m *CommandSuccess) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandSuccess) GetSchema() *Schema {
+ if m != nil {
+ return m.Schema
+ }
+ return nil
+}
+
+// / Response from CommandProducer
+type CommandProducerSuccess struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandProducerSuccess) Reset() { *m = CommandProducerSuccess{} }
+func (m *CommandProducerSuccess) String() string { return proto.CompactTextString(m) }
+func (*CommandProducerSuccess) ProtoMessage() {}
+func (*CommandProducerSuccess) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{29}
+}
+func (m *CommandProducerSuccess) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandProducerSuccess.Unmarshal(m, b)
+}
+func (m *CommandProducerSuccess) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandProducerSuccess.Marshal(b, m, deterministic)
+}
+func (dst *CommandProducerSuccess) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandProducerSuccess.Merge(dst, src)
+}
+func (m *CommandProducerSuccess) XXX_Size() int {
+ return xxx_messageInfo_CommandProducerSuccess.Size(m)
+}
+func (m *CommandProducerSuccess) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandProducerSuccess.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandProducerSuccess proto.InternalMessageInfo
+
+const Default_CommandProducerSuccess_LastSequenceId int64 = -1
+
+func (m *CommandProducerSuccess) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandProducerSuccess) GetProducerName() string {
+ if m != nil && m.ProducerName != nil {
+ return *m.ProducerName
+ }
+ return ""
+}
+
+func (m *CommandProducerSuccess) GetLastSequenceId() int64 {
+ if m != nil && m.LastSequenceId != nil {
+ return *m.LastSequenceId
+ }
+ return Default_CommandProducerSuccess_LastSequenceId
+}
+
+func (m *CommandProducerSuccess) GetSchemaVersion() []byte {
+ if m != nil {
+ return m.SchemaVersion
+ }
+ return nil
+}
+
+type CommandError struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandError) Reset() { *m = CommandError{} }
+func (m *CommandError) String() string { return proto.CompactTextString(m) }
+func (*CommandError) ProtoMessage() {}
+func (*CommandError) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{30}
+}
+func (m *CommandError) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandError.Unmarshal(m, b)
+}
+func (m *CommandError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandError.Marshal(b, m, deterministic)
+}
+func (dst *CommandError) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandError.Merge(dst, src)
+}
+func (m *CommandError) XXX_Size() int {
+ return xxx_messageInfo_CommandError.Size(m)
+}
+func (m *CommandError) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandError.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandError proto.InternalMessageInfo
+
+func (m *CommandError) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandError) GetError() ServerError {
+ if m != nil && m.Error != nil {
+ return *m.Error
+ }
+ return ServerError_UnknownError
+}
+
+func (m *CommandError) GetMessage() string {
+ if m != nil && m.Message != nil {
+ return *m.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 {
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandPing) Reset() { *m = CommandPing{} }
+func (m *CommandPing) String() string { return proto.CompactTextString(m) }
+func (*CommandPing) ProtoMessage() {}
+func (*CommandPing) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{31}
+}
+func (m *CommandPing) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandPing.Unmarshal(m, b)
+}
+func (m *CommandPing) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandPing.Marshal(b, m, deterministic)
+}
+func (dst *CommandPing) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandPing.Merge(dst, src)
+}
+func (m *CommandPing) XXX_Size() int {
+ return xxx_messageInfo_CommandPing.Size(m)
+}
+func (m *CommandPing) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandPing.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandPing proto.InternalMessageInfo
+
+type CommandPong struct {
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandPong) Reset() { *m = CommandPong{} }
+func (m *CommandPong) String() string { return proto.CompactTextString(m) }
+func (*CommandPong) ProtoMessage() {}
+func (*CommandPong) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{32}
+}
+func (m *CommandPong) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandPong.Unmarshal(m, b)
+}
+func (m *CommandPong) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandPong.Marshal(b, m, deterministic)
+}
+func (dst *CommandPong) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandPong.Merge(dst, src)
+}
+func (m *CommandPong) XXX_Size() int {
+ return xxx_messageInfo_CommandPong.Size(m)
+}
+func (m *CommandPong) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandPong.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandPong proto.InternalMessageInfo
+
+type CommandConsumerStats struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandConsumerStats) Reset() { *m = CommandConsumerStats{} }
+func (m *CommandConsumerStats) String() string { return proto.CompactTextString(m) }
+func (*CommandConsumerStats) ProtoMessage() {}
+func (*CommandConsumerStats) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{33}
+}
+func (m *CommandConsumerStats) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandConsumerStats.Unmarshal(m, b)
+}
+func (m *CommandConsumerStats) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandConsumerStats.Marshal(b, m, deterministic)
+}
+func (dst *CommandConsumerStats) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandConsumerStats.Merge(dst, src)
+}
+func (m *CommandConsumerStats) XXX_Size() int {
+ return xxx_messageInfo_CommandConsumerStats.Size(m)
+}
+func (m *CommandConsumerStats) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandConsumerStats.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandConsumerStats proto.InternalMessageInfo
+
+func (m *CommandConsumerStats) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandConsumerStats) GetConsumerId() uint64 {
+ if m != nil && m.ConsumerId != nil {
+ return *m.ConsumerId
+ }
+ return 0
+}
+
+type CommandConsumerStatsResponse struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandConsumerStatsResponse) Reset() { *m = CommandConsumerStatsResponse{} }
+func (m *CommandConsumerStatsResponse) String() string { return proto.CompactTextString(m) }
+func (*CommandConsumerStatsResponse) ProtoMessage() {}
+func (*CommandConsumerStatsResponse) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{34}
+}
+func (m *CommandConsumerStatsResponse) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandConsumerStatsResponse.Unmarshal(m, b)
+}
+func (m *CommandConsumerStatsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandConsumerStatsResponse.Marshal(b, m, deterministic)
+}
+func (dst *CommandConsumerStatsResponse) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandConsumerStatsResponse.Merge(dst, src)
+}
+func (m *CommandConsumerStatsResponse) XXX_Size() int {
+ return xxx_messageInfo_CommandConsumerStatsResponse.Size(m)
+}
+func (m *CommandConsumerStatsResponse) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandConsumerStatsResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandConsumerStatsResponse proto.InternalMessageInfo
+
+func (m *CommandConsumerStatsResponse) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandConsumerStatsResponse) GetErrorCode() ServerError {
+ if m != nil && m.ErrorCode != nil {
+ return *m.ErrorCode
+ }
+ return ServerError_UnknownError
+}
+
+func (m *CommandConsumerStatsResponse) GetErrorMessage() string {
+ if m != nil && m.ErrorMessage != nil {
+ return *m.ErrorMessage
+ }
+ return ""
+}
+
+func (m *CommandConsumerStatsResponse) GetMsgRateOut() float64 {
+ if m != nil && m.MsgRateOut != nil {
+ return *m.MsgRateOut
+ }
+ return 0
+}
+
+func (m *CommandConsumerStatsResponse) GetMsgThroughputOut() float64 {
+ if m != nil && m.MsgThroughputOut != nil {
+ return *m.MsgThroughputOut
+ }
+ return 0
+}
+
+func (m *CommandConsumerStatsResponse) GetMsgRateRedeliver() float64 {
+ if m != nil && m.MsgRateRedeliver != nil {
+ return *m.MsgRateRedeliver
+ }
+ return 0
+}
+
+func (m *CommandConsumerStatsResponse) GetConsumerName() string {
+ if m != nil && m.ConsumerName != nil {
+ return *m.ConsumerName
+ }
+ return ""
+}
+
+func (m *CommandConsumerStatsResponse) GetAvailablePermits() uint64 {
+ if m != nil && m.AvailablePermits != nil {
+ return *m.AvailablePermits
+ }
+ return 0
+}
+
+func (m *CommandConsumerStatsResponse) GetUnackedMessages() uint64 {
+ if m != nil && m.UnackedMessages != nil {
+ return *m.UnackedMessages
+ }
+ return 0
+}
+
+func (m *CommandConsumerStatsResponse) GetBlockedConsumerOnUnackedMsgs() bool {
+ if m != nil && m.BlockedConsumerOnUnackedMsgs != nil {
+ return *m.BlockedConsumerOnUnackedMsgs
+ }
+ return false
+}
+
+func (m *CommandConsumerStatsResponse) GetAddress() string {
+ if m != nil && m.Address != nil {
+ return *m.Address
+ }
+ return ""
+}
+
+func (m *CommandConsumerStatsResponse) GetConnectedSince() string {
+ if m != nil && m.ConnectedSince != nil {
+ return *m.ConnectedSince
+ }
+ return ""
+}
+
+func (m *CommandConsumerStatsResponse) GetType() string {
+ if m != nil && m.Type != nil {
+ return *m.Type
+ }
+ return ""
+}
+
+func (m *CommandConsumerStatsResponse) GetMsgRateExpired() float64 {
+ if m != nil && m.MsgRateExpired != nil {
+ return *m.MsgRateExpired
+ }
+ return 0
+}
+
+func (m *CommandConsumerStatsResponse) GetMsgBacklog() uint64 {
+ if m != nil && m.MsgBacklog != nil {
+ return *m.MsgBacklog
+ }
+ return 0
+}
+
+type CommandGetLastMessageId struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandGetLastMessageId) Reset() { *m = CommandGetLastMessageId{} }
+func (m *CommandGetLastMessageId) String() string { return proto.CompactTextString(m) }
+func (*CommandGetLastMessageId) ProtoMessage() {}
+func (*CommandGetLastMessageId) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{35}
+}
+func (m *CommandGetLastMessageId) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandGetLastMessageId.Unmarshal(m, b)
+}
+func (m *CommandGetLastMessageId) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandGetLastMessageId.Marshal(b, m, deterministic)
+}
+func (dst *CommandGetLastMessageId) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandGetLastMessageId.Merge(dst, src)
+}
+func (m *CommandGetLastMessageId) XXX_Size() int {
+ return xxx_messageInfo_CommandGetLastMessageId.Size(m)
+}
+func (m *CommandGetLastMessageId) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandGetLastMessageId.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandGetLastMessageId proto.InternalMessageInfo
+
+func (m *CommandGetLastMessageId) GetConsumerId() uint64 {
+ if m != nil && m.ConsumerId != nil {
+ return *m.ConsumerId
+ }
+ return 0
+}
+
+func (m *CommandGetLastMessageId) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+type CommandGetLastMessageIdResponse struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandGetLastMessageIdResponse) Reset() { *m = CommandGetLastMessageIdResponse{} }
+func (m *CommandGetLastMessageIdResponse) String() string { return proto.CompactTextString(m) }
+func (*CommandGetLastMessageIdResponse) ProtoMessage() {}
+func (*CommandGetLastMessageIdResponse) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{36}
+}
+func (m *CommandGetLastMessageIdResponse) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandGetLastMessageIdResponse.Unmarshal(m, b)
+}
+func (m *CommandGetLastMessageIdResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandGetLastMessageIdResponse.Marshal(b, m, deterministic)
+}
+func (dst *CommandGetLastMessageIdResponse) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandGetLastMessageIdResponse.Merge(dst, src)
+}
+func (m *CommandGetLastMessageIdResponse) XXX_Size() int {
+ return xxx_messageInfo_CommandGetLastMessageIdResponse.Size(m)
+}
+func (m *CommandGetLastMessageIdResponse) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandGetLastMessageIdResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandGetLastMessageIdResponse proto.InternalMessageInfo
+
+func (m *CommandGetLastMessageIdResponse) GetLastMessageId() *MessageIdData {
+ if m != nil {
+ return m.LastMessageId
+ }
+ return nil
+}
+
+func (m *CommandGetLastMessageIdResponse) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+type CommandGetTopicsOfNamespace struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandGetTopicsOfNamespace) Reset() { *m = CommandGetTopicsOfNamespace{} }
+func (m *CommandGetTopicsOfNamespace) String() string { return proto.CompactTextString(m) }
+func (*CommandGetTopicsOfNamespace) ProtoMessage() {}
+func (*CommandGetTopicsOfNamespace) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{37}
+}
+func (m *CommandGetTopicsOfNamespace) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandGetTopicsOfNamespace.Unmarshal(m, b)
+}
+func (m *CommandGetTopicsOfNamespace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandGetTopicsOfNamespace.Marshal(b, m, deterministic)
+}
+func (dst *CommandGetTopicsOfNamespace) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandGetTopicsOfNamespace.Merge(dst, src)
+}
+func (m *CommandGetTopicsOfNamespace) XXX_Size() int {
+ return xxx_messageInfo_CommandGetTopicsOfNamespace.Size(m)
+}
+func (m *CommandGetTopicsOfNamespace) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandGetTopicsOfNamespace.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandGetTopicsOfNamespace proto.InternalMessageInfo
+
+const Default_CommandGetTopicsOfNamespace_Mode CommandGetTopicsOfNamespace_Mode = CommandGetTopicsOfNamespace_PERSISTENT
+
+func (m *CommandGetTopicsOfNamespace) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandGetTopicsOfNamespace) GetNamespace() string {
+ if m != nil && m.Namespace != nil {
+ return *m.Namespace
+ }
+ return ""
+}
+
+func (m *CommandGetTopicsOfNamespace) GetMode() CommandGetTopicsOfNamespace_Mode {
+ if m != nil && m.Mode != nil {
+ return *m.Mode
+ }
+ return Default_CommandGetTopicsOfNamespace_Mode
+}
+
+type CommandGetTopicsOfNamespaceResponse struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandGetTopicsOfNamespaceResponse) Reset() { *m = CommandGetTopicsOfNamespaceResponse{} }
+func (m *CommandGetTopicsOfNamespaceResponse) String() string { return proto.CompactTextString(m) }
+func (*CommandGetTopicsOfNamespaceResponse) ProtoMessage() {}
+func (*CommandGetTopicsOfNamespaceResponse) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{38}
+}
+func (m *CommandGetTopicsOfNamespaceResponse) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandGetTopicsOfNamespaceResponse.Unmarshal(m, b)
+}
+func (m *CommandGetTopicsOfNamespaceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandGetTopicsOfNamespaceResponse.Marshal(b, m, deterministic)
+}
+func (dst *CommandGetTopicsOfNamespaceResponse) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandGetTopicsOfNamespaceResponse.Merge(dst, src)
+}
+func (m *CommandGetTopicsOfNamespaceResponse) XXX_Size() int {
+ return xxx_messageInfo_CommandGetTopicsOfNamespaceResponse.Size(m)
+}
+func (m *CommandGetTopicsOfNamespaceResponse) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandGetTopicsOfNamespaceResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandGetTopicsOfNamespaceResponse proto.InternalMessageInfo
+
+func (m *CommandGetTopicsOfNamespaceResponse) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandGetTopicsOfNamespaceResponse) GetTopics() []string {
+ if m != nil {
+ return m.Topics
+ }
+ return nil
+}
+
+type CommandGetSchema struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandGetSchema) Reset() { *m = CommandGetSchema{} }
+func (m *CommandGetSchema) String() string { return proto.CompactTextString(m) }
+func (*CommandGetSchema) ProtoMessage() {}
+func (*CommandGetSchema) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{39}
+}
+func (m *CommandGetSchema) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandGetSchema.Unmarshal(m, b)
+}
+func (m *CommandGetSchema) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandGetSchema.Marshal(b, m, deterministic)
+}
+func (dst *CommandGetSchema) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandGetSchema.Merge(dst, src)
+}
+func (m *CommandGetSchema) XXX_Size() int {
+ return xxx_messageInfo_CommandGetSchema.Size(m)
+}
+func (m *CommandGetSchema) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandGetSchema.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandGetSchema proto.InternalMessageInfo
+
+func (m *CommandGetSchema) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandGetSchema) GetTopic() string {
+ if m != nil && m.Topic != nil {
+ return *m.Topic
+ }
+ return ""
+}
+
+func (m *CommandGetSchema) GetSchemaVersion() []byte {
+ if m != nil {
+ return m.SchemaVersion
+ }
+ return nil
+}
+
+type CommandGetSchemaResponse struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CommandGetSchemaResponse) Reset() { *m = CommandGetSchemaResponse{} }
+func (m *CommandGetSchemaResponse) String() string { return proto.CompactTextString(m) }
+func (*CommandGetSchemaResponse) ProtoMessage() {}
+func (*CommandGetSchemaResponse) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{40}
+}
+func (m *CommandGetSchemaResponse) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CommandGetSchemaResponse.Unmarshal(m, b)
+}
+func (m *CommandGetSchemaResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CommandGetSchemaResponse.Marshal(b, m, deterministic)
+}
+func (dst *CommandGetSchemaResponse) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommandGetSchemaResponse.Merge(dst, src)
+}
+func (m *CommandGetSchemaResponse) XXX_Size() int {
+ return xxx_messageInfo_CommandGetSchemaResponse.Size(m)
+}
+func (m *CommandGetSchemaResponse) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommandGetSchemaResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommandGetSchemaResponse proto.InternalMessageInfo
+
+func (m *CommandGetSchemaResponse) GetRequestId() uint64 {
+ if m != nil && m.RequestId != nil {
+ return *m.RequestId
+ }
+ return 0
+}
+
+func (m *CommandGetSchemaResponse) GetErrorCode() ServerError {
+ if m != nil && m.ErrorCode != nil {
+ return *m.ErrorCode
+ }
+ return ServerError_UnknownError
+}
+
+func (m *CommandGetSchemaResponse) GetErrorMessage() string {
+ if m != nil && m.ErrorMessage != nil {
+ return *m.ErrorMessage
+ }
+ return ""
+}
+
+func (m *CommandGetSchemaResponse) GetSchema() *Schema {
+ if m != nil {
+ return m.Schema
+ }
+ return nil
+}
+
+func (m *CommandGetSchemaResponse) GetSchemaVersion() []byte {
+ if m != nil {
+ return m.SchemaVersion
+ }
+ return nil
+}
+
+type BaseCommand struct {
+ 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"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *BaseCommand) Reset() { *m = BaseCommand{} }
+func (m *BaseCommand) String() string { return proto.CompactTextString(m) }
+func (*BaseCommand) ProtoMessage() {}
+func (*BaseCommand) Descriptor() ([]byte, []int) {
+ return fileDescriptor_PulsarApi_9ff3bd5e091a4809, []int{41}
+}
+func (m *BaseCommand) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_BaseCommand.Unmarshal(m, b)
+}
+func (m *BaseCommand) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_BaseCommand.Marshal(b, m, deterministic)
+}
+func (dst *BaseCommand) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_BaseCommand.Merge(dst, src)
+}
+func (m *BaseCommand) XXX_Size() int {
+ return xxx_messageInfo_BaseCommand.Size(m)
+}
+func (m *BaseCommand) XXX_DiscardUnknown() {
+ xxx_messageInfo_BaseCommand.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_BaseCommand proto.InternalMessageInfo
+
+func (m *BaseCommand) GetType() BaseCommand_Type {
+ if m != nil && m.Type != nil {
+ return *m.Type
+ }
+ return BaseCommand_CONNECT
+}
+
+func (m *BaseCommand) GetConnect() *CommandConnect {
+ if m != nil {
+ return m.Connect
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetConnected() *CommandConnected {
+ if m != nil {
+ return m.Connected
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetSubscribe() *CommandSubscribe {
+ if m != nil {
+ return m.Subscribe
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetProducer() *CommandProducer {
+ if m != nil {
+ return m.Producer
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetSend() *CommandSend {
+ if m != nil {
+ return m.Send
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetSendReceipt() *CommandSendReceipt {
+ if m != nil {
+ return m.SendReceipt
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetSendError() *CommandSendError {
+ if m != nil {
+ return m.SendError
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetMessage() *CommandMessage {
+ if m != nil {
+ return m.Message
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetAck() *CommandAck {
+ if m != nil {
+ return m.Ack
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetFlow() *CommandFlow {
+ if m != nil {
+ return m.Flow
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetUnsubscribe() *CommandUnsubscribe {
+ if m != nil {
+ return m.Unsubscribe
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetSuccess() *CommandSuccess {
+ if m != nil {
+ return m.Success
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetError() *CommandError {
+ if m != nil {
+ return m.Error
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetCloseProducer() *CommandCloseProducer {
+ if m != nil {
+ return m.CloseProducer
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetCloseConsumer() *CommandCloseConsumer {
+ if m != nil {
+ return m.CloseConsumer
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetProducerSuccess() *CommandProducerSuccess {
+ if m != nil {
+ return m.ProducerSuccess
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetPing() *CommandPing {
+ if m != nil {
+ return m.Ping
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetPong() *CommandPong {
+ if m != nil {
+ return m.Pong
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetRedeliverUnacknowledgedMessages() *CommandRedeliverUnacknowledgedMessages {
+ if m != nil {
+ return m.RedeliverUnacknowledgedMessages
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetPartitionMetadata() *CommandPartitionedTopicMetadata {
+ if m != nil {
+ return m.PartitionMetadata
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetPartitionMetadataResponse() *CommandPartitionedTopicMetadataResponse {
+ if m != nil {
+ return m.PartitionMetadataResponse
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetLookupTopic() *CommandLookupTopic {
+ if m != nil {
+ return m.LookupTopic
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetLookupTopicResponse() *CommandLookupTopicResponse {
+ if m != nil {
+ return m.LookupTopicResponse
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetConsumerStats() *CommandConsumerStats {
+ if m != nil {
+ return m.ConsumerStats
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetConsumerStatsResponse() *CommandConsumerStatsResponse {
+ if m != nil {
+ return m.ConsumerStatsResponse
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetReachedEndOfTopic() *CommandReachedEndOfTopic {
+ if m != nil {
+ return m.ReachedEndOfTopic
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetSeek() *CommandSeek {
+ if m != nil {
+ return m.Seek
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetGetLastMessageId() *CommandGetLastMessageId {
+ if m != nil {
+ return m.GetLastMessageId
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetGetLastMessageIdResponse() *CommandGetLastMessageIdResponse {
+ if m != nil {
+ return m.GetLastMessageIdResponse
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetActiveConsumerChange() *CommandActiveConsumerChange {
+ if m != nil {
+ return m.ActiveConsumerChange
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetGetTopicsOfNamespace() *CommandGetTopicsOfNamespace {
+ if m != nil {
+ return m.GetTopicsOfNamespace
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetGetTopicsOfNamespaceResponse() *CommandGetTopicsOfNamespaceResponse {
+ if m != nil {
+ return m.GetTopicsOfNamespaceResponse
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetGetSchema() *CommandGetSchema {
+ if m != nil {
+ return m.GetSchema
+ }
+ return nil
+}
+
+func (m *BaseCommand) GetGetSchemaResponse() *CommandGetSchemaResponse {
+ if m != nil {
+ return m.GetSchemaResponse
+ }
+ return nil
+}
+
+func init() {
+ proto.RegisterType((*Schema)(nil), "pulsar.proto.Schema")
+ proto.RegisterType((*MessageIdData)(nil), "pulsar.proto.MessageIdData")
+ proto.RegisterType((*KeyValue)(nil), "pulsar.proto.KeyValue")
+ proto.RegisterType((*KeyLongValue)(nil), "pulsar.proto.KeyLongValue")
+ proto.RegisterType((*EncryptionKeys)(nil), "pulsar.proto.EncryptionKeys")
+ proto.RegisterType((*MessageMetadata)(nil), "pulsar.proto.MessageMetadata")
+ proto.RegisterType((*SingleMessageMetadata)(nil), "pulsar.proto.SingleMessageMetadata")
+ proto.RegisterType((*CommandConnect)(nil), "pulsar.proto.CommandConnect")
+ proto.RegisterType((*CommandConnected)(nil), "pulsar.proto.CommandConnected")
+ proto.RegisterType((*CommandSubscribe)(nil), "pulsar.proto.CommandSubscribe")
+ proto.RegisterType((*CommandPartitionedTopicMetadata)(nil), "pulsar.proto.CommandPartitionedTopicMetadata")
+ proto.RegisterType((*CommandPartitionedTopicMetadataResponse)(nil), "pulsar.proto.CommandPartitionedTopicMetadataResponse")
+ proto.RegisterType((*CommandLookupTopic)(nil), "pulsar.proto.CommandLookupTopic")
+ proto.RegisterType((*CommandLookupTopicResponse)(nil), "pulsar.proto.CommandLookupTopicResponse")
+ proto.RegisterType((*CommandProducer)(nil), "pulsar.proto.CommandProducer")
+ proto.RegisterType((*CommandSend)(nil), "pulsar.proto.CommandSend")
+ proto.RegisterType((*CommandSendReceipt)(nil), "pulsar.proto.CommandSendReceipt")
+ proto.RegisterType((*CommandSendError)(nil), "pulsar.proto.CommandSendError")
+ proto.RegisterType((*CommandMessage)(nil), "pulsar.proto.CommandMessage")
+ proto.RegisterType((*CommandAck)(nil), "pulsar.proto.CommandAck")
+ proto.RegisterType((*CommandActiveConsumerChange)(nil), "pulsar.proto.CommandActiveConsumerChange")
+ proto.RegisterType((*CommandFlow)(nil), "pulsar.proto.CommandFlow")
+ proto.RegisterType((*CommandUnsubscribe)(nil), "pulsar.proto.CommandUnsubscribe")
+ proto.RegisterType((*CommandSeek)(nil), "pulsar.proto.CommandSeek")
+ proto.RegisterType((*CommandReachedEndOfTopic)(nil), "pulsar.proto.CommandReachedEndOfTopic")
+ proto.RegisterType((*CommandCloseProducer)(nil), "pulsar.proto.CommandCloseProducer")
+ proto.RegisterType((*CommandCloseConsumer)(nil), "pulsar.proto.CommandCloseConsumer")
+ proto.RegisterType((*CommandRedeliverUnacknowledgedMessages)(nil), "pulsar.proto.CommandRedeliverUnacknowledgedMessages")
+ proto.RegisterType((*CommandSuccess)(nil), "pulsar.proto.CommandSuccess")
+ proto.RegisterType((*CommandProducerSuccess)(nil), "pulsar.proto.CommandProducerSuccess")
+ proto.RegisterType((*CommandError)(nil), "pulsar.proto.CommandError")
+ proto.RegisterType((*CommandPing)(nil), "pulsar.proto.CommandPing")
+ proto.RegisterType((*CommandPong)(nil), "pulsar.proto.CommandPong")
+ proto.RegisterType((*CommandConsumerStats)(nil), "pulsar.proto.CommandConsumerStats")
+ proto.RegisterType((*CommandConsumerStatsResponse)(nil), "pulsar.proto.CommandConsumerStatsResponse")
+ proto.RegisterType((*CommandGetLastMessageId)(nil), "pulsar.proto.CommandGetLastMessageId")
+ proto.RegisterType((*CommandGetLastMessageIdResponse)(nil), "pulsar.proto.CommandGetLastMessageIdResponse")
+ proto.RegisterType((*CommandGetTopicsOfNamespace)(nil), "pulsar.proto.CommandGetTopicsOfNamespace")
+ proto.RegisterType((*CommandGetTopicsOfNamespaceResponse)(nil), "pulsar.proto.CommandGetTopicsOfNamespaceResponse")
+ proto.RegisterType((*CommandGetSchema)(nil), "pulsar.proto.CommandGetSchema")
+ proto.RegisterType((*CommandGetSchemaResponse)(nil), "pulsar.proto.CommandGetSchemaResponse")
+ proto.RegisterType((*BaseCommand)(nil), "pulsar.proto.BaseCommand")
+ proto.RegisterEnum("pulsar.proto.CompressionType", CompressionType_name, CompressionType_value)
+ proto.RegisterEnum("pulsar.proto.ServerError", ServerError_name, ServerError_value)
+ proto.RegisterEnum("pulsar.proto.AuthMethod", AuthMethod_name, AuthMethod_value)
+ proto.RegisterEnum("pulsar.proto.ProtocolVersion", ProtocolVersion_name, ProtocolVersion_value)
+ proto.RegisterEnum("pulsar.proto.Schema_Type", Schema_Type_name, Schema_Type_value)
+ proto.RegisterEnum("pulsar.proto.CommandSubscribe_SubType", CommandSubscribe_SubType_name, CommandSubscribe_SubType_value)
+ proto.RegisterEnum("pulsar.proto.CommandSubscribe_InitialPosition", CommandSubscribe_InitialPosition_name, CommandSubscribe_InitialPosition_value)
+ proto.RegisterEnum("pulsar.proto.CommandPartitionedTopicMetadataResponse_LookupType", CommandPartitionedTopicMetadataResponse_LookupType_name, CommandPartitionedTopicMetadataResponse_LookupType_value)
+ proto.RegisterEnum("pulsar.proto.CommandLookupTopicResponse_LookupType", CommandLookupTopicResponse_LookupType_name, CommandLookupTopicResponse_LookupType_value)
+ proto.RegisterEnum("pulsar.proto.CommandAck_AckType", CommandAck_AckType_name, CommandAck_AckType_value)
+ proto.RegisterEnum("pulsar.proto.CommandAck_ValidationError", CommandAck_ValidationError_name, CommandAck_ValidationError_value)
+ proto.RegisterEnum("pulsar.proto.CommandGetTopicsOfNamespace_Mode", CommandGetTopicsOfNamespace_Mode_name, CommandGetTopicsOfNamespace_Mode_value)
+ proto.RegisterEnum("pulsar.proto.BaseCommand_Type", BaseCommand_Type_name, BaseCommand_Type_value)
+}
+
+func init() { proto.RegisterFile("PulsarApi.proto", fileDescriptor_PulsarApi_9ff3bd5e091a4809) }
+
+var fileDescriptor_PulsarApi_9ff3bd5e091a4809 = []byte{
+ // 4065 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x3b, 0x4d, 0x6f, 0x1b, 0x49,
+ 0x76, 0x6e, 0x7e, 0x48, 0xe4, 0xe3, 0x57, 0xb9, 0x2c, 0x6b, 0xda, 0x1f, 0x63, 0xd3, 0xed, 0xb5,
+ 0x47, 0xe3, 0x1d, 0x2b, 0xb6, 0xec, 0x75, 0x66, 0xbc, 0x9b, 0x60, 0x28, 0xaa, 0x6d, 0x33, 0x96,
+ 0x48, 0x6d, 0x91, 0xf2, 0x62, 0x27, 0xbb, 0xe8, 0x6d, 0x75, 0x97, 0xa9, 0x86, 0x9a, 0xdd, 0x4c,
+ 0x7f, 0x68, 0xac, 0x39, 0xe4, 0x36, 0x08, 0x02, 0x04, 0x08, 0x90, 0x1c, 0x73, 0xc8, 0x21, 0x08,
+ 0x72, 0xce, 0x2d, 0x40, 0x7e, 0x43, 0x6e, 0xb9, 0xe4, 0x94, 0x4b, 0x72, 0x0c, 0x90, 0x43, 0x90,
+ 0x73, 0x50, 0xd5, 0xd5, 0x5f, 0x24, 0x45, 0xca, 0x3b, 0x7b, 0xc8, 0x89, 0xdd, 0xaf, 0x5e, 0xbd,
+ 0x7a, 0xf5, 0xde, 0xab, 0xf7, 0x55, 0x4d, 0x68, 0x1d, 0x86, 0xb6, 0xaf, 0x7b, 0x9d, 0xa9, 0xb5,
+ 0x3d, 0xf5, 0xdc, 0xc0, 0xc5, 0xf5, 0x29, 0x07, 0x44, 0x6f, 0xca, 0x7f, 0x48, 0xb0, 0x36, 0x34,
+ 0x4e, 0xe8, 0x44, 0xc7, 0x18, 0x4a, 0x8e, 0x3e, 0xa1, 0xb2, 0xd4, 0x2e, 0x6c, 0x55, 0x09, 0x7f,
+ 0xc6, 0x77, 0xa1, 0xe6, 0xf3, 0x51, 0xcd, 0xd4, 0x03, 0x5d, 0x2e, 0xb6, 0x0b, 0x5b, 0x75, 0x02,
+ 0x11, 0x68, 0x4f, 0x0f, 0x74, 0xfc, 0x18, 0x4a, 0xc1, 0xf9, 0x94, 0xca, 0xa5, 0x76, 0x61, 0xab,
+ 0xb9, 0x73, 0x63, 0x3b, 0x4b, 0x7c, 0x3b, 0x22, 0xbc, 0x3d, 0x3a, 0x9f, 0x52, 0xc2, 0xd1, 0xf0,
+ 0x0b, 0x80, 0xa9, 0xe7, 0x4e, 0xa9, 0x17, 0x58, 0xd4, 0x97, 0xcb, 0xed, 0xe2, 0x56, 0x6d, 0x67,
+ 0x33, 0x3f, 0xe9, 0x2d, 0x3d, 0x7f, 0xa7, 0xdb, 0x21, 0x25, 0x19, 0x4c, 0xe5, 0x0f, 0xa1, 0xc4,
+ 0xa8, 0xe0, 0x0a, 0x94, 0xfa, 0xae, 0x43, 0xd1, 0x15, 0x0c, 0xb0, 0x36, 0x0c, 0x3c, 0xcb, 0x19,
+ 0x23, 0x89, 0x41, 0xff, 0xc8, 0x77, 0x1d, 0x54, 0xc0, 0x75, 0xa8, 0x1c, 0x32, 0x2a, 0xc7, 0xe1,
+ 0x7b, 0x54, 0x64, 0xf0, 0xce, 0x99, 0xe7, 0xa2, 0x92, 0xf2, 0x17, 0x12, 0x34, 0x0e, 0xa8, 0xef,
+ 0xeb, 0x63, 0xda, 0x33, 0x39, 0xe3, 0x37, 0xa1, 0x62, 0x53, 0x73, 0x4c, 0xbd, 0x9e, 0xc9, 0x77,
+ 0x5c, 0x22, 0xc9, 0x3b, 0x96, 0x61, 0x9d, 0x3a, 0x81, 0x77, 0xde, 0x33, 0xe5, 0x02, 0x1f, 0x8a,
+ 0x5f, 0x71, 0x1b, 0xaa, 0x53, 0xdd, 0x0b, 0xac, 0xc0, 0x72, 0x1d, 0xb9, 0xd8, 0x96, 0xb6, 0xca,
+ 0x2f, 0x0b, 0x8f, 0x9f, 0x92, 0x14, 0x88, 0xef, 0x43, 0xed, 0x58, 0x0f, 0x8c, 0x13, 0xcd, 0x72,
+ 0x4c, 0xfa, 0x41, 0x2e, 0x25, 0x38, 0xc0, 0xc1, 0x3d, 0x06, 0x55, 0x76, 0xa0, 0x12, 0x6f, 0x13,
+ 0x23, 0x28, 0x9e, 0xd2, 0x73, 0x21, 0x75, 0xf6, 0x88, 0x37, 0xa0, 0x7c, 0xc6, 0x86, 0xf8, 0xe2,
+ 0x55, 0x12, 0xbd, 0x28, 0x2f, 0xa0, 0xfe, 0x96, 0x9e, 0xef, 0xbb, 0xce, 0xf8, 0x52, 0xf3, 0x4a,
+ 0xf1, 0x3c, 0x1b, 0x9a, 0xaa, 0x63, 0x78, 0xe7, 0x53, 0xc6, 0xde, 0x5b, 0x7a, 0xee, 0xaf, 0x9a,
+ 0x59, 0x17, 0x33, 0xf1, 0x0e, 0x54, 0x26, 0x34, 0xd0, 0x85, 0xe6, 0x97, 0xa9, 0x2a, 0xc1, 0x53,
+ 0xfe, 0xb7, 0x0c, 0x2d, 0x21, 0xe8, 0x03, 0x01, 0xc3, 0xf7, 0xa1, 0x31, 0xf5, 0x5c, 0x33, 0x34,
+ 0xa8, 0xa7, 0x65, 0x2c, 0xac, 0x1e, 0x03, 0xfb, 0xb1, 0xa5, 0xd1, 0x3f, 0x09, 0xa9, 0x63, 0x50,
+ 0xcd, 0x8a, 0xe5, 0x0e, 0x31, 0xa8, 0x67, 0xe2, 0x7b, 0x50, 0x9f, 0x86, 0xc7, 0xb6, 0xe5, 0x9f,
+ 0x68, 0x81, 0x35, 0xa1, 0xdc, 0x16, 0x4b, 0xa4, 0x26, 0x60, 0x23, 0x6b, 0x32, 0x6b, 0x5d, 0xa5,
+ 0xcb, 0x5a, 0x17, 0xfe, 0x0c, 0x5a, 0x1e, 0x9d, 0xda, 0x96, 0xa1, 0x07, 0xd4, 0xd4, 0xde, 0x7b,
+ 0xee, 0x44, 0x2e, 0xb7, 0xa5, 0xad, 0x2a, 0x69, 0xa6, 0xe0, 0x57, 0x9e, 0x3b, 0xe1, 0x3b, 0x89,
+ 0x35, 0xad, 0x31, 0x19, 0xae, 0x71, 0xb4, 0x7a, 0x02, 0x7c, 0x4b, 0xcf, 0x19, 0xa3, 0xc9, 0x34,
+ 0x2d, 0x70, 0xe5, 0xf5, 0x76, 0x71, 0xab, 0x4a, 0x6a, 0x09, 0x6c, 0xe4, 0x62, 0x15, 0x6a, 0x86,
+ 0x3b, 0x99, 0x7a, 0xd4, 0xf7, 0x99, 0x21, 0x55, 0xda, 0xd2, 0x56, 0x73, 0xe7, 0xd3, 0x3c, 0xa7,
+ 0xdd, 0x14, 0x81, 0x99, 0xfe, 0xcb, 0x52, 0x7f, 0xd0, 0x57, 0x49, 0x76, 0x1e, 0xde, 0x86, 0xab,
+ 0xa1, 0x13, 0x03, 0xa8, 0xa9, 0xf9, 0xd6, 0x77, 0x54, 0xae, 0xb6, 0xa5, 0xad, 0xc6, 0x4b, 0xe9,
+ 0x09, 0x41, 0xd9, 0xb1, 0xa1, 0xf5, 0x1d, 0xc5, 0xcf, 0xe1, 0xba, 0x13, 0x4e, 0xb4, 0x49, 0xa4,
+ 0x1f, 0x5f, 0xb3, 0x1c, 0x8d, 0x1b, 0xa5, 0x5c, 0xe3, 0x56, 0x2a, 0x3d, 0x25, 0xd8, 0x09, 0x27,
+ 0x42, 0x7d, 0x7e, 0xcf, 0xd9, 0x65, 0x83, 0xb8, 0x0d, 0x40, 0xcf, 0xa8, 0x13, 0x44, 0x62, 0xaf,
+ 0xb7, 0xa5, 0xad, 0x12, 0x23, 0x5f, 0xe5, 0x40, 0x2e, 0x77, 0x15, 0x5a, 0x34, 0x31, 0x31, 0x26,
+ 0x17, 0x5f, 0x6e, 0x70, 0xe1, 0xdf, 0xce, 0x6f, 0x29, 0x6f, 0x87, 0xa4, 0x49, 0xf3, 0x76, 0xf9,
+ 0x59, 0x8e, 0x8c, 0x6e, 0x8f, 0x5d, 0xb9, 0x19, 0xa9, 0x21, 0x05, 0x77, 0xec, 0xb1, 0x8b, 0x3f,
+ 0x07, 0x94, 0x41, 0x9c, 0xea, 0x9e, 0x3e, 0x91, 0x5b, 0x6d, 0x69, 0xab, 0x4e, 0x32, 0x04, 0x0e,
+ 0x19, 0x18, 0x3f, 0x80, 0xa6, 0x70, 0x60, 0x67, 0xd4, 0xe3, 0xc2, 0x46, 0x1c, 0xb1, 0x11, 0x41,
+ 0xdf, 0x45, 0x40, 0xfc, 0x35, 0xdc, 0xc8, 0x29, 0x56, 0x3b, 0x7e, 0xf1, 0x5c, 0xa3, 0x8e, 0xe1,
+ 0x9a, 0xd4, 0x94, 0xaf, 0xb6, 0xa5, 0xad, 0xca, 0xcb, 0xf2, 0x7b, 0xdd, 0xf6, 0x29, 0xd9, 0xcc,
+ 0xea, 0x7a, 0xf7, 0xc5, 0x73, 0x35, 0x42, 0x52, 0xfe, 0xa1, 0x00, 0xd7, 0x87, 0x96, 0x33, 0xb6,
+ 0xe9, 0xac, 0xf9, 0xe7, 0xad, 0x52, 0xba, 0xb4, 0x55, 0xce, 0x19, 0x5b, 0x61, 0xb1, 0xb1, 0x4d,
+ 0xf5, 0x73, 0xdb, 0xd5, 0x85, 0xf6, 0xd9, 0xa9, 0x28, 0x93, 0x9a, 0x80, 0x71, 0xad, 0x3f, 0x82,
+ 0x06, 0xb3, 0x03, 0xdd, 0x60, 0xc6, 0xed, 0x86, 0x01, 0xf7, 0x49, 0xc9, 0x7e, 0xea, 0xc9, 0xd8,
+ 0x20, 0x0c, 0x66, 0x74, 0x5d, 0x5e, 0xa0, 0xeb, 0xa5, 0x92, 0x5a, 0xbb, 0x8c, 0xa4, 0xfe, 0xbe,
+ 0x08, 0xcd, 0xae, 0x3b, 0x99, 0xe8, 0x8e, 0xd9, 0x75, 0x1d, 0x87, 0x1a, 0x01, 0xd3, 0x92, 0x61,
+ 0x5b, 0x6c, 0xdd, 0x58, 0x4b, 0x91, 0x8b, 0x68, 0x44, 0xd0, 0x58, 0x4b, 0x5f, 0x41, 0x4d, 0x0f,
+ 0x83, 0x13, 0x6d, 0x42, 0x83, 0x13, 0xd7, 0xe4, 0xf2, 0x68, 0xee, 0xc8, 0x79, 0x51, 0x76, 0xc2,
+ 0xe0, 0xe4, 0x80, 0x8f, 0x13, 0xd0, 0x93, 0x67, 0xbc, 0x05, 0x28, 0x33, 0x35, 0x72, 0x43, 0xe2,
+ 0x8c, 0xa7, 0x58, 0xdc, 0x11, 0xdd, 0x82, 0x2a, 0xc7, 0x14, 0x6e, 0x8f, 0x19, 0x4b, 0x85, 0x01,
+ 0x78, 0xd4, 0xf8, 0x02, 0x10, 0x5f, 0xc6, 0x70, 0xed, 0x84, 0xd5, 0xc8, 0xc5, 0x4b, 0x4f, 0x48,
+ 0x2b, 0x1e, 0x8a, 0xf9, 0x7d, 0x0c, 0xd7, 0xa6, 0x9e, 0xfb, 0xe1, 0x5c, 0x0b, 0x5c, 0xed, 0xd8,
+ 0x73, 0x4f, 0xa9, 0xa7, 0x85, 0x9e, 0x2d, 0x9c, 0x06, 0xe2, 0x43, 0x23, 0x77, 0x97, 0x0f, 0x1c,
+ 0x79, 0x36, 0x7e, 0x0c, 0xd8, 0xf5, 0xac, 0xb1, 0xe5, 0xe8, 0xb6, 0x36, 0xf5, 0x2c, 0xc7, 0xb0,
+ 0xa6, 0xba, 0x2d, 0xaf, 0x73, 0xec, 0xab, 0xf1, 0xc8, 0x61, 0x3c, 0x80, 0xbf, 0xc8, 0xa0, 0xa7,
+ 0x1c, 0x57, 0x22, 0xe2, 0xf1, 0x48, 0x27, 0xe6, 0xfc, 0x09, 0x6c, 0xe4, 0xb1, 0x85, 0x10, 0xab,
+ 0x1c, 0x1f, 0x67, 0xf1, 0x23, 0x61, 0x28, 0x63, 0x40, 0x79, 0x35, 0x51, 0x93, 0x1f, 0x27, 0xea,
+ 0x9d, 0x51, 0x6f, 0x56, 0x51, 0x11, 0x34, 0xde, 0xf8, 0x22, 0x31, 0x15, 0x2e, 0x12, 0x93, 0xf2,
+ 0x2f, 0xe5, 0x64, 0xa5, 0x61, 0x78, 0xec, 0x1b, 0x9e, 0x75, 0x4c, 0x59, 0x48, 0x0a, 0xdc, 0xa9,
+ 0x65, 0x88, 0x05, 0xa2, 0x17, 0xac, 0x40, 0xdd, 0x8f, 0x50, 0xf8, 0x19, 0x17, 0x11, 0x32, 0x07,
+ 0xc3, 0x5f, 0xc3, 0xba, 0x1f, 0x1e, 0x33, 0x9f, 0xc9, 0x4f, 0x43, 0x73, 0xe7, 0xe1, 0x9c, 0x63,
+ 0xcd, 0x2d, 0xb5, 0x3d, 0x8c, 0xb0, 0x49, 0x3c, 0x8d, 0xc5, 0x22, 0xc3, 0x75, 0xfc, 0x70, 0x42,
+ 0x3d, 0x16, 0x8b, 0x4a, 0x51, 0x2c, 0x8a, 0x41, 0x3d, 0x13, 0x7f, 0x0a, 0xe0, 0xb1, 0xc8, 0xe4,
+ 0x07, 0x6c, 0xbc, 0xcc, 0xc7, 0xab, 0x02, 0xd2, 0x33, 0xd9, 0xc9, 0x4d, 0xe6, 0x73, 0x4b, 0x13,
+ 0x61, 0x22, 0x06, 0x72, 0x3b, 0x7b, 0x00, 0xcd, 0xa9, 0x67, 0xb9, 0x9e, 0x15, 0x9c, 0x6b, 0x36,
+ 0x3d, 0xa3, 0x91, 0xa6, 0xcb, 0xa4, 0x11, 0x43, 0xf7, 0x19, 0x10, 0xdf, 0x81, 0x75, 0x33, 0xf4,
+ 0xf4, 0x63, 0x9b, 0x72, 0xd5, 0x56, 0x5e, 0x96, 0x02, 0x2f, 0xa4, 0x24, 0x06, 0x62, 0x15, 0x90,
+ 0x1f, 0xe8, 0x5e, 0x10, 0x7b, 0x75, 0xc6, 0x10, 0xd3, 0x69, 0x6d, 0xe7, 0x56, 0x7e, 0xdb, 0xb9,
+ 0xf4, 0x87, 0x34, 0xf9, 0xa4, 0x04, 0x96, 0x8b, 0xf5, 0x70, 0xb9, 0x58, 0xcf, 0x76, 0xe0, 0x51,
+ 0xdd, 0xd4, 0x12, 0x0f, 0xc2, 0xe3, 0x48, 0x85, 0x34, 0x18, 0xb4, 0x1b, 0x03, 0xf1, 0x17, 0xb0,
+ 0x16, 0x39, 0x5b, 0x1e, 0x3b, 0x6a, 0x3b, 0x1b, 0x8b, 0x92, 0x44, 0x22, 0x70, 0xf0, 0x6f, 0xa0,
+ 0x65, 0x39, 0x56, 0x60, 0xe9, 0xf6, 0xa1, 0xeb, 0x47, 0x79, 0x56, 0x83, 0x9f, 0xf3, 0xed, 0x15,
+ 0x5a, 0xec, 0xe5, 0x67, 0xbd, 0x5c, 0xdb, 0xd7, 0x03, 0xea, 0x07, 0x64, 0x96, 0x9c, 0xb2, 0x03,
+ 0xeb, 0x42, 0xe3, 0xb8, 0x01, 0x55, 0xf5, 0x83, 0x61, 0x87, 0xbe, 0x75, 0x16, 0xe7, 0x94, 0x27,
+ 0xba, 0x47, 0x4d, 0x24, 0xb1, 0x4c, 0xf2, 0x95, 0x6e, 0xd9, 0xee, 0x19, 0xf5, 0x50, 0x41, 0xf9,
+ 0x31, 0xb4, 0x66, 0xe8, 0x33, 0xe4, 0x68, 0x05, 0x74, 0x85, 0x21, 0xab, 0xba, 0x67, 0x5b, 0xec,
+ 0x4d, 0x52, 0xfe, 0x53, 0x82, 0xbb, 0x82, 0xbd, 0xc3, 0xd8, 0x05, 0x52, 0x73, 0xc4, 0x0c, 0x38,
+ 0x09, 0x0a, 0x8b, 0xcd, 0x3b, 0x6f, 0x57, 0x85, 0x59, 0xbb, 0x5a, 0xec, 0x20, 0x8a, 0x1f, 0xe7,
+ 0x20, 0x4a, 0x1f, 0xe9, 0x20, 0xca, 0x17, 0x3a, 0x88, 0x7f, 0x2a, 0xc0, 0x67, 0x2b, 0xf6, 0x49,
+ 0xa8, 0x3f, 0x75, 0x1d, 0x9f, 0xe2, 0x3b, 0x00, 0x49, 0x38, 0x60, 0x41, 0x50, 0xda, 0x6a, 0x90,
+ 0x0c, 0x64, 0xd5, 0xce, 0x7f, 0x05, 0x15, 0x4f, 0x90, 0xe2, 0xfb, 0x6d, 0xee, 0x7c, 0xbd, 0xd0,
+ 0x1c, 0x56, 0xf1, 0xb1, 0xbd, 0xef, 0xba, 0xa7, 0xe1, 0x94, 0x1f, 0xf7, 0x84, 0x22, 0xfe, 0x3d,
+ 0x28, 0x53, 0xcf, 0x73, 0x3d, 0x2e, 0x9b, 0xf9, 0x2a, 0x86, 0xbb, 0x36, 0x95, 0x21, 0x90, 0x08,
+ 0x8f, 0x15, 0x08, 0xe2, 0xb8, 0x09, 0xf1, 0xc4, 0xaf, 0xca, 0x03, 0x80, 0x74, 0x09, 0x5c, 0x63,
+ 0xa6, 0x66, 0x18, 0xd4, 0xf7, 0x23, 0xeb, 0x62, 0x16, 0xc5, 0xac, 0x4b, 0xf9, 0xbe, 0x00, 0x58,
+ 0xb0, 0x2c, 0xd0, 0xb9, 0xfe, 0x7f, 0x2b, 0xab, 0xf8, 0x31, 0x34, 0x98, 0xbe, 0x98, 0xcf, 0xd0,
+ 0x03, 0xeb, 0x2c, 0x12, 0x50, 0x12, 0x85, 0xf3, 0x63, 0x17, 0x98, 0x50, 0xe9, 0xe3, 0x4c, 0xa8,
+ 0xfc, 0x91, 0x26, 0xb4, 0x76, 0xa1, 0x09, 0xfd, 0x5b, 0x11, 0x6e, 0xce, 0xcb, 0x21, 0xb1, 0x9a,
+ 0x47, 0x80, 0xa2, 0xb8, 0xc9, 0x74, 0x60, 0x19, 0xf4, 0xc8, 0xb3, 0xb9, 0xed, 0x54, 0xc9, 0x1c,
+ 0x1c, 0x3f, 0x81, 0x6b, 0xb3, 0xb0, 0x91, 0xed, 0x8b, 0xa4, 0x69, 0xd1, 0x10, 0x1e, 0xcc, 0x19,
+ 0xd5, 0xb3, 0x85, 0x46, 0xb5, 0x80, 0xb3, 0xc5, 0x76, 0x94, 0x57, 0x54, 0x69, 0xa5, 0xa2, 0xca,
+ 0x4b, 0x14, 0x95, 0xd8, 0xe4, 0xda, 0xc7, 0xdb, 0xe4, 0x7a, 0xce, 0x26, 0x79, 0xca, 0x16, 0xa5,
+ 0x21, 0x27, 0x9e, 0x1b, 0x8e, 0x4f, 0x34, 0x3f, 0x12, 0x03, 0x4f, 0x46, 0x2a, 0xf9, 0x94, 0x8d,
+ 0xe7, 0x24, 0x11, 0x5a, 0x2a, 0x2c, 0xe5, 0x59, 0xce, 0xaa, 0xeb, 0x50, 0x21, 0xd4, 0xb4, 0x3c,
+ 0x6a, 0x30, 0xdf, 0x57, 0x83, 0x75, 0x91, 0x1f, 0x20, 0x29, 0x63, 0xe3, 0x05, 0xe5, 0xaf, 0x0b,
+ 0xd0, 0x8a, 0x8f, 0xa5, 0xa8, 0xf4, 0x2e, 0x30, 0xf0, 0xbb, 0x50, 0x4b, 0x0a, 0xc4, 0xb4, 0xf6,
+ 0x8b, 0x41, 0x73, 0xf1, 0xb6, 0xb8, 0x20, 0xde, 0xe6, 0x0b, 0xcc, 0x92, 0xc8, 0x94, 0xb3, 0x05,
+ 0xe6, 0x7d, 0xa8, 0x8a, 0xe2, 0x80, 0x9a, 0x79, 0xc9, 0xa7, 0xf0, 0x5c, 0x18, 0x5c, 0xbb, 0x64,
+ 0x18, 0x4c, 0xe3, 0xdb, 0xfa, 0xea, 0xf8, 0xa6, 0x84, 0x50, 0x8b, 0x43, 0x17, 0x75, 0xcc, 0xd9,
+ 0xad, 0x4b, 0x73, 0x5b, 0x5f, 0x59, 0x17, 0xff, 0x08, 0xea, 0xd9, 0xa2, 0x4e, 0x74, 0x25, 0xa4,
+ 0xa7, 0xa4, 0x96, 0xa9, 0xe5, 0x94, 0xbf, 0x92, 0x12, 0x87, 0xc3, 0xd6, 0x25, 0xd4, 0xa0, 0xd6,
+ 0x34, 0xf8, 0x1d, 0x2c, 0xff, 0x12, 0x20, 0x93, 0x79, 0x14, 0x57, 0x67, 0x1e, 0xd5, 0x49, 0xfc,
+ 0xaa, 0xfc, 0xad, 0x94, 0x26, 0x7e, 0xd4, 0x31, 0xb9, 0x39, 0xff, 0x0e, 0x58, 0x4a, 0x8e, 0x4e,
+ 0x71, 0x61, 0x53, 0x6a, 0xe9, 0xd1, 0x29, 0x71, 0xbb, 0x4c, 0xdc, 0xf9, 0xdf, 0x48, 0x49, 0xad,
+ 0x22, 0x76, 0x31, 0x9b, 0x1c, 0x4a, 0x73, 0xc9, 0x61, 0x5e, 0x22, 0x8c, 0xbd, 0x4b, 0x4b, 0x84,
+ 0x25, 0xce, 0x1e, 0x35, 0xa9, 0x6d, 0x9d, 0x51, 0xef, 0x5c, 0x33, 0xdc, 0xd0, 0x09, 0xb8, 0x4c,
+ 0x79, 0x41, 0xdf, 0x4a, 0x87, 0xba, 0x6c, 0x44, 0xf9, 0x9f, 0x22, 0x80, 0xe0, 0xae, 0x63, 0x9c,
+ 0xae, 0xe6, 0xec, 0xa7, 0x50, 0xd1, 0x8d, 0x53, 0x8d, 0x37, 0xec, 0x0a, 0x5c, 0x36, 0xed, 0x85,
+ 0x0e, 0xaf, 0x63, 0x9c, 0x6e, 0x77, 0x8c, 0xd3, 0x28, 0x29, 0xd6, 0xa3, 0x87, 0x39, 0x45, 0x17,
+ 0x3f, 0x62, 0x5b, 0x43, 0x40, 0x67, 0xba, 0x6d, 0x99, 0x3a, 0xaf, 0x1a, 0xb3, 0xb1, 0x76, 0xeb,
+ 0x42, 0x06, 0xde, 0x25, 0x13, 0x22, 0x5d, 0xb5, 0xce, 0xf2, 0x00, 0xc6, 0xd0, 0x5c, 0x2f, 0xf1,
+ 0xe6, 0xdc, 0x69, 0x4d, 0x1a, 0x66, 0xb9, 0x7e, 0xe2, 0xe7, 0xb0, 0x2e, 0x36, 0x88, 0x9b, 0x00,
+ 0x3d, 0xc7, 0xb4, 0xce, 0x2c, 0x33, 0xd4, 0x6d, 0x74, 0x85, 0xbd, 0x77, 0xc3, 0x49, 0x68, 0x73,
+ 0x37, 0x8c, 0x24, 0xe5, 0x2f, 0x25, 0x68, 0xcd, 0xf0, 0x82, 0xef, 0xc0, 0xcd, 0xa3, 0x99, 0xe6,
+ 0x4a, 0xd7, 0xf5, 0xbc, 0x90, 0x17, 0x20, 0xe8, 0x0a, 0xde, 0x04, 0xbc, 0x47, 0x33, 0x9d, 0x1a,
+ 0x3e, 0x0b, 0x49, 0x78, 0x03, 0x50, 0xf7, 0x84, 0x1a, 0xa7, 0x7e, 0x38, 0x39, 0xb0, 0xfc, 0x89,
+ 0x1e, 0x18, 0x27, 0xa8, 0x80, 0x6f, 0xc0, 0x75, 0xde, 0x69, 0xd9, 0xa3, 0x43, 0xea, 0x59, 0xba,
+ 0x6d, 0x7d, 0x47, 0xa3, 0x09, 0x45, 0x7c, 0x0d, 0x5a, 0x7b, 0x34, 0xee, 0x68, 0x44, 0xc0, 0x92,
+ 0x72, 0x0c, 0xb7, 0x12, 0x39, 0x31, 0x26, 0xbb, 0x42, 0xc3, 0xdd, 0x13, 0xdd, 0xb9, 0x8c, 0x81,
+ 0x2a, 0x50, 0xb5, 0x7c, 0x4d, 0xe7, 0x73, 0x79, 0x7c, 0x4c, 0x3c, 0x61, 0xc5, 0xf2, 0x23, 0x92,
+ 0xca, 0xbb, 0xc4, 0x4d, 0xbd, 0xb2, 0xdd, 0x6f, 0x57, 0xd3, 0x7c, 0x08, 0x4d, 0xa1, 0xee, 0x43,
+ 0xea, 0x4d, 0xac, 0xc0, 0xe7, 0x06, 0xd6, 0x20, 0x33, 0x50, 0x65, 0x94, 0xb8, 0xa1, 0x23, 0xc7,
+ 0x4f, 0x8a, 0xbd, 0x95, 0xe4, 0x97, 0xa7, 0x40, 0xca, 0x9f, 0x4b, 0x19, 0xaf, 0x4a, 0x4f, 0x7f,
+ 0x28, 0xbd, 0x1f, 0xe4, 0xd4, 0x7e, 0x0a, 0xb2, 0x60, 0x85, 0x50, 0xdd, 0x38, 0xa1, 0xa6, 0xea,
+ 0x98, 0x83, 0xf7, 0xa3, 0x38, 0xd0, 0x2d, 0xe5, 0x4b, 0x79, 0x07, 0x1b, 0x71, 0xcd, 0x6d, 0xbb,
+ 0x3e, 0x4d, 0xe2, 0xe6, 0x4a, 0xa7, 0xb8, 0x42, 0x40, 0x33, 0x74, 0x63, 0x8b, 0xf9, 0xc1, 0x82,
+ 0xff, 0x33, 0x09, 0x1e, 0x26, 0xbb, 0x15, 0xce, 0xe9, 0xc8, 0xd1, 0x8d, 0x53, 0xc7, 0xfd, 0x96,
+ 0xb7, 0xd3, 0x63, 0xb7, 0xe9, 0xaf, 0x5e, 0xea, 0x67, 0x50, 0x4b, 0x85, 0xce, 0xec, 0x67, 0xa5,
+ 0x87, 0x81, 0x44, 0xea, 0xbe, 0xf2, 0xeb, 0xc4, 0x51, 0x8b, 0x8c, 0x7b, 0x86, 0x75, 0x69, 0x56,
+ 0xc7, 0x69, 0xd8, 0x2e, 0x5c, 0x22, 0x6c, 0xff, 0xa3, 0x04, 0x9b, 0x33, 0xc9, 0xcc, 0x25, 0xd7,
+ 0x99, 0x4b, 0x4e, 0x0a, 0x0b, 0xba, 0xdf, 0x5f, 0x00, 0xb2, 0x75, 0x3f, 0xd0, 0xb2, 0x81, 0x8d,
+ 0x99, 0x5d, 0x91, 0x5f, 0x1d, 0x34, 0xd9, 0xd8, 0x30, 0x0d, 0x70, 0xf3, 0x4d, 0xcd, 0xd2, 0x82,
+ 0xa6, 0xa6, 0xf2, 0x01, 0xea, 0x82, 0xe5, 0xc8, 0x6b, 0xad, 0x60, 0x34, 0x09, 0x9b, 0x85, 0x8f,
+ 0x0f, 0x9b, 0xc5, 0x7c, 0xd8, 0x6c, 0x24, 0xc7, 0xf1, 0xd0, 0x72, 0xc6, 0xd9, 0x57, 0xd7, 0x19,
+ 0x67, 0x8d, 0x51, 0x68, 0x7f, 0x18, 0xe8, 0xc1, 0x4a, 0x41, 0xae, 0xea, 0xca, 0x28, 0xff, 0x5d,
+ 0x82, 0xdb, 0x8b, 0x08, 0x93, 0xc5, 0xf9, 0xf9, 0xdc, 0x02, 0x5f, 0x02, 0xf0, 0x8d, 0x69, 0x86,
+ 0x6b, 0x52, 0xd1, 0x5d, 0x5c, 0x22, 0x85, 0x2a, 0x47, 0xee, 0xba, 0x26, 0xcb, 0x2d, 0x1b, 0xd1,
+ 0xcc, 0x54, 0x1e, 0x3c, 0x01, 0xe5, 0xc0, 0x38, 0x71, 0xb8, 0x03, 0x30, 0xf1, 0xc7, 0x44, 0x0f,
+ 0xe8, 0x40, 0x34, 0x61, 0x25, 0x92, 0x81, 0xb0, 0x62, 0x67, 0xe2, 0x8f, 0x45, 0xf2, 0x3d, 0x0d,
+ 0x03, 0x86, 0x55, 0xe6, 0x58, 0x73, 0x70, 0x81, 0xcb, 0x66, 0x26, 0xc7, 0x8e, 0x17, 0x0a, 0x11,
+ 0x6e, 0x0e, 0x8e, 0x15, 0xc8, 0x35, 0x9e, 0x44, 0x75, 0x90, 0x6f, 0x46, 0x3d, 0x02, 0xa4, 0x9f,
+ 0xe9, 0x96, 0xad, 0x1f, 0xdb, 0x89, 0x03, 0x67, 0x95, 0x41, 0x89, 0xcc, 0xc1, 0xf1, 0x16, 0xb4,
+ 0x42, 0x76, 0xc4, 0xd3, 0xb3, 0xcd, 0x1b, 0x4e, 0x25, 0x32, 0x0b, 0xc6, 0xbb, 0x70, 0xfb, 0xd8,
+ 0x76, 0x19, 0x28, 0xd6, 0xc7, 0xc0, 0x39, 0x12, 0x38, 0xfe, 0xd8, 0x97, 0x81, 0xb7, 0x8b, 0x96,
+ 0xe2, 0x30, 0x23, 0xd3, 0x4d, 0x93, 0xc5, 0x51, 0xde, 0x5d, 0xaa, 0x92, 0xf8, 0x95, 0x85, 0x1c,
+ 0x23, 0x6e, 0x4c, 0x0e, 0x2d, 0xc7, 0x88, 0xee, 0x26, 0xaa, 0x64, 0x06, 0x8a, 0xb1, 0xb8, 0xa2,
+ 0x6c, 0xf0, 0xd1, 0xe8, 0x1e, 0x92, 0x85, 0xab, 0x48, 0x4e, 0xea, 0x87, 0xa9, 0xe5, 0x51, 0x93,
+ 0xdf, 0x34, 0x48, 0x64, 0x06, 0x2a, 0x74, 0xb6, 0xab, 0x1b, 0xa7, 0xb6, 0x3b, 0xe6, 0x77, 0x0c,
+ 0x25, 0x92, 0x81, 0x28, 0xbf, 0x84, 0x4f, 0x84, 0xc5, 0xbd, 0xa6, 0xc1, 0xbe, 0xee, 0x67, 0x3a,
+ 0x6a, 0x3f, 0xd4, 0xb5, 0x7e, 0x9f, 0x76, 0x91, 0x66, 0x69, 0x27, 0x06, 0xdd, 0x85, 0x16, 0x77,
+ 0x1b, 0x99, 0x60, 0x25, 0xad, 0xce, 0x37, 0x1b, 0x76, 0x8e, 0xd1, 0x15, 0x7c, 0xfc, 0xbb, 0x94,
+ 0xa4, 0x1b, 0xaf, 0x69, 0xc0, 0xe3, 0x98, 0x3f, 0x78, 0xcf, 0xac, 0xc6, 0x9f, 0xea, 0xc6, 0xca,
+ 0x43, 0x75, 0x1b, 0xaa, 0x4e, 0x8c, 0x2b, 0x5c, 0x5f, 0x0a, 0xc0, 0x7d, 0x28, 0x4d, 0xd8, 0x61,
+ 0x2b, 0x2e, 0x69, 0xf1, 0x2d, 0x5a, 0x75, 0xfb, 0xc0, 0x35, 0xe9, 0x4b, 0x38, 0x54, 0xc9, 0xb0,
+ 0x37, 0x1c, 0xa9, 0xfd, 0x11, 0xe1, 0x74, 0x94, 0x67, 0x50, 0x62, 0x23, 0x2c, 0x89, 0x4b, 0xc7,
+ 0xd0, 0x15, 0x8c, 0xa1, 0xd9, 0x1f, 0xf4, 0xb5, 0x0c, 0x4c, 0xc2, 0xeb, 0x50, 0xec, 0xec, 0xef,
+ 0xa3, 0x82, 0xf2, 0x2b, 0xb8, 0xbf, 0x64, 0xa9, 0xcb, 0x7a, 0x8f, 0x4d, 0x58, 0xe3, 0xd5, 0x6c,
+ 0x14, 0xb9, 0xaa, 0x44, 0xbc, 0x29, 0x4e, 0x52, 0xe3, 0xbc, 0xa6, 0x81, 0xb8, 0x6a, 0x5f, 0x41,
+ 0x2a, 0xa9, 0x92, 0x0b, 0xd9, 0x2a, 0x79, 0xde, 0xeb, 0x17, 0x17, 0x79, 0xfd, 0xff, 0x92, 0x92,
+ 0x04, 0x24, 0x59, 0xf0, 0xff, 0x89, 0x07, 0x4c, 0x43, 0x6e, 0xe9, 0x12, 0x9d, 0xe0, 0xf9, 0xfd,
+ 0x96, 0x17, 0xed, 0xf7, 0x9f, 0x6f, 0x40, 0x6d, 0x57, 0x67, 0x39, 0x0d, 0xdf, 0x33, 0xde, 0x11,
+ 0xc7, 0x5d, 0xe2, 0x51, 0xec, 0x4e, 0x7e, 0x89, 0x0c, 0x62, 0xfe, 0xb3, 0x84, 0x75, 0xe1, 0x34,
+ 0x44, 0x32, 0x70, 0x7b, 0xa1, 0x25, 0x8a, 0x3e, 0x07, 0x89, 0x91, 0xf1, 0xcf, 0xa0, 0x9a, 0x38,
+ 0x1b, 0x91, 0x26, 0xde, 0x59, 0x36, 0x93, 0x9a, 0x24, 0x9d, 0xc0, 0x66, 0x27, 0x29, 0xb0, 0x90,
+ 0xc8, 0x9d, 0xe5, 0x4d, 0x6e, 0x92, 0x4e, 0xc0, 0x5f, 0x41, 0x25, 0x4e, 0x21, 0xb8, 0x60, 0x6a,
+ 0x0b, 0x2e, 0x90, 0xb3, 0xe9, 0x0a, 0x49, 0xd0, 0xf1, 0x63, 0x28, 0xf9, 0xd4, 0x89, 0xfa, 0x72,
+ 0xb5, 0x59, 0x05, 0x67, 0xbb, 0x04, 0x1c, 0x0d, 0x77, 0xa1, 0xce, 0x7e, 0x35, 0x2f, 0x6a, 0x1a,
+ 0x88, 0x36, 0x47, 0xfb, 0xe2, 0x69, 0x11, 0x1e, 0xa9, 0xf9, 0x99, 0x4e, 0xc3, 0x1f, 0x00, 0x70,
+ 0x22, 0x51, 0x8a, 0x51, 0x59, 0xb6, 0xdb, 0xb8, 0x15, 0x40, 0xaa, 0x7e, 0xd2, 0x15, 0x78, 0x91,
+ 0xe6, 0x1a, 0xd5, 0x25, 0x1a, 0x12, 0x96, 0x96, 0xf6, 0xbe, 0x1e, 0x41, 0x51, 0x37, 0x4e, 0x79,
+ 0xa4, 0xa9, 0xcd, 0x5e, 0x15, 0xa6, 0xc5, 0x26, 0x61, 0x48, 0x4c, 0x2c, 0xef, 0x6d, 0xf7, 0x5b,
+ 0x1e, 0x67, 0x2e, 0x12, 0x0b, 0xab, 0x86, 0x08, 0x47, 0xc3, 0xbb, 0x50, 0x0b, 0xd3, 0x1a, 0x46,
+ 0x5c, 0x6e, 0x2c, 0x96, 0x4a, 0xa6, 0xd6, 0x21, 0xd9, 0x49, 0x6c, 0x5b, 0x7e, 0x94, 0x46, 0xf2,
+ 0xf0, 0x74, 0xd1, 0xb6, 0x44, 0xaa, 0x49, 0x62, 0x64, 0xfc, 0x24, 0xce, 0xd5, 0x9a, 0x7c, 0xd6,
+ 0xcd, 0x85, 0xb3, 0x72, 0xc9, 0x5a, 0x0f, 0x9a, 0x06, 0x4b, 0xfd, 0xb5, 0xc4, 0x68, 0x5a, 0x7c,
+ 0xaa, 0xb2, 0xd8, 0x5e, 0xb3, 0xd5, 0x07, 0x69, 0x18, 0xb9, 0x62, 0x24, 0x21, 0x15, 0x07, 0x33,
+ 0x7e, 0xa7, 0xbe, 0x94, 0x54, 0x1c, 0xdb, 0x05, 0xa9, 0xa4, 0xfe, 0x18, 0xf0, 0x8b, 0xc2, 0x28,
+ 0x39, 0x8e, 0x05, 0x71, 0x95, 0x13, 0xfb, 0xd1, 0x52, 0x63, 0x8e, 0x05, 0xd2, 0x9a, 0xce, 0x24,
+ 0xe3, 0x8f, 0xa1, 0x34, 0xb5, 0x9c, 0xb1, 0x8c, 0x97, 0xe8, 0x90, 0xe5, 0xa4, 0x84, 0xa3, 0x71,
+ 0x74, 0xd7, 0x19, 0xcb, 0xd7, 0x96, 0xa1, 0xbb, 0x1c, 0xdd, 0x75, 0xc6, 0xf8, 0x4f, 0xe1, 0xae,
+ 0xb7, 0xbc, 0xcc, 0x91, 0x37, 0x38, 0xa5, 0xe7, 0x0b, 0x29, 0xad, 0x28, 0x91, 0xc8, 0x2a, 0xe2,
+ 0xf8, 0x8f, 0xe1, 0x6a, 0x72, 0x67, 0x12, 0x5f, 0x6d, 0xc8, 0xd7, 0xf9, 0x8a, 0x8f, 0x3f, 0xee,
+ 0x3e, 0x64, 0x9e, 0x0e, 0xf6, 0x33, 0x37, 0xfb, 0xb3, 0xf7, 0x26, 0xf2, 0x26, 0x5f, 0xe4, 0x27,
+ 0xbf, 0xd5, 0xa5, 0x0b, 0xb9, 0x98, 0x2e, 0x3b, 0x44, 0x76, 0xda, 0x5e, 0x97, 0x3f, 0x59, 0x72,
+ 0x88, 0xb2, 0x6d, 0xf8, 0xec, 0x24, 0xfc, 0x0d, 0x5c, 0xb3, 0xe7, 0x5b, 0xf4, 0xb2, 0xcc, 0x69,
+ 0x6d, 0x5d, 0xb6, 0xa5, 0x4f, 0x16, 0x11, 0xc1, 0x6f, 0xd2, 0xab, 0x5c, 0x5e, 0x4b, 0xc8, 0x37,
+ 0x96, 0x99, 0x7a, 0xae, 0xea, 0xc8, 0x4f, 0xc4, 0xbf, 0x81, 0xeb, 0xc6, 0xa2, 0xaa, 0x44, 0xbe,
+ 0xc9, 0x29, 0x3e, 0xba, 0x04, 0xc5, 0x98, 0xd3, 0xc5, 0x84, 0xf0, 0x08, 0xae, 0x7a, 0xb3, 0x2d,
+ 0x07, 0xf9, 0x16, 0xa7, 0xfe, 0xf0, 0x02, 0x7b, 0x9c, 0xc1, 0x26, 0xf3, 0x04, 0xa2, 0x60, 0x41,
+ 0x4f, 0xe5, 0xdb, 0x4b, 0x83, 0x05, 0x3d, 0x25, 0x1c, 0x0d, 0xff, 0x1c, 0xd0, 0x78, 0x26, 0x5d,
+ 0x95, 0x3f, 0xe5, 0x53, 0x1f, 0x5c, 0x94, 0xdd, 0xe5, 0x73, 0xdb, 0xb9, 0xe9, 0xd8, 0x02, 0x79,
+ 0x7c, 0x41, 0x06, 0x2c, 0xdf, 0x59, 0x62, 0xfc, 0x17, 0xa5, 0xcd, 0xe4, 0x42, 0x72, 0x58, 0x83,
+ 0xcd, 0xa8, 0x2f, 0x96, 0xf8, 0x36, 0xcd, 0xe0, 0x5d, 0x35, 0xf9, 0x2e, 0x5f, 0xe8, 0xf3, 0x0b,
+ 0x22, 0xc8, 0x7c, 0x1b, 0x8e, 0x6c, 0xe8, 0x8b, 0x9a, 0x73, 0xbf, 0x86, 0x8d, 0xf1, 0x82, 0x24,
+ 0x53, 0x6e, 0x2f, 0x21, 0xbf, 0x30, 0x2b, 0x5d, 0x48, 0x06, 0x87, 0x70, 0x7b, 0xbc, 0x24, 0x87,
+ 0x95, 0xef, 0xf1, 0x65, 0x9e, 0x5e, 0x7e, 0x99, 0x58, 0x64, 0x4b, 0xc9, 0xb2, 0x4c, 0x66, 0x1c,
+ 0xe7, 0x9a, 0xb2, 0xb2, 0x24, 0xb6, 0xa7, 0x19, 0x69, 0x3a, 0x81, 0xd9, 0xed, 0x78, 0x36, 0x53,
+ 0x95, 0xef, 0x2f, 0xb1, 0xdb, 0xb9, 0xbc, 0x96, 0xcc, 0x13, 0x50, 0xfe, 0xae, 0x2c, 0xbe, 0x19,
+ 0xad, 0xc1, 0x7a, 0x77, 0xd0, 0xef, 0xab, 0xdd, 0x11, 0x2a, 0xe0, 0x06, 0x54, 0xc5, 0x8b, 0xba,
+ 0x87, 0x8a, 0xec, 0x75, 0x78, 0xb4, 0x3b, 0xec, 0x92, 0xde, 0xae, 0x8a, 0x4a, 0xfc, 0xf3, 0x51,
+ 0x32, 0xd8, 0x3b, 0xea, 0xaa, 0x04, 0x95, 0x71, 0x05, 0x4a, 0x43, 0xb5, 0xbf, 0x87, 0xd6, 0x30,
+ 0x82, 0x3a, 0x7b, 0xd2, 0x88, 0xda, 0x55, 0x7b, 0x87, 0x23, 0xb4, 0xce, 0x0a, 0x0c, 0x0e, 0x51,
+ 0x09, 0x19, 0x10, 0x54, 0x61, 0x8b, 0x1c, 0xa8, 0xc3, 0x61, 0xe7, 0xb5, 0x8a, 0xaa, 0xbc, 0xb2,
+ 0xe8, 0xbe, 0x45, 0xc0, 0x28, 0xbc, 0xda, 0x1f, 0xfc, 0x02, 0xd5, 0x70, 0x0b, 0x6a, 0x47, 0xfd,
+ 0x74, 0xa9, 0x3a, 0xbf, 0x1a, 0x3e, 0xea, 0x76, 0xd5, 0xe1, 0x10, 0x35, 0x70, 0x15, 0xca, 0x11,
+ 0xa1, 0x26, 0xab, 0x54, 0xba, 0xfb, 0x83, 0xa1, 0xaa, 0x25, 0x8c, 0xb4, 0x52, 0x58, 0x77, 0xd0,
+ 0x1f, 0x1e, 0x1d, 0xa8, 0x04, 0x21, 0xbc, 0x01, 0x28, 0xc6, 0xd0, 0x62, 0x42, 0x57, 0xd9, 0x82,
+ 0x87, 0xbd, 0xfe, 0x6b, 0x84, 0xf9, 0xd3, 0xa0, 0xff, 0x1a, 0x5d, 0xc3, 0x0f, 0xe0, 0x1e, 0x51,
+ 0xf7, 0xd4, 0xfd, 0xde, 0x3b, 0x95, 0x68, 0x47, 0xfd, 0x4e, 0xf7, 0x6d, 0x7f, 0xf0, 0x8b, 0x7d,
+ 0x75, 0xef, 0xb5, 0xba, 0xa7, 0x09, 0x9e, 0x87, 0x68, 0x03, 0xcb, 0xb0, 0x71, 0xd8, 0x21, 0xa3,
+ 0xde, 0xa8, 0x37, 0xe8, 0xf3, 0x91, 0x51, 0x67, 0xaf, 0x33, 0xea, 0xa0, 0xeb, 0xf8, 0x1e, 0x7c,
+ 0xba, 0x68, 0x44, 0x23, 0xea, 0xf0, 0x70, 0xd0, 0x1f, 0xaa, 0x68, 0x93, 0x7f, 0x0c, 0x31, 0x18,
+ 0xbc, 0x3d, 0x3a, 0x44, 0x9f, 0xe0, 0x6b, 0xd0, 0x8a, 0x9e, 0x53, 0x04, 0x99, 0x6f, 0x41, 0x30,
+ 0xaf, 0x0d, 0x47, 0x9d, 0xd1, 0x10, 0xdd, 0xc0, 0xb7, 0xe0, 0x93, 0x3c, 0x2c, 0x9d, 0x70, 0x93,
+ 0xb1, 0x43, 0xd4, 0x4e, 0xf7, 0x8d, 0xba, 0xa7, 0x31, 0x39, 0x0f, 0x5e, 0x69, 0xa3, 0xc1, 0x61,
+ 0xaf, 0x8b, 0x6e, 0x45, 0x6a, 0x51, 0xdf, 0xa2, 0xdb, 0xf8, 0x13, 0xb8, 0xf6, 0x5a, 0x1d, 0x69,
+ 0xfb, 0x9d, 0xe1, 0x28, 0xde, 0x89, 0xd6, 0xdb, 0x43, 0x9f, 0xe2, 0x36, 0xdc, 0x5e, 0x30, 0x90,
+ 0x92, 0xbf, 0x83, 0x6f, 0xc2, 0x66, 0xa7, 0x3b, 0xea, 0xbd, 0x4b, 0x65, 0xaa, 0x75, 0xdf, 0x74,
+ 0xfa, 0xaf, 0x55, 0x74, 0x97, 0xf1, 0xc5, 0x66, 0xf3, 0xf5, 0x86, 0x6c, 0xe5, 0x7e, 0xe7, 0x40,
+ 0x1d, 0x1e, 0x76, 0xba, 0x2a, 0x6a, 0xe3, 0x1f, 0x41, 0xfb, 0x82, 0xc1, 0x94, 0xfc, 0x3d, 0x66,
+ 0x1e, 0x0c, 0x6b, 0xd8, 0x7d, 0xa3, 0x1e, 0x74, 0x90, 0x12, 0x73, 0x1a, 0xbd, 0xa7, 0x88, 0xf7,
+ 0x1f, 0x7d, 0xc9, 0xef, 0x48, 0xb3, 0x1f, 0x7a, 0xf2, 0x6f, 0x9c, 0x07, 0x7d, 0x15, 0x5d, 0x61,
+ 0x76, 0xb4, 0xff, 0xcd, 0xf3, 0xe8, 0x03, 0xe7, 0x6f, 0xf6, 0x7b, 0xbb, 0xa8, 0xc0, 0x9f, 0x86,
+ 0xa3, 0x3d, 0x54, 0x7c, 0xf4, 0xaf, 0x45, 0xa8, 0x65, 0x8a, 0x31, 0x66, 0xa3, 0x47, 0x0e, 0xcb,
+ 0x19, 0xc4, 0x3d, 0xc1, 0x15, 0x7c, 0x15, 0x1a, 0x71, 0xbc, 0xcd, 0x5c, 0x40, 0x1c, 0xb2, 0xba,
+ 0xc9, 0x0f, 0xa8, 0x63, 0x88, 0x5b, 0x86, 0x02, 0xe3, 0xae, 0x13, 0x06, 0x27, 0xd4, 0x09, 0x2c,
+ 0x23, 0xbd, 0xe5, 0x40, 0x45, 0xbc, 0x09, 0xb8, 0x13, 0xdd, 0x4a, 0x7f, 0x97, 0x81, 0x97, 0xd8,
+ 0x5a, 0xb1, 0x5f, 0xdb, 0x0d, 0xfd, 0x73, 0x54, 0x66, 0x4a, 0x17, 0xf7, 0xc5, 0x7d, 0x37, 0x20,
+ 0x54, 0x37, 0xcf, 0xd1, 0x1a, 0xb3, 0xbc, 0x38, 0x61, 0xdb, 0x8d, 0x7a, 0x3c, 0x3f, 0x0f, 0xdd,
+ 0x40, 0x57, 0x3f, 0x18, 0x94, 0x9a, 0x34, 0xca, 0x4f, 0xd1, 0x3a, 0xfe, 0x1c, 0x1e, 0x2c, 0x45,
+ 0xfb, 0x60, 0xd0, 0xe8, 0x62, 0xa5, 0xc2, 0xb6, 0x14, 0x5f, 0xa0, 0x44, 0xb3, 0xab, 0x4c, 0x5b,
+ 0x2c, 0xbd, 0x9e, 0x4e, 0x5d, 0x2f, 0xa0, 0xa6, 0xa8, 0x0a, 0xa3, 0x41, 0x60, 0xf8, 0xdc, 0x6b,
+ 0xf5, 0xdd, 0xe0, 0x95, 0x1b, 0x3a, 0x26, 0xaa, 0x31, 0xc3, 0x1a, 0x66, 0x3e, 0x17, 0x4b, 0x46,
+ 0xea, 0xfc, 0x76, 0x26, 0x6e, 0x8a, 0xc5, 0xd0, 0x06, 0xdb, 0xd9, 0xc8, 0x75, 0x0f, 0x74, 0xe7,
+ 0x9c, 0x44, 0x75, 0xb2, 0x8f, 0x9a, 0x8c, 0x08, 0xa7, 0x3b, 0xa2, 0xde, 0xc4, 0x72, 0xf4, 0x20,
+ 0xde, 0x4c, 0x8b, 0x89, 0x26, 0xd9, 0x0c, 0x13, 0x0d, 0x3f, 0xa9, 0x3d, 0x87, 0x5f, 0x5e, 0x45,
+ 0xac, 0xe8, 0x13, 0x8a, 0xae, 0x32, 0xd1, 0xf6, 0xf8, 0x15, 0x92, 0x1e, 0x58, 0xc7, 0x36, 0x8d,
+ 0x9c, 0x17, 0xc2, 0x8f, 0xde, 0x02, 0xa4, 0xdf, 0x47, 0xb0, 0x63, 0x93, 0xbe, 0x89, 0x2f, 0xdf,
+ 0xaf, 0x41, 0x2b, 0x85, 0xfd, 0xd2, 0xd0, 0xdf, 0x3d, 0x8d, 0x14, 0x9b, 0x02, 0x3b, 0x4c, 0x97,
+ 0x3e, 0x2a, 0x3c, 0xfa, 0x5e, 0x82, 0xd6, 0xe1, 0xcc, 0x47, 0x89, 0x6b, 0x50, 0x38, 0x7b, 0x82,
+ 0xae, 0xf0, 0x5f, 0x36, 0x93, 0xfd, 0xee, 0xa0, 0x02, 0xff, 0x7d, 0x86, 0x8a, 0xfc, 0xf7, 0x39,
+ 0x2a, 0xf1, 0xdf, 0x9f, 0xa0, 0x32, 0xff, 0x7d, 0x81, 0xd6, 0xf8, 0xef, 0xef, 0xa3, 0x75, 0xfe,
+ 0xfb, 0x25, 0xaa, 0xf0, 0xdf, 0xaf, 0x22, 0x67, 0x77, 0xf6, 0xf4, 0x09, 0x82, 0xe8, 0xe1, 0x29,
+ 0xaa, 0x45, 0x0f, 0x3b, 0xa8, 0x1e, 0x3d, 0x3c, 0x43, 0x8d, 0xdd, 0x87, 0xa0, 0xb8, 0xde, 0x78,
+ 0x5b, 0x9f, 0xb2, 0xe4, 0x22, 0x76, 0xe9, 0x86, 0x3b, 0x99, 0xb8, 0xce, 0xb6, 0x1e, 0xff, 0x33,
+ 0xe1, 0x4d, 0xf1, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x99, 0x3c, 0x38, 0xad, 0x30, 0x00,
+ 0x00,
+}
diff --git a/pulsar/reader.go b/pulsar/reader.go
new file mode 100644
index 0000000..5592630
--- /dev/null
+++ b/pulsar/reader.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 pulsar
+
+import "context"
+
+type ReaderMessage struct {
+ Reader
+ Message
+}
+
+type ReaderOptions struct {
+ // Specify the topic this consumer will subscribe on.
+ // This argument is required when constructing the reader.
+ Topic string
+
+ // Set the reader name.
+ Name string
+
+ // The 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
+
+ // Sets a `MessageChannel` for the consumer
+ // When a message is received, it will be pushed to the channel for consumption
+ MessageChannel chan ReaderMessage
+
+ // 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
+
+ // Set the subscription role prefix. The default prefix is "reader".
+ SubscriptionRolePrefix string
+
+ // 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
+}
+
+// A Reader can be used to scan through all the messages currently available in a topic.
+type Reader interface {
+ // The topic from which this reader is reading from
+ Topic() string
+
+ // Read the next message in the topic, blocking until a message is available
+ Next(context.Context) (Message, error)
+
+ // Check if there is any message available to read from the current position
+ HasNext() (bool, error)
+
+ // Close the reader and stop the broker to push more messages
+ Close() error
+}
[pulsar-client-go] 08/38: Added serialize method for string map
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 0fe868ab5bff52ffc33430f74490beee8d608934
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Wed Apr 3 07:50:08 2019 -0700
Added serialize method for string map
---
pulsar/impl/commands.go | 25 +++++++++++++++++++++++++
pulsar/impl/commands_test.go | 26 ++++++++++++++++++++++++++
2 files changed, 51 insertions(+)
diff --git a/pulsar/impl/commands.go b/pulsar/impl/commands.go
index c803602..ed9f6b9 100644
--- a/pulsar/impl/commands.go
+++ b/pulsar/impl/commands.go
@@ -32,3 +32,28 @@ func baseCommand(cmdType pb.BaseCommand_Type, msg proto.Message) *pb.BaseCommand
return cmd
}
+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 += 1
+ }
+
+ return list
+}
+
+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/pulsar/impl/commands_test.go b/pulsar/impl/commands_test.go
new file mode 100644
index 0000000..d9f94e6
--- /dev/null
+++ b/pulsar/impl/commands_test.go
@@ -0,0 +1,26 @@
+package impl
+
+import (
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func TestConvertStringMap(t *testing.T) {
+ m := make(map[string]string)
+ m["a"] = "1"
+ m["b"] = "2"
+
+ pbm := ConvertFromStringMap(m)
+
+ assert.Equal(t, 2, len(pbm))
+ assert.Equal(t, "a", *pbm[0].Key)
+ assert.Equal(t, "1", *pbm[0].Value)
+ assert.Equal(t, "b", *pbm[1].Key)
+ assert.Equal(t, "2", *pbm[1].Value)
+
+ m2 := ConvertToStringMap(pbm)
+ assert.Equal(t, 2, len(m2))
+ assert.Equal(t, "1", m2["a"])
+ assert.Equal(t, "2", m2["b"])
+}
+
[pulsar-client-go] 19/38: Support compression in producer
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 0eb04d510ed5817685b3e1f7280ff4eb4fd2856e
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Fri May 3 12:34:36 2019 -0700
Support compression in producer
---
pulsar/impl/batch_builder.go | 37 ++++++++++++++++--
pulsar/impl_partition_producer.go | 8 ++--
pulsar/producer_test.go | 80 +++++++++++++++++++++++++++++++++++++++
pulsar/util_test.go | 12 ++++++
4 files changed, 129 insertions(+), 8 deletions(-)
diff --git a/pulsar/impl/batch_builder.go b/pulsar/impl/batch_builder.go
index e8c0af8..0619154 100644
--- a/pulsar/impl/batch_builder.go
+++ b/pulsar/impl/batch_builder.go
@@ -3,6 +3,7 @@ package impl
import (
"github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
+ "pulsar-client-go-native/pulsar/impl/compression"
pb "pulsar-client-go-native/pulsar/pulsar_proto"
"time"
)
@@ -28,13 +29,16 @@ type BatchBuilder struct {
cmdSend *pb.BaseCommand
msgMetadata *pb.MessageMetadata
callbacks []interface{}
+
+ compressionProvider compression.Provider
}
-func NewBatchBuilder(maxMessages uint, producerName string, producerId uint64) *BatchBuilder {
+func NewBatchBuilder(maxMessages uint, producerName string, producerId uint64,
+ compressionType pb.CompressionType) *BatchBuilder {
if maxMessages == 0 {
maxMessages = DefaultMaxMessagesPerBatch
}
- return &BatchBuilder{
+ bb := &BatchBuilder{
buffer: NewBuffer(4096),
numMessages: 0,
maxMessages: maxMessages,
@@ -47,8 +51,15 @@ func NewBatchBuilder(maxMessages uint, producerName string, producerId uint64) *
msgMetadata: &pb.MessageMetadata{
ProducerName: &producerName,
},
- callbacks: []interface{}{},
+ callbacks: []interface{}{},
+ compressionProvider: getCompressionProvider(compressionType),
+ }
+
+ if compressionType != pb.CompressionType_NONE {
+ bb.msgMetadata.Compression = &compressionType
}
+
+ return bb
}
func (bb *BatchBuilder) IsFull() bool {
@@ -108,11 +119,29 @@ func (bb *BatchBuilder) Flush() (batchData []byte, sequenceId uint64, callbacks
bb.msgMetadata.NumMessagesInBatch = proto.Int32(int32(bb.numMessages))
bb.cmdSend.Send.NumMessages = proto.Int32(int32(bb.numMessages))
+ compressed := bb.compressionProvider.Compress(bb.buffer.ReadableSlice())
+
buffer := NewBuffer(4096)
- serializeBatch(buffer, bb.cmdSend, bb.msgMetadata, bb.buffer.ReadableSlice())
+ serializeBatch(buffer, bb.cmdSend, bb.msgMetadata, compressed)
callbacks = bb.callbacks
sequenceId = bb.cmdSend.Send.GetSequenceId()
bb.reset()
return buffer.ReadableSlice(), sequenceId, callbacks
}
+
+func getCompressionProvider(compressionType pb.CompressionType) compression.Provider {
+ switch compressionType {
+ case pb.CompressionType_NONE:
+ return compression.NoopProvider
+ case pb.CompressionType_LZ4:
+ return compression.Lz4Provider
+ case pb.CompressionType_ZLIB:
+ return compression.ZLibProvider
+ case pb.CompressionType_ZSTD:
+ return compression.ZStdProvider
+ default:
+ log.Panic("Unsupported compression type: ", compressionType)
+ return nil
+ }
+}
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index 2557d1d..b87384d 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -115,7 +115,8 @@ func (p *partitionProducer) grabCnx() error {
p.producerName = res.Response.ProducerSuccess.ProducerName
if p.batchBuilder == nil {
- p.batchBuilder = impl.NewBatchBuilder(p.options.BatchingMaxMessages, *p.producerName, p.producerId)
+ p.batchBuilder = impl.NewBatchBuilder(p.options.BatchingMaxMessages, *p.producerName,
+ p.producerId, pb.CompressionType(p.options.CompressionType))
}
if p.sequenceIdGenerator == nil {
nextSequenceId := uint64(res.Response.ProducerSuccess.GetLastSequenceId() + 1)
@@ -235,8 +236,8 @@ func (p *partitionProducer) internalSend(request *sendRequest) {
}
type pendingItem struct {
- batchData []byte
- sequenceId uint64
+ batchData []byte
+ sequenceId uint64
sendRequests []interface{}
}
@@ -393,4 +394,3 @@ type flushRequest struct {
waitGroup *sync.WaitGroup
err error
}
-
diff --git a/pulsar/producer_test.go b/pulsar/producer_test.go
new file mode 100644
index 0000000..ab3d739
--- /dev/null
+++ b/pulsar/producer_test.go
@@ -0,0 +1,80 @@
+package pulsar
+
+import (
+ "context"
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func TestSimpleProducer(t *testing.T) {
+ client, err := NewClient(ClientOptions{
+ URL: serviceUrl,
+ })
+ assert.NoError(t, err)
+
+ producer, err := client.CreateProducer(ProducerOptions{
+ Topic: newTopicName(),
+ })
+
+ assert.NoError(t, err)
+ assert.NotNil(t, producer)
+
+ for i := 0; i < 10; i++ {
+ err := producer.Send(context.Background(), &ProducerMessage{
+ Payload: []byte("hello"),
+ })
+
+ assert.NoError(t, err)
+ }
+
+ err = producer.Close()
+ assert.NoError(t, err)
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
+
+func TestProducerCompression(t *testing.T) {
+
+ type testProvider struct {
+ name string
+ compressionType CompressionType
+ }
+
+ var providers = []testProvider{
+ {"zlib", ZLib},
+ {"lz4", LZ4},
+ {"zstd", ZSTD},
+ }
+
+ for _, p := range providers {
+ t.Run(p.name, func(t *testing.T) {
+ client, err := NewClient(ClientOptions{
+ URL: serviceUrl,
+ })
+ assert.NoError(t, err)
+
+ producer, err := client.CreateProducer(ProducerOptions{
+ Topic: newTopicName(),
+ CompressionType: p.compressionType,
+ })
+
+ assert.NoError(t, err)
+ assert.NotNil(t, producer)
+
+ for i := 0; i < 10; i++ {
+ err := producer.Send(context.Background(), &ProducerMessage{
+ Payload: []byte("hello"),
+ })
+
+ assert.NoError(t, err)
+ }
+
+ err = producer.Close()
+ assert.NoError(t, err)
+
+ err = client.Close()
+ assert.NoError(t, err)
+ })
+ }
+}
diff --git a/pulsar/util_test.go b/pulsar/util_test.go
new file mode 100644
index 0000000..4bc67d3
--- /dev/null
+++ b/pulsar/util_test.go
@@ -0,0 +1,12 @@
+package pulsar
+
+import (
+ "fmt"
+ "time"
+)
+
+const serviceUrl = "pulsar://localhost:6650"
+
+func newTopicName() string {
+ return fmt.Sprintf("my-topic-%v", time.Now().Nanosecond())
+}
[pulsar-client-go] 04/38: Create producer session
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit ccc596a716e0a15944fc3d270f842cffad8ec1fb
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Sat Mar 30 07:47:31 2019 -0700
Create producer session
---
pulsar/impl/commands.go | 4 ++
pulsar/impl/connection.go | 7 ++-
pulsar/impl/connection_pool.go | 14 +++--
pulsar/impl/lookup_service.go | 34 ++++++++++--
pulsar/impl/rpc_client.go | 30 +++++++---
pulsar/impl_client.go | 10 +++-
pulsar/impl_partition_producer.go | 112 ++++++++++++++++++++++++++++----------
pulsar/impl_producer.go | 50 ++++++++---------
pulsar/message.go | 4 +-
pulsar/producer.go | 4 +-
10 files changed, 186 insertions(+), 83 deletions(-)
diff --git a/pulsar/impl/commands.go b/pulsar/impl/commands.go
index 90760e1..16e5b60 100644
--- a/pulsar/impl/commands.go
+++ b/pulsar/impl/commands.go
@@ -24,6 +24,10 @@ func baseCommand(cmdType pb.BaseCommand_Type, msg proto.Message) *pb.BaseCommand
cmd.PartitionMetadata = msg.(*pb.CommandPartitionedTopicMetadata)
break
+ case pb.BaseCommand_PRODUCER:
+ cmd.Producer = msg.(*pb.CommandProducer)
+ break
+
default:
log.Panic("Missing command type: ", cmdType)
}
diff --git a/pulsar/impl/connection.go b/pulsar/impl/connection.go
index 6379f6a..28871cb 100644
--- a/pulsar/impl/connection.go
+++ b/pulsar/impl/connection.go
@@ -5,6 +5,7 @@ import (
"github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
"net"
+ "net/url"
pb "pulsar-client-go-native/pulsar/pulsar_proto"
"sync"
"sync/atomic"
@@ -51,11 +52,11 @@ type connection struct {
pendingReqs map[uint64]*request
}
-func newConnection(logicalAddr string, physicalAddr string) *connection {
+func newConnection(logicalAddr *url.URL, physicalAddr *url.URL) *connection {
cnx := &connection{
state: connectionInit,
- logicalAddr: logicalAddr,
- physicalAddr: physicalAddr,
+ logicalAddr: logicalAddr.Host,
+ physicalAddr: physicalAddr.Host,
writeBuffer: NewBuffer(4096),
log: log.WithField("raddr", physicalAddr),
pendingReqs: make(map[uint64]*request),
diff --git a/pulsar/impl/connection_pool.go b/pulsar/impl/connection_pool.go
index 676f205..1fa647f 100644
--- a/pulsar/impl/connection_pool.go
+++ b/pulsar/impl/connection_pool.go
@@ -1,11 +1,13 @@
package impl
import (
+ log "github.com/sirupsen/logrus"
+ "net/url"
"sync"
)
type ConnectionPool interface {
- GetConnection(logicalAddr string, physicalAddr string) (Connection, error)
+ GetConnection(logicalAddr *url.URL, physicalAddr *url.URL) (Connection, error)
// Close all the connections in the pool
Close()
@@ -19,11 +21,13 @@ func NewConnectionPool() ConnectionPool {
return &connectionPool{}
}
-func (p *connectionPool) GetConnection(logicalAddr string, physicalAddr string) (Connection, error) {
- cachedCnx, found := p.pool.Load(logicalAddr)
+func (p *connectionPool) GetConnection(logicalAddr *url.URL, physicalAddr *url.URL) (Connection, error) {
+ cachedCnx, found := p.pool.Load(logicalAddr.Host)
if found {
cnx := cachedCnx.(*connection)
- if err := cnx.waitUntilReady(); err != nil {
+ log.Debug("Found connection in cache:", cnx.logicalAddr, cnx.physicalAddr)
+
+ if err := cnx.waitUntilReady(); err == nil {
// Connection is ready to be used
return cnx, nil
} else {
@@ -33,7 +37,7 @@ func (p *connectionPool) GetConnection(logicalAddr string, physicalAddr string)
}
// Try to create a new connection
- newCnx, wasCached := p.pool.LoadOrStore(logicalAddr, newConnection(logicalAddr, physicalAddr))
+ newCnx, wasCached := p.pool.LoadOrStore(logicalAddr.Host, newConnection(logicalAddr, physicalAddr))
cnx := newCnx.(*connection)
if !wasCached {
cnx.start()
diff --git a/pulsar/impl/lookup_service.go b/pulsar/impl/lookup_service.go
index 0ebf424..afd0dda 100644
--- a/pulsar/impl/lookup_service.go
+++ b/pulsar/impl/lookup_service.go
@@ -1,6 +1,8 @@
package impl
import (
+ "errors"
+ "fmt"
log "github.com/sirupsen/logrus"
"net/url"
pb "pulsar-client-go-native/pulsar/pulsar_proto"
@@ -16,18 +18,22 @@ type LookupService interface {
}
type lookupService struct {
- rpcClient RpcClient
+ rpcClient RpcClient
+ serviceUrl *url.URL
}
-func NewLookupService(rpcClient RpcClient) LookupService {
+func NewLookupService(rpcClient RpcClient, serviceUrl *url.URL) LookupService {
return &lookupService{
- rpcClient: rpcClient,
+ rpcClient: rpcClient,
+ serviceUrl: serviceUrl,
}
}
func (ls *lookupService) Lookup(topic string) (*LookupResult, error) {
// Follow brokers redirect up to certain number of times
- for i := 0; i < 20; i++ {
+ const lookupResultMaxRedirect = 20
+
+ for i := 0; i < lookupResultMaxRedirect; i++ {
id := ls.rpcClient.NewRequestId()
res, err := ls.rpcClient.RequestToAnyBroker(id, pb.BaseCommand_LOOKUP, &pb.CommandLookupTopic{
RequestId: &id,
@@ -42,6 +48,7 @@ func (ls *lookupService) Lookup(topic string) (*LookupResult, error) {
lr := res.Response.LookupTopicResponse
switch *lr.Response {
case pb.CommandLookupTopicResponse_Redirect:
+ // TODO: Handle redirects
log.WithField("topic", topic).Infof("Follow redirect to broker. %v / %v - Use proxy: %v",
lr.BrokerServiceUrl, lr.BrokerServiceUrlTls, lr.ProxyThroughServiceUrl)
break
@@ -49,12 +56,27 @@ func (ls *lookupService) Lookup(topic string) (*LookupResult, error) {
case pb.CommandLookupTopicResponse_Connect:
log.WithField("topic", topic).Infof("Successfully looked up topic on broker. %s / %s - Use proxy: %t",
lr.GetBrokerServiceUrl(), lr.GetBrokerServiceUrlTls(), lr.GetProxyThroughServiceUrl())
- return nil, nil
+
+ logicalAddress, err := url.Parse(lr.GetBrokerServiceUrl())
+ if err != nil {
+ return nil, err
+ }
+
+ var physicalAddr *url.URL
+ if lr.GetProxyThroughServiceUrl() {
+ physicalAddr = ls.serviceUrl
+ } else {
+ physicalAddr = logicalAddress
+ }
+ return &LookupResult{
+ LogicalAddr: logicalAddress,
+ PhysicalAddr: physicalAddr,
+ }, nil
case pb.CommandLookupTopicResponse_Failed:
log.WithField("topic", topic).Warn("Failed to lookup topic",
lr.Error.String())
- return nil, nil
+ return nil, errors.New(fmt.Sprintf("failed to lookup topic: %s", lr.Error.String()))
}
}
diff --git a/pulsar/impl/rpc_client.go b/pulsar/impl/rpc_client.go
index fd76569..2aa6106 100644
--- a/pulsar/impl/rpc_client.go
+++ b/pulsar/impl/rpc_client.go
@@ -17,31 +17,37 @@ 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 string, physicalAddr string, requestId uint64,
+ Request(logicalAddr *url.URL, physicalAddr *url.URL, requestId uint64,
cmdType pb.BaseCommand_Type, message proto.Message) (*RpcResult, error)
}
type rpcClient struct {
- hostPort string
- pool ConnectionPool
- requestIdGenerator uint64
+ serviceUrl *url.URL
+ pool ConnectionPool
+ requestIdGenerator uint64
+ producerIdGenerator uint64
+ consumerIdGenerator uint64
}
func NewRpcClient(serviceUrl *url.URL, pool ConnectionPool) RpcClient {
return &rpcClient{
- hostPort: serviceUrl.Host,
- pool: pool,
+ serviceUrl: serviceUrl,
+ pool: pool,
}
}
func (c *rpcClient) RequestToAnyBroker(requestId uint64, cmdType pb.BaseCommand_Type, message proto.Message) (*RpcResult, error) {
- return c.Request(c.hostPort, c.hostPort, requestId, cmdType, message)
+ return c.Request(c.serviceUrl, c.serviceUrl, requestId, cmdType, message)
}
-func (c *rpcClient) Request(logicalAddr string, physicalAddr string, requestId uint64,
+func (c *rpcClient) Request(logicalAddr *url.URL, physicalAddr *url.URL, requestId uint64,
cmdType pb.BaseCommand_Type, message proto.Message) (*RpcResult, error) {
// TODO: Add retry logic in case of connection issues
cnx, err := c.pool.GetConnection(logicalAddr, physicalAddr)
@@ -69,3 +75,11 @@ func (c *rpcClient) Request(logicalAddr string, physicalAddr string, requestId u
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/pulsar/impl_client.go b/pulsar/impl_client.go
index 4a7047f..a1f6e10 100644
--- a/pulsar/impl_client.go
+++ b/pulsar/impl_client.go
@@ -15,7 +15,9 @@ type client struct {
rpcClient impl.RpcClient
lookupService impl.LookupService
- handlers map[impl.Closable]bool
+ handlers map[impl.Closable]bool
+ producerIdGenerator uint64
+ consumerIdGenerator uint64
}
func newClient(options ClientOptions) (Client, error) {
@@ -37,12 +39,13 @@ func newClient(options ClientOptions) (Client, error) {
cnxPool: impl.NewConnectionPool(),
}
c.rpcClient = impl.NewRpcClient(url, c.cnxPool)
- c.lookupService = impl.NewLookupService(c.rpcClient)
+ c.lookupService = impl.NewLookupService(c.rpcClient, url)
+ c.handlers = make(map[impl.Closable]bool)
return c, nil
}
func (client *client) CreateProducer(options ProducerOptions) (Producer, error) {
- producer, err := newProducer(client, options)
+ producer, err := newProducer(client, &options)
if err == nil {
client.handlers[producer] = true
}
@@ -92,6 +95,7 @@ func (client *client) TopicPartitions(topic string) ([]string, error) {
}
}
+
func (client *client) Close() error {
for handler := range client.handlers {
if err := handler.Close(); err != nil {
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index d035ad1..4ba5506 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -3,8 +3,8 @@ package pulsar
import (
"context"
log "github.com/sirupsen/logrus"
- //"pulsar-client-go-native/pulsar/impl"
- //pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ "pulsar-client-go-native/pulsar/impl"
+ pb "pulsar-client-go-native/pulsar/pulsar_proto"
"sync"
)
@@ -14,12 +14,27 @@ type partitionProducer struct {
log *log.Entry
mutex sync.Mutex
cond *sync.Cond
+ cnx impl.Connection
+
+ producerName *string
+ producerId uint64
+
+ // Channel where app is posting messages to be published
+ eventsChan chan interface{}
}
func newPartitionProducer(client *client, topic string, options *ProducerOptions) (*partitionProducer, error) {
p := &partitionProducer{
- log: log.WithField("topic", topic),
+ log: log.WithField("topic", topic),
+ client: client,
+ topic: topic,
+ producerId: client.rpcClient.NewProducerId(),
+ eventsChan: make(chan interface{}),
+ }
+
+ if options.Name != "" {
+ p.producerName = &options.Name
}
err := p.grabCnx()
@@ -27,55 +42,95 @@ func newPartitionProducer(client *client, topic string, options *ProducerOptions
log.WithError(err).Errorf("Failed to create producer")
return nil, err
} else {
- log.Info("Created producer")
+ log.Info("Created producer on cnx: ")
+ go p.run()
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
- //}
-
- //id := p.client.rpcClient.NewRequestId()
- //p.client.rpcClient.Request(lr.LogicalAddr.Host, lr.PhysicalAddr.Host, id, pb.BaseCommand_PRODUCER, *pb.CommandProducer{
- //
- //})
- //
- //var cnx impl.Connection
- //cnx, err = p.client.cnxPool.GetConnection(lr.LogicalAddr.Host, lr.PhysicalAddr.Host)
- //if err != nil {
- // p.log.WithError(err).Warn("Failed to get connection")
- // return err
- //}
-
- //cnx.
+ lr, err := p.client.lookupService.Lookup(p.topic)
+ if err != nil {
+ p.log.WithError(err).Warn("Failed to lookup topic")
+ return err
+ }
+
+ p.log.Info("Lookup result: ", lr)
+ id := p.client.rpcClient.NewRequestId()
+ res, err := p.client.rpcClient.Request(lr.LogicalAddr, lr.PhysicalAddr, id, pb.BaseCommand_PRODUCER, &pb.CommandProducer{
+ RequestId: &id,
+ Topic: &p.topic,
+ Encrypted: nil,
+ Metadata: nil,
+ ProducerId: &p.producerId,
+ ProducerName: p.producerName,
+ Schema: nil,
+ })
+
+ if err != nil {
+ p.log.WithError(err).Error("Failed to create producer")
+ return err
+ }
+ p.producerName = res.Response.ProducerSuccess.ProducerName
+ p.cnx = res.Cnx
+ p.log.WithField("cnx", res.Cnx).Info("Created producer")
return nil
}
func (p *partitionProducer) run() {
-
+ for {
+ i := <-p.eventsChan
+ switch v := i.(type) {
+ case *sendRequest:
+ p.log.Info("Received send request: ", v)
+ v.callback(nil, v.msg, nil)
+ }
+ }
}
func (p *partitionProducer) Topic() string {
- return ""
+ return p.topic
}
func (p *partitionProducer) Name() string {
- return ""
+ return *p.producerName
}
-func (p *partitionProducer) Send(context.Context, ProducerMessage) error {
+func (p *partitionProducer) Send(ctx context.Context, msg *ProducerMessage) error {
+ wg := sync.WaitGroup{}
+ wg.Add(1)
+
+ var err error
+
+ p.SendAsync(ctx, msg, func(ID MessageID, message *ProducerMessage, e error) {
+ err = e
+ wg.Done()
+ })
+
+ // When sending synchronously we flush immediately to avoid
+ // the increased latency and reduced throughput of batching
+ if err = p.Flush(); err != nil {
+ return err
+ }
+
+ wg.Wait()
+ return err
return nil
}
-func (p *partitionProducer) SendAsync(context.Context, ProducerMessage, func(ProducerMessage, error)) {
+type sendRequest struct {
+ ctx context.Context
+ msg *ProducerMessage
+ callback func(MessageID, *ProducerMessage, error)
+}
+
+func (p *partitionProducer) SendAsync(ctx context.Context, msg *ProducerMessage, callback func(MessageID, *ProducerMessage, error)) {
+ p.eventsChan <- &sendRequest{ctx, msg, callback}
}
func (p *partitionProducer) LastSequenceID() int64 {
+ // TODO: return real last sequence id
return -1
}
@@ -84,5 +139,6 @@ func (p *partitionProducer) Flush() error {
}
func (p *partitionProducer) Close() error {
+ p.log.Info("Closing producer")
return nil
}
diff --git a/pulsar/impl_producer.go b/pulsar/impl_producer.go
index 587b09d..abedfab 100644
--- a/pulsar/impl_producer.go
+++ b/pulsar/impl_producer.go
@@ -2,18 +2,16 @@ package pulsar
import (
"context"
- "fmt"
"pulsar-client-go-native/pulsar/impl"
- "sync"
)
type producer struct {
topic string
producers []Producer
- messageRouter func(ProducerMessage, TopicMetadata) int
+ messageRouter func(*ProducerMessage, TopicMetadata) int
}
-func newProducer(client *client, options ProducerOptions) (*producer, error) {
+func newProducer(client *client, options *ProducerOptions) (*producer, error) {
if options.Topic == "" {
return nil, newError(ResultInvalidTopicName, "Topic name is required for producer")
}
@@ -24,7 +22,7 @@ func newProducer(client *client, options ProducerOptions) (*producer, error) {
if options.MessageRouter == nil {
internalRouter := impl.NewDefaultRouter(options.BatchingMaxPublishDelay)
- p.messageRouter = func(message ProducerMessage, metadata TopicMetadata) int {
+ p.messageRouter = func(message *ProducerMessage, metadata TopicMetadata) int {
return internalRouter(metadata.NumPartitions())
}
}
@@ -45,12 +43,10 @@ func newProducer(client *client, options ProducerOptions) (*producer, error) {
c := make(chan ProducerError, numPartitions)
- for i := 0; i < numPartitions; i++ {
- partition := i
+ for partitionIdx, partition := range partitions {
go func() {
- partitionName := fmt.Sprintf("%s-partition-%d", options.Topic, partition)
- prod, err := newPartitionProducer(client, partitionName, &options)
- c <- ProducerError{partition, prod, err}
+ prod, err := newPartitionProducer(client, partition, options)
+ c <- ProducerError{partitionIdx, prod, err}
}()
}
@@ -85,22 +81,12 @@ func (p *producer) NumPartitions() uint32 {
return uint32(len(p.producers))
}
-func (p *producer) Send(ctx context.Context, msg ProducerMessage) error {
- wg := sync.WaitGroup{}
- wg.Add(1)
-
- var err error
-
- p.SendAsync(ctx, msg, func(message ProducerMessage, e error) {
- err = e
- wg.Done()
- })
-
- wg.Wait()
- return err
+func (p *producer) Send(ctx context.Context, msg *ProducerMessage) error {
+ partition := p.messageRouter(msg, p)
+ return p.producers[partition].Send(ctx, msg)
}
-func (p *producer) SendAsync(ctx context.Context, msg ProducerMessage, callback func(ProducerMessage, error)) {
+func (p *producer) SendAsync(ctx context.Context, msg *ProducerMessage, callback func(MessageID, *ProducerMessage, error)) {
partition := p.messageRouter(msg, p)
p.producers[partition].SendAsync(ctx, msg, callback)
}
@@ -117,9 +103,21 @@ func (p *producer) LastSequenceID() int64 {
}
func (p *producer) Flush() error {
- return nil
+ var err error = nil
+ for _, pp := range p.producers {
+ if e := pp.Flush(); e != nil && err == nil {
+ err = e
+ }
+ }
+ return err
}
func (p *producer) Close() error {
- return nil
+ var err error = nil
+ for _, pp := range p.producers {
+ if e := pp.Close(); e != nil && err == nil {
+ err = e
+ }
+ }
+ return err
}
diff --git a/pulsar/message.go b/pulsar/message.go
index ad61704..60dd989 100644
--- a/pulsar/message.go
+++ b/pulsar/message.go
@@ -83,8 +83,8 @@ func DeserializeMessageID(data []byte) MessageID {
var (
// MessageID that points to the earliest message avaialable in a topic
-//EarliestMessage MessageID = earliestMessageID()
+// TODO: EarliestMessage MessageID = earliestMessageID()
// MessageID that points to the latest message
-//LatestMessage MessageID = latestMessageID()
+// TODO: LatestMessage MessageID = latestMessageID()
)
diff --git a/pulsar/producer.go b/pulsar/producer.go
index 90769cb..0e59e66 100644
--- a/pulsar/producer.go
+++ b/pulsar/producer.go
@@ -161,12 +161,12 @@ type Producer interface {
// 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) error
+ Send(context.Context, *ProducerMessage) error
// Send a message in asynchronous mode
// The callback will report back the message being published and
// the eventual error in publishing
- SendAsync(context.Context, ProducerMessage, func(ProducerMessage, error))
+ SendAsync(context.Context, *ProducerMessage, func(MessageID, *ProducerMessage, error))
// 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
[pulsar-client-go] 33/38: Renamed `impl` package to `internal`
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit d6dbcfa0037e899417d1cf5536849bf918de8d26
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Tue May 7 16:38:57 2019 -0700
Renamed `impl` package to `internal`
---
pulsar/impl_client.go | 22 +++++++++++-----------
pulsar/impl_message.go | 2 +-
pulsar/impl_partition_producer.go | 20 ++++++++++----------
pulsar/impl_producer.go | 12 ++++++------
pulsar/{impl => internal}/backoff.go | 2 +-
pulsar/{impl => internal}/batch_builder.go | 6 +++---
pulsar/{impl => internal}/buffer.go | 2 +-
pulsar/{impl => internal}/buffer_test.go | 2 +-
pulsar/{impl => internal}/checksum.go | 2 +-
pulsar/{impl => internal}/closable.go | 2 +-
pulsar/{impl => internal}/commands.go | 4 ++--
pulsar/{impl => internal}/commands_test.go | 2 +-
.../{impl => internal}/compression/compression.go | 0
.../compression/compression_test.go | 0
pulsar/{impl => internal}/compression/lz4.go | 0
pulsar/{impl => internal}/compression/noop.go | 0
pulsar/{impl => internal}/compression/zlib.go | 0
pulsar/{impl => internal}/compression/zstd.go | 0
pulsar/{impl => internal}/connection.go | 4 ++--
pulsar/{impl => internal}/connection_pool.go | 2 +-
pulsar/{impl => internal}/connection_reader.go | 4 ++--
pulsar/{impl => internal}/default_router.go | 2 +-
pulsar/{impl => internal}/default_router_test.go | 2 +-
pulsar/{impl => internal}/hash.go | 2 +-
pulsar/{impl => internal}/hash_test.go | 2 +-
pulsar/{impl => internal}/lookup_service.go | 4 ++--
pulsar/{impl => internal}/lookup_service_test.go | 4 ++--
pulsar/{ => internal}/pulsar_proto/PulsarApi.pb.go | 0
pulsar/{impl => internal}/rpc_client.go | 4 ++--
pulsar/{impl => internal}/topic_name.go | 2 +-
pulsar/{impl => internal}/topic_name_test.go | 2 +-
pulsar/{impl => internal}/util/blocking_queue.go | 0
.../{impl => internal}/util/blocking_queue_test.go | 0
pulsar/{impl => internal}/util/semaphore.go | 0
pulsar/{impl => internal}/utils.go | 2 +-
pulsar/producer_test.go | 2 +-
36 files changed, 58 insertions(+), 58 deletions(-)
diff --git a/pulsar/impl_client.go b/pulsar/impl_client.go
index 89b955d..0db2ee8 100644
--- a/pulsar/impl_client.go
+++ b/pulsar/impl_client.go
@@ -23,18 +23,18 @@ import (
"fmt"
log "github.com/sirupsen/logrus"
"net/url"
- "pulsar-client-go/pulsar/impl"
- pb "pulsar-client-go/pulsar/pulsar_proto"
+ "pulsar-client-go/pulsar/internal"
+ pb "pulsar-client-go/pulsar/internal/pulsar_proto"
)
type client struct {
options ClientOptions
- cnxPool impl.ConnectionPool
- rpcClient impl.RpcClient
- lookupService impl.LookupService
+ cnxPool internal.ConnectionPool
+ rpcClient internal.RpcClient
+ lookupService internal.LookupService
- handlers map[impl.Closable]bool
+ handlers map[internal.Closable]bool
producerIdGenerator uint64
consumerIdGenerator uint64
}
@@ -55,11 +55,11 @@ func newClient(options ClientOptions) (Client, error) {
}
c := &client{
- cnxPool: impl.NewConnectionPool(),
+ cnxPool: internal.NewConnectionPool(),
}
- c.rpcClient = impl.NewRpcClient(url, c.cnxPool)
- c.lookupService = impl.NewLookupService(c.rpcClient, url)
- c.handlers = make(map[impl.Closable]bool)
+ c.rpcClient = internal.NewRpcClient(url, c.cnxPool)
+ c.lookupService = internal.NewLookupService(c.rpcClient, url)
+ c.handlers = make(map[internal.Closable]bool)
return c, nil
}
@@ -82,7 +82,7 @@ func (client *client) CreateReader(options ReaderOptions) (Reader, error) {
}
func (client *client) TopicPartitions(topic string) ([]string, error) {
- topicName, err := impl.ParseTopicName(topic)
+ topicName, err := internal.ParseTopicName(topic)
if err != nil {
return nil, err
}
diff --git a/pulsar/impl_message.go b/pulsar/impl_message.go
index 24f3f30..b73445f 100644
--- a/pulsar/impl_message.go
+++ b/pulsar/impl_message.go
@@ -21,7 +21,7 @@ package pulsar
import (
"github.com/golang/protobuf/proto"
- pb "pulsar-client-go/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/internal/pulsar_proto"
)
type messageId struct {
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index 41e7702..0e38fa6 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -23,9 +23,9 @@ import (
"context"
"github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
- "pulsar-client-go/pulsar/impl"
- "pulsar-client-go/pulsar/impl/util"
- pb "pulsar-client-go/pulsar/pulsar_proto"
+ "pulsar-client-go/pulsar/internal"
+ "pulsar-client-go/pulsar/internal/util"
+ pb "pulsar-client-go/pulsar/internal/pulsar_proto"
"sync"
"sync/atomic"
"time"
@@ -45,12 +45,12 @@ type partitionProducer struct {
client *client
topic string
log *log.Entry
- cnx impl.Connection
+ cnx internal.Connection
options *ProducerOptions
producerName *string
producerId uint64
- batchBuilder *impl.BatchBuilder
+ batchBuilder *internal.BatchBuilder
sequenceIdGenerator *uint64
batchFlushTicker *time.Ticker
@@ -140,7 +140,7 @@ func (p *partitionProducer) grabCnx() error {
p.producerName = res.Response.ProducerSuccess.ProducerName
if p.batchBuilder == nil {
- p.batchBuilder = impl.NewBatchBuilder(p.options.BatchingMaxMessages, *p.producerName,
+ p.batchBuilder = internal.NewBatchBuilder(p.options.BatchingMaxMessages, *p.producerName,
p.producerId, pb.CompressionType(p.options.CompressionType))
}
if p.sequenceIdGenerator == nil {
@@ -170,7 +170,7 @@ func (p *partitionProducer) ConnectionClosed() {
func (p *partitionProducer) reconnectToBroker() {
p.log.Info("Reconnecting to broker")
- backoff := impl.Backoff{}
+ backoff := internal.Backoff{}
for {
if p.state != producerReady {
// Producer is already closing
@@ -231,7 +231,7 @@ func (p *partitionProducer) internalSend(request *sendRequest) {
}
if msg.EventTime != nil {
- smm.EventTime = proto.Uint64(impl.TimestampMillis(*msg.EventTime))
+ smm.EventTime = proto.Uint64(internal.TimestampMillis(*msg.EventTime))
}
if msg.Key != "" {
@@ -239,10 +239,10 @@ func (p *partitionProducer) internalSend(request *sendRequest) {
}
if msg.Properties != nil {
- smm.Properties = impl.ConvertFromStringMap(msg.Properties)
+ smm.Properties = internal.ConvertFromStringMap(msg.Properties)
}
- sequenceId := impl.GetAndAdd(p.sequenceIdGenerator, 1)
+ sequenceId := internal.GetAndAdd(p.sequenceIdGenerator, 1)
if sendAsBatch {
for ; p.batchBuilder.Add(smm, sequenceId, msg.Payload, request, msg.ReplicationClusters) == false; {
diff --git a/pulsar/impl_producer.go b/pulsar/impl_producer.go
index c379531..afe8b3a 100644
--- a/pulsar/impl_producer.go
+++ b/pulsar/impl_producer.go
@@ -21,7 +21,7 @@ package pulsar
import (
"context"
- "pulsar-client-go/pulsar/impl"
+ "pulsar-client-go/pulsar/internal"
)
type producer struct {
@@ -33,11 +33,11 @@ type producer struct {
func getHashingFunction(s HashingScheme) func(string) uint32 {
switch s {
case JavaStringHash:
- return impl.JavaStringHash
+ return internal.JavaStringHash
case Murmur3_32Hash:
- return impl.Murmur3_32Hash
+ return internal.Murmur3_32Hash
default:
- return impl.JavaStringHash
+ return internal.JavaStringHash
}
}
@@ -51,8 +51,8 @@ func newProducer(client *client, options *ProducerOptions) (*producer, error) {
}
if options.MessageRouter == nil {
- internalRouter := impl.NewDefaultRouter(
- impl.NewSystemClock(),
+ internalRouter := internal.NewDefaultRouter(
+ internal.NewSystemClock(),
getHashingFunction(options.HashingScheme),
options.BatchingMaxPublishDelay)
p.messageRouter = func(message *ProducerMessage, metadata TopicMetadata) int {
diff --git a/pulsar/impl/backoff.go b/pulsar/internal/backoff.go
similarity index 98%
rename from pulsar/impl/backoff.go
rename to pulsar/internal/backoff.go
index 3e7629e..94a185e 100644
--- a/pulsar/impl/backoff.go
+++ b/pulsar/internal/backoff.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import (
"time"
diff --git a/pulsar/impl/batch_builder.go b/pulsar/internal/batch_builder.go
similarity index 97%
rename from pulsar/impl/batch_builder.go
rename to pulsar/internal/batch_builder.go
index a3b41a2..5c18850 100644
--- a/pulsar/impl/batch_builder.go
+++ b/pulsar/internal/batch_builder.go
@@ -17,13 +17,13 @@
// under the License.
//
-package impl
+package internal
import (
"github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
- "pulsar-client-go/pulsar/impl/compression"
- pb "pulsar-client-go/pulsar/pulsar_proto"
+ "pulsar-client-go/pulsar/internal/compression"
+ pb "pulsar-client-go/pulsar/internal/pulsar_proto"
"time"
)
diff --git a/pulsar/impl/buffer.go b/pulsar/internal/buffer.go
similarity index 99%
rename from pulsar/impl/buffer.go
rename to pulsar/internal/buffer.go
index bf92b8f..cadf041 100644
--- a/pulsar/impl/buffer.go
+++ b/pulsar/internal/buffer.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import (
"encoding/binary"
diff --git a/pulsar/impl/buffer_test.go b/pulsar/internal/buffer_test.go
similarity index 98%
rename from pulsar/impl/buffer_test.go
rename to pulsar/internal/buffer_test.go
index e6ace40..72a9ee8 100644
--- a/pulsar/impl/buffer_test.go
+++ b/pulsar/internal/buffer_test.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import (
"testing"
diff --git a/pulsar/impl/checksum.go b/pulsar/internal/checksum.go
similarity index 98%
rename from pulsar/impl/checksum.go
rename to pulsar/internal/checksum.go
index 906c4dc..eba1460 100644
--- a/pulsar/impl/checksum.go
+++ b/pulsar/internal/checksum.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import "hash/crc32"
diff --git a/pulsar/impl/closable.go b/pulsar/internal/closable.go
similarity index 98%
rename from pulsar/impl/closable.go
rename to pulsar/internal/closable.go
index 3805556..77801a4 100644
--- a/pulsar/impl/closable.go
+++ b/pulsar/internal/closable.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
type Closable interface {
Close() error
diff --git a/pulsar/impl/commands.go b/pulsar/internal/commands.go
similarity index 98%
rename from pulsar/impl/commands.go
rename to pulsar/internal/commands.go
index 949d56d..b375817 100644
--- a/pulsar/impl/commands.go
+++ b/pulsar/internal/commands.go
@@ -17,12 +17,12 @@
// under the License.
//
-package impl
+package internal
import (
"github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
- pb "pulsar-client-go/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/internal/pulsar_proto"
)
const MaxFrameSize = 5 * 1024 * 1024
diff --git a/pulsar/impl/commands_test.go b/pulsar/internal/commands_test.go
similarity index 98%
rename from pulsar/impl/commands_test.go
rename to pulsar/internal/commands_test.go
index a1f08a8..7f510f1 100644
--- a/pulsar/impl/commands_test.go
+++ b/pulsar/internal/commands_test.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import (
"github.com/stretchr/testify/assert"
diff --git a/pulsar/impl/compression/compression.go b/pulsar/internal/compression/compression.go
similarity index 100%
rename from pulsar/impl/compression/compression.go
rename to pulsar/internal/compression/compression.go
diff --git a/pulsar/impl/compression/compression_test.go b/pulsar/internal/compression/compression_test.go
similarity index 100%
rename from pulsar/impl/compression/compression_test.go
rename to pulsar/internal/compression/compression_test.go
diff --git a/pulsar/impl/compression/lz4.go b/pulsar/internal/compression/lz4.go
similarity index 100%
rename from pulsar/impl/compression/lz4.go
rename to pulsar/internal/compression/lz4.go
diff --git a/pulsar/impl/compression/noop.go b/pulsar/internal/compression/noop.go
similarity index 100%
rename from pulsar/impl/compression/noop.go
rename to pulsar/internal/compression/noop.go
diff --git a/pulsar/impl/compression/zlib.go b/pulsar/internal/compression/zlib.go
similarity index 100%
rename from pulsar/impl/compression/zlib.go
rename to pulsar/internal/compression/zlib.go
diff --git a/pulsar/impl/compression/zstd.go b/pulsar/internal/compression/zstd.go
similarity index 100%
rename from pulsar/impl/compression/zstd.go
rename to pulsar/internal/compression/zstd.go
diff --git a/pulsar/impl/connection.go b/pulsar/internal/connection.go
similarity index 99%
rename from pulsar/impl/connection.go
rename to pulsar/internal/connection.go
index aa1c809..affa8cc 100644
--- a/pulsar/impl/connection.go
+++ b/pulsar/internal/connection.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import (
"errors"
@@ -25,7 +25,7 @@ import (
log "github.com/sirupsen/logrus"
"net"
"net/url"
- pb "pulsar-client-go/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/internal/pulsar_proto"
"sync"
"sync/atomic"
"time"
diff --git a/pulsar/impl/connection_pool.go b/pulsar/internal/connection_pool.go
similarity index 99%
rename from pulsar/impl/connection_pool.go
rename to pulsar/internal/connection_pool.go
index 474f2f8..4b56484 100644
--- a/pulsar/impl/connection_pool.go
+++ b/pulsar/internal/connection_pool.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import (
log "github.com/sirupsen/logrus"
diff --git a/pulsar/impl/connection_reader.go b/pulsar/internal/connection_reader.go
similarity index 98%
rename from pulsar/impl/connection_reader.go
rename to pulsar/internal/connection_reader.go
index fd753d1..836d7ce 100644
--- a/pulsar/impl/connection_reader.go
+++ b/pulsar/internal/connection_reader.go
@@ -17,14 +17,14 @@
// under the License.
//
-package impl
+package internal
import (
"bufio"
"github.com/golang/protobuf/proto"
"github.com/pkg/errors"
"io"
- pb "pulsar-client-go/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/internal/pulsar_proto"
)
type connectionReader struct {
diff --git a/pulsar/impl/default_router.go b/pulsar/internal/default_router.go
similarity index 99%
rename from pulsar/impl/default_router.go
rename to pulsar/internal/default_router.go
index 20db625..cbdff53 100644
--- a/pulsar/impl/default_router.go
+++ b/pulsar/internal/default_router.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import (
"math/rand"
diff --git a/pulsar/impl/default_router_test.go b/pulsar/internal/default_router_test.go
similarity index 99%
rename from pulsar/impl/default_router_test.go
rename to pulsar/internal/default_router_test.go
index 8cad90d..0134c99 100644
--- a/pulsar/impl/default_router_test.go
+++ b/pulsar/internal/default_router_test.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import (
"github.com/stretchr/testify/assert"
diff --git a/pulsar/impl/hash.go b/pulsar/internal/hash.go
similarity index 98%
rename from pulsar/impl/hash.go
rename to pulsar/internal/hash.go
index 61f580b..5ec7df8 100644
--- a/pulsar/impl/hash.go
+++ b/pulsar/internal/hash.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import "github.com/spaolacci/murmur3"
diff --git a/pulsar/impl/hash_test.go b/pulsar/internal/hash_test.go
similarity index 98%
rename from pulsar/impl/hash_test.go
rename to pulsar/internal/hash_test.go
index b4f41d5..79c4c62 100644
--- a/pulsar/impl/hash_test.go
+++ b/pulsar/internal/hash_test.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import (
"github.com/stretchr/testify/assert"
diff --git a/pulsar/impl/lookup_service.go b/pulsar/internal/lookup_service.go
similarity index 98%
rename from pulsar/impl/lookup_service.go
rename to pulsar/internal/lookup_service.go
index 13c74a7..1ec8841 100644
--- a/pulsar/impl/lookup_service.go
+++ b/pulsar/internal/lookup_service.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import (
"errors"
@@ -25,7 +25,7 @@ import (
"github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
"net/url"
- pb "pulsar-client-go/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/internal/pulsar_proto"
)
type LookupResult struct {
diff --git a/pulsar/impl/lookup_service_test.go b/pulsar/internal/lookup_service_test.go
similarity index 99%
rename from pulsar/impl/lookup_service_test.go
rename to pulsar/internal/lookup_service_test.go
index a5e8cb0..7e0d148 100644
--- a/pulsar/impl/lookup_service_test.go
+++ b/pulsar/internal/lookup_service_test.go
@@ -17,13 +17,13 @@
// under the License.
//
-package impl
+package internal
import (
"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert"
"net/url"
- pb "pulsar-client-go/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/internal/pulsar_proto"
"testing"
)
diff --git a/pulsar/pulsar_proto/PulsarApi.pb.go b/pulsar/internal/pulsar_proto/PulsarApi.pb.go
similarity index 100%
rename from pulsar/pulsar_proto/PulsarApi.pb.go
rename to pulsar/internal/pulsar_proto/PulsarApi.pb.go
diff --git a/pulsar/impl/rpc_client.go b/pulsar/internal/rpc_client.go
similarity index 98%
rename from pulsar/impl/rpc_client.go
rename to pulsar/internal/rpc_client.go
index 32be5b6..2281def 100644
--- a/pulsar/impl/rpc_client.go
+++ b/pulsar/internal/rpc_client.go
@@ -17,12 +17,12 @@
// under the License.
//
-package impl
+package internal
import (
"github.com/golang/protobuf/proto"
"net/url"
- pb "pulsar-client-go/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/internal/pulsar_proto"
"sync"
"sync/atomic"
)
diff --git a/pulsar/impl/topic_name.go b/pulsar/internal/topic_name.go
similarity index 99%
rename from pulsar/impl/topic_name.go
rename to pulsar/internal/topic_name.go
index 7b284ef..6cee520 100644
--- a/pulsar/impl/topic_name.go
+++ b/pulsar/internal/topic_name.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import (
"errors"
diff --git a/pulsar/impl/topic_name_test.go b/pulsar/internal/topic_name_test.go
similarity index 99%
rename from pulsar/impl/topic_name_test.go
rename to pulsar/internal/topic_name_test.go
index 7095edb..f1339a5 100644
--- a/pulsar/impl/topic_name_test.go
+++ b/pulsar/internal/topic_name_test.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import (
"testing"
diff --git a/pulsar/impl/util/blocking_queue.go b/pulsar/internal/util/blocking_queue.go
similarity index 100%
rename from pulsar/impl/util/blocking_queue.go
rename to pulsar/internal/util/blocking_queue.go
diff --git a/pulsar/impl/util/blocking_queue_test.go b/pulsar/internal/util/blocking_queue_test.go
similarity index 100%
rename from pulsar/impl/util/blocking_queue_test.go
rename to pulsar/internal/util/blocking_queue_test.go
diff --git a/pulsar/impl/util/semaphore.go b/pulsar/internal/util/semaphore.go
similarity index 100%
rename from pulsar/impl/util/semaphore.go
rename to pulsar/internal/util/semaphore.go
diff --git a/pulsar/impl/utils.go b/pulsar/internal/utils.go
similarity index 98%
rename from pulsar/impl/utils.go
rename to pulsar/internal/utils.go
index b9b9b08..30837d6 100644
--- a/pulsar/impl/utils.go
+++ b/pulsar/internal/utils.go
@@ -17,7 +17,7 @@
// under the License.
//
-package impl
+package internal
import (
"sync/atomic"
diff --git a/pulsar/producer_test.go b/pulsar/producer_test.go
index 318d811..5d781a3 100644
--- a/pulsar/producer_test.go
+++ b/pulsar/producer_test.go
@@ -23,7 +23,7 @@ import (
"context"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
- "pulsar-client-go/pulsar/impl/util"
+ "pulsar-client-go/pulsar/internal/util"
"sync"
"testing"
"time"
[pulsar-client-go] 30/38: Added license headers
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 1ead55b2a8709614387f22bb2ea0b7b8e560ded4
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Mon May 6 14:44:31 2019 -0700
Added license headers
---
LICENSE | 305 ++++++++++++++++++++++++++++
NOTICE | 6 +
pulsar/impl/backoff.go | 19 ++
pulsar/impl/batch_builder.go | 19 ++
pulsar/impl/buffer.go | 19 ++
pulsar/impl/buffer_test.go | 19 ++
pulsar/impl/checksum.go | 19 ++
pulsar/impl/closable.go | 19 ++
pulsar/impl/commands.go | 19 ++
pulsar/impl/commands_test.go | 19 ++
pulsar/impl/compression/compression.go | 19 ++
pulsar/impl/compression/compression_test.go | 19 ++
pulsar/impl/compression/lz4.go | 19 ++
pulsar/impl/compression/noop.go | 19 ++
pulsar/impl/compression/zlib.go | 19 ++
pulsar/impl/compression/zstd.go | 19 ++
pulsar/impl/connection.go | 19 ++
pulsar/impl/connection_pool.go | 19 ++
pulsar/impl/connection_reader.go | 19 ++
pulsar/impl/default_router.go | 19 ++
pulsar/impl/default_router_test.go | 19 ++
pulsar/impl/hash.go | 19 ++
pulsar/impl/hash_test.go | 19 ++
pulsar/impl/lookup_service.go | 19 ++
pulsar/impl/lookup_service_test.go | 19 ++
pulsar/impl/rpc_client.go | 19 ++
pulsar/impl/topic_name.go | 19 ++
pulsar/impl/topic_name_test.go | 19 ++
pulsar/impl/util/blocking_queue.go | 19 ++
pulsar/impl/util/blocking_queue_test.go | 19 ++
pulsar/impl/util/semaphore.go | 19 ++
pulsar/impl/utils.go | 19 ++
pulsar/impl_client.go | 19 ++
pulsar/impl_client_test.go | 19 ++
pulsar/impl_message.go | 19 ++
pulsar/impl_message_test.go | 19 ++
pulsar/impl_partition_producer.go | 19 ++
pulsar/impl_producer.go | 19 ++
pulsar/producer_test.go | 19 ++
pulsar/util_test.go | 19 ++
40 files changed, 1033 insertions(+)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..356931c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,305 @@
+
+ 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.
+
+----------------------------------------------------------------------------------------------------
+
+pulsar-common/src/main/java/org/apache/pulsar/common/util/protobuf/ByteBufCoded{Input,Output}Stream.java
+
+Copyright 2014, Google Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Code generated by the Protocol Buffer compiler is owned by the owner
+of the input file used when generating it. This code is not
+standalone and requires a support library to be linked with it. This
+support library is itself covered by the above license.
+
+----------------------------------------------------------------------------------------------------
+
+pulsar-client-cpp/lib/lz4/lz4.{h,c}
+
+LZ4 - Fast LZ compression algorithm
+Copyright (C) 2011-2015, Yann Collet.
+
+BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You can contact the author at :
+- LZ4 source repository : https://github.com/Cyan4973/lz4
+- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+
+----------------------------------------------------------------------------------------------------
+
+pulsar-client-cpp/lib/checksum/crc32c_sw.cc
+
+/* crc32c.c -- compute CRC-32C using the Intel crc32 instruction
+ * Copyright (C) 2013 Mark Adler
+ * Version 1.1 1 Aug 2013 Mark Adler
+ */
+
+/*
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Mark Adler
+ madler@alumni.caltech.edu
+ */
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..92236a6
--- /dev/null
+++ b/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/pulsar/impl/backoff.go b/pulsar/impl/backoff.go
index 451509f..afd6c4f 100644
--- a/pulsar/impl/backoff.go
+++ b/pulsar/impl/backoff.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/batch_builder.go b/pulsar/impl/batch_builder.go
index 6675d8d..0cb19f0 100644
--- a/pulsar/impl/batch_builder.go
+++ b/pulsar/impl/batch_builder.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/buffer.go b/pulsar/impl/buffer.go
index 3f8dcc0..bf92b8f 100644
--- a/pulsar/impl/buffer.go
+++ b/pulsar/impl/buffer.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/buffer_test.go b/pulsar/impl/buffer_test.go
index 1d72196..e6ace40 100644
--- a/pulsar/impl/buffer_test.go
+++ b/pulsar/impl/buffer_test.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/checksum.go b/pulsar/impl/checksum.go
index cbea686..906c4dc 100644
--- a/pulsar/impl/checksum.go
+++ b/pulsar/impl/checksum.go
@@ -1,3 +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 impl
import "hash/crc32"
diff --git a/pulsar/impl/closable.go b/pulsar/impl/closable.go
index c483901..3805556 100644
--- a/pulsar/impl/closable.go
+++ b/pulsar/impl/closable.go
@@ -1,3 +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 impl
type Closable interface {
diff --git a/pulsar/impl/commands.go b/pulsar/impl/commands.go
index 7a55a89..949d56d 100644
--- a/pulsar/impl/commands.go
+++ b/pulsar/impl/commands.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/commands_test.go b/pulsar/impl/commands_test.go
index d9f94e6..a1f08a8 100644
--- a/pulsar/impl/commands_test.go
+++ b/pulsar/impl/commands_test.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/compression/compression.go b/pulsar/impl/compression/compression.go
index 107485b..a4aa652 100644
--- a/pulsar/impl/compression/compression.go
+++ b/pulsar/impl/compression/compression.go
@@ -1,3 +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 compression
type Provider interface {
diff --git a/pulsar/impl/compression/compression_test.go b/pulsar/impl/compression/compression_test.go
index ef57402..b21f0fc 100644
--- a/pulsar/impl/compression/compression_test.go
+++ b/pulsar/impl/compression/compression_test.go
@@ -1,3 +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 compression
import (
diff --git a/pulsar/impl/compression/lz4.go b/pulsar/impl/compression/lz4.go
index cb725dd..da1868c 100644
--- a/pulsar/impl/compression/lz4.go
+++ b/pulsar/impl/compression/lz4.go
@@ -1,3 +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 compression
import (
diff --git a/pulsar/impl/compression/noop.go b/pulsar/impl/compression/noop.go
index 2267d66..533ab2c 100644
--- a/pulsar/impl/compression/noop.go
+++ b/pulsar/impl/compression/noop.go
@@ -1,3 +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 compression
type noopProvider struct {
diff --git a/pulsar/impl/compression/zlib.go b/pulsar/impl/compression/zlib.go
index ea184e6..1646bc5 100644
--- a/pulsar/impl/compression/zlib.go
+++ b/pulsar/impl/compression/zlib.go
@@ -1,3 +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 compression
import (
diff --git a/pulsar/impl/compression/zstd.go b/pulsar/impl/compression/zstd.go
index bf61be8..ffad2bc 100644
--- a/pulsar/impl/compression/zstd.go
+++ b/pulsar/impl/compression/zstd.go
@@ -1,3 +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 compression
import (
diff --git a/pulsar/impl/connection.go b/pulsar/impl/connection.go
index 75ad6e3..aa1c809 100644
--- a/pulsar/impl/connection.go
+++ b/pulsar/impl/connection.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/connection_pool.go b/pulsar/impl/connection_pool.go
index ef5ca8b..474f2f8 100644
--- a/pulsar/impl/connection_pool.go
+++ b/pulsar/impl/connection_pool.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/connection_reader.go b/pulsar/impl/connection_reader.go
index 8277507..fd753d1 100644
--- a/pulsar/impl/connection_reader.go
+++ b/pulsar/impl/connection_reader.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/default_router.go b/pulsar/impl/default_router.go
index 1621ed4..20db625 100644
--- a/pulsar/impl/default_router.go
+++ b/pulsar/impl/default_router.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/default_router_test.go b/pulsar/impl/default_router_test.go
index b3ef841..8cad90d 100644
--- a/pulsar/impl/default_router_test.go
+++ b/pulsar/impl/default_router_test.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/hash.go b/pulsar/impl/hash.go
index bd65da1..61f580b 100644
--- a/pulsar/impl/hash.go
+++ b/pulsar/impl/hash.go
@@ -1,3 +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 impl
import "github.com/spaolacci/murmur3"
diff --git a/pulsar/impl/hash_test.go b/pulsar/impl/hash_test.go
index 76b418a..b4f41d5 100644
--- a/pulsar/impl/hash_test.go
+++ b/pulsar/impl/hash_test.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/lookup_service.go b/pulsar/impl/lookup_service.go
index ce1360e..13c74a7 100644
--- a/pulsar/impl/lookup_service.go
+++ b/pulsar/impl/lookup_service.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/lookup_service_test.go b/pulsar/impl/lookup_service_test.go
index 62f0ea7..a5e8cb0 100644
--- a/pulsar/impl/lookup_service_test.go
+++ b/pulsar/impl/lookup_service_test.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/rpc_client.go b/pulsar/impl/rpc_client.go
index 137d6f0..32be5b6 100644
--- a/pulsar/impl/rpc_client.go
+++ b/pulsar/impl/rpc_client.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/topic_name.go b/pulsar/impl/topic_name.go
index 2bafeb2..7b284ef 100644
--- a/pulsar/impl/topic_name.go
+++ b/pulsar/impl/topic_name.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/topic_name_test.go b/pulsar/impl/topic_name_test.go
index b4d6184..7095edb 100644
--- a/pulsar/impl/topic_name_test.go
+++ b/pulsar/impl/topic_name_test.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl/util/blocking_queue.go b/pulsar/impl/util/blocking_queue.go
index bdf6099..b663302 100644
--- a/pulsar/impl/util/blocking_queue.go
+++ b/pulsar/impl/util/blocking_queue.go
@@ -1,3 +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 util
import (
diff --git a/pulsar/impl/util/blocking_queue_test.go b/pulsar/impl/util/blocking_queue_test.go
index 15cda0c..f8cb3fa 100644
--- a/pulsar/impl/util/blocking_queue_test.go
+++ b/pulsar/impl/util/blocking_queue_test.go
@@ -1,3 +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 util
import (
diff --git a/pulsar/impl/util/semaphore.go b/pulsar/impl/util/semaphore.go
index 9df8cd1..45fa7f4 100644
--- a/pulsar/impl/util/semaphore.go
+++ b/pulsar/impl/util/semaphore.go
@@ -1,3 +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 util
type Semaphore chan bool
diff --git a/pulsar/impl/utils.go b/pulsar/impl/utils.go
index 02d15b3..b9b9b08 100644
--- a/pulsar/impl/utils.go
+++ b/pulsar/impl/utils.go
@@ -1,3 +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 impl
import (
diff --git a/pulsar/impl_client.go b/pulsar/impl_client.go
index f688208..89b955d 100644
--- a/pulsar/impl_client.go
+++ b/pulsar/impl_client.go
@@ -1,3 +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 pulsar
import (
diff --git a/pulsar/impl_client_test.go b/pulsar/impl_client_test.go
index 99f0c78..4542740 100644
--- a/pulsar/impl_client_test.go
+++ b/pulsar/impl_client_test.go
@@ -1,3 +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 pulsar
import (
diff --git a/pulsar/impl_message.go b/pulsar/impl_message.go
index 651bab3..24f3f30 100644
--- a/pulsar/impl_message.go
+++ b/pulsar/impl_message.go
@@ -1,3 +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 pulsar
import (
diff --git a/pulsar/impl_message_test.go b/pulsar/impl_message_test.go
index ea64640..f720c33 100644
--- a/pulsar/impl_message_test.go
+++ b/pulsar/impl_message_test.go
@@ -1,3 +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 pulsar
import (
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index 9e8800c..41e7702 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -1,3 +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 pulsar
import (
diff --git a/pulsar/impl_producer.go b/pulsar/impl_producer.go
index f1b5509..c379531 100644
--- a/pulsar/impl_producer.go
+++ b/pulsar/impl_producer.go
@@ -1,3 +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 pulsar
import (
diff --git a/pulsar/producer_test.go b/pulsar/producer_test.go
index 1408170..318d811 100644
--- a/pulsar/producer_test.go
+++ b/pulsar/producer_test.go
@@ -1,3 +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 pulsar
import (
diff --git a/pulsar/util_test.go b/pulsar/util_test.go
index 4bc67d3..1795e41 100644
--- a/pulsar/util_test.go
+++ b/pulsar/util_test.go
@@ -1,3 +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 pulsar
import (
[pulsar-client-go] 23/38: Completed default message router and tests
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit e7a4aef63b1b89d5b1f2bede6e043362c4788c9f
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Sat May 4 08:24:23 2019 -0700
Completed default message router and tests
---
pulsar/impl/default_router.go | 42 ++++++++++++++++++------
pulsar/impl/default_router_test.go | 66 ++++++++++++++++++++++++++++++++++++++
pulsar/impl_producer.go | 18 +++++++++--
pulsar/producer.go | 22 -------------
4 files changed, 115 insertions(+), 33 deletions(-)
diff --git a/pulsar/impl/default_router.go b/pulsar/impl/default_router.go
index bb5ca73..1621ed4 100644
--- a/pulsar/impl/default_router.go
+++ b/pulsar/impl/default_router.go
@@ -1,26 +1,50 @@
package impl
import (
+ "math/rand"
"time"
)
type defaultRouter struct {
- partitionIdx uint32
+ clock Clock
+ shiftIdx uint32
maxBatchingDelay time.Duration
+ hashFunc func(string) uint32
}
-func NewDefaultRouter(maxBatchingDelay time.Duration) func(uint32) int {
- // TODO: XXX
- //state := &defaultRouter{
- // partitionIdx: rand.Uint32(),
- // maxBatchingDelay: maxBatchingDelay,
- //}
+type Clock func() uint64
- return func(numPartitions uint32) int {
+func NewSystemClock() Clock {
+ return func() uint64 {
+ return uint64(time.Now().UnixNano())
+ }
+}
+
+func NewDefaultRouter(clock Clock, hashFunc func(string) uint32, maxBatchingDelay time.Duration) func(string, uint32) int {
+ state := &defaultRouter{
+ clock: clock,
+ shiftIdx: rand.Uint32(),
+ maxBatchingDelay: maxBatchingDelay,
+ hashFunc: hashFunc,
+ }
+
+ return func(key string, numPartitions uint32) int {
if numPartitions == 1 {
+ // When there are no partitions, don't even bother
return 0
}
- return -1
+ if key != "" {
+ // When a key is specified, use the hash of that key
+ return int(state.hashFunc(key) % numPartitions)
+ }
+
+ // If there's no key, we do round-robin across partition, sticking with a given
+ // partition for a certain amount of time, to ensure we can have a decent amount
+ // of batching of the messages.
+ //
+ //currentMs / maxBatchingDelayMs + startPtnIdx
+ n := uint32(state.clock()/uint64(maxBatchingDelay.Nanoseconds())) + state.shiftIdx
+ return int(n % numPartitions)
}
}
diff --git a/pulsar/impl/default_router_test.go b/pulsar/impl/default_router_test.go
new file mode 100644
index 0000000..b3ef841
--- /dev/null
+++ b/pulsar/impl/default_router_test.go
@@ -0,0 +1,66 @@
+package impl
+
+import (
+ "github.com/stretchr/testify/assert"
+ "testing"
+ "time"
+)
+
+
+func TestDefaultRouter(t *testing.T) {
+
+ var currentClock uint64
+
+ router := NewDefaultRouter(func() uint64 {
+ return currentClock
+ }, JavaStringHash, 10*time.Nanosecond)
+
+ // partition index should not change with time
+ p1 := router("my-key", 100)
+ p2 := router("my-key", 100)
+
+ assert.Equal(t, p1, p2)
+
+ currentClock = 100
+ p3 := router("my-key", 100)
+
+ assert.Equal(t, p1, p3)
+
+ // With no key, we should give the same partition for a given time range
+ pr1 := router("", 100)
+ pr2 := router("", 100)
+ assert.Equal(t, pr1, pr2)
+
+ currentClock = 101
+ pr3 := router("", 100)
+ assert.Equal(t, pr1, pr3)
+
+ currentClock = 102
+ pr4 := router("", 100)
+ assert.Equal(t, pr1, pr4)
+
+ currentClock = 111
+ pr5 := router("", 100)
+ assert.NotEqual(t, pr1, pr5)
+
+ currentClock = 112
+ pr6 := router("", 100)
+ assert.Equal(t, pr5, pr6)
+}
+
+func TestDefaultRouterNoPartitions(t *testing.T) {
+
+ router := NewDefaultRouter(NewSystemClock(), JavaStringHash, 10*time.Nanosecond)
+
+ // partition index should not change with time
+ p1 := router("", 1)
+ p2 := router("my-key", 1)
+ p3 := router("my-key-2", 1)
+ p4 := router("my-key-3", 1)
+
+ assert.Equal(t, 0, p1)
+ assert.Equal(t, 0, p2)
+ assert.Equal(t, 0, p3)
+ assert.Equal(t, 0, p4)
+}
+
diff --git a/pulsar/impl_producer.go b/pulsar/impl_producer.go
index abedfab..12e5e7c 100644
--- a/pulsar/impl_producer.go
+++ b/pulsar/impl_producer.go
@@ -11,6 +11,17 @@ type producer struct {
messageRouter func(*ProducerMessage, TopicMetadata) int
}
+func getHashingFunction(s HashingScheme) func(string) uint32 {
+ switch s {
+ case JavaStringHash:
+ return impl.JavaStringHash
+ case Murmur3_32Hash:
+ return impl.Murmur3_32Hash
+ default:
+ return impl.JavaStringHash
+ }
+}
+
func newProducer(client *client, options *ProducerOptions) (*producer, error) {
if options.Topic == "" {
return nil, newError(ResultInvalidTopicName, "Topic name is required for producer")
@@ -21,9 +32,12 @@ func newProducer(client *client, options *ProducerOptions) (*producer, error) {
}
if options.MessageRouter == nil {
- internalRouter := impl.NewDefaultRouter(options.BatchingMaxPublishDelay)
+ internalRouter := impl.NewDefaultRouter(
+ impl.NewSystemClock(),
+ getHashingFunction(options.HashingScheme),
+ options.BatchingMaxPublishDelay)
p.messageRouter = func(message *ProducerMessage, metadata TopicMetadata) int {
- return internalRouter(metadata.NumPartitions())
+ return internalRouter(message.Key, metadata.NumPartitions())
}
}
diff --git a/pulsar/producer.go b/pulsar/producer.go
index 8eaf340..2a248cb 100644
--- a/pulsar/producer.go
+++ b/pulsar/producer.go
@@ -24,25 +24,11 @@ import (
"time"
)
-type MessageRoutingMode int
-
-const (
- // Publish messages across all partitions in round-robin.
- RoundRobinDistribution MessageRoutingMode = iota
-
- // The producer will chose one single partition and publish all the messages into that partition
- UseSinglePartition
-
- // Use custom message router implementation that will be called to determine the partition for a particular message.
- CustomPartition
-)
-
type HashingScheme int
const (
JavaStringHash HashingScheme = iota // Java String.hashCode() equivalent
Murmur3_32Hash // Use Murmur3 hashing function
- BoostHash // C++ based boost::hash
)
type CompressionType int
@@ -97,20 +83,12 @@ type ProducerOptions struct {
// `ProducerQueueIsFullError` when there is no space left in pending queue.
BlockIfQueueFull bool
- // Set the message routing mode for the partitioned producer.
- // Default routing mode is round-robin routing.
- //
- // This logic is applied when the application is not setting a key ProducerMessage#setKey(String) on a
- // particular message.
- MessageRoutingMode
-
// Change the `HashingScheme` used to chose the partition on where to publish a particular message.
// Standard hashing functions available are:
//
// - `JavaStringHash` : Java String.hashCode() equivalent
// - `Murmur3_32Hash` : Use Murmur3 hashing function.
// https://en.wikipedia.org/wiki/MurmurHash">https://en.wikipedia.org/wiki/MurmurHash
- // - `BoostHash` : C++ based boost::hash
//
// Default is `JavaStringHash`.
HashingScheme
[pulsar-client-go] 38/38: Merge pull request #1 from merlimat/master
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 9c5d5098536baeae117b005fafe5606d4037efa8
Merge: d74beea e058b84
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Tue May 14 09:33:33 2019 -0700
Merge pull request #1 from merlimat/master
Initial client library submission
.gitignore | 1 +
Dockerfile | 34 +
LICENSE | 305 ++
NOTICE | 6 +
README.md | 60 +
integration-tests/certs/broker-cert.pem | 73 +
integration-tests/certs/broker-key.pem | 28 +
integration-tests/certs/cacert.pem | 62 +
integration-tests/certs/client-cert.pem | 73 +
integration-tests/certs/client-key.pem | 28 +
integration-tests/client.conf | 27 +
integration-tests/standalone.conf | 280 ++
integration-tests/tokens/secret.key | 1 +
integration-tests/tokens/token.txt | 1 +
perf/perf-consumer.go | 113 +
perf/perf-producer.go | 147 +
perf/pulsar-perf-go.go | 49 +
pulsar-test-service-start.sh | 79 +
pulsar-test-service-stop.sh | 35 +
pulsar/client.go | 113 +
pulsar/consumer.go | 179 +
pulsar/error.go | 103 +
pulsar/impl_client.go | 152 +
pulsar/impl_client_test.go | 203 ++
pulsar/impl_message.go | 78 +
pulsar/impl_message_test.go | 48 +
pulsar/impl_partition_producer.go | 427 +++
pulsar/impl_producer.go | 156 +
pulsar/internal/auth/disabled.go | 49 +
pulsar/internal/auth/provider.go | 63 +
pulsar/internal/auth/tls.go | 64 +
pulsar/internal/auth/token.go | 98 +
pulsar/internal/backoff.go | 45 +
pulsar/internal/batch_builder.go | 166 +
pulsar/internal/buffer.go | 193 ++
pulsar/internal/buffer_test.go | 38 +
pulsar/internal/checksum.go | 28 +
pulsar/internal/closable.go | 24 +
pulsar/internal/commands.go | 141 +
pulsar/internal/commands_test.go | 45 +
pulsar/internal/compression/compression.go | 33 +
pulsar/internal/compression/compression_test.go | 71 +
pulsar/internal/compression/lz4.go | 47 +
pulsar/internal/compression/noop.go | 35 +
pulsar/internal/compression/zlib.go | 54 +
pulsar/internal/compression/zstd.go | 39 +
pulsar/internal/connection.go | 484 +++
pulsar/internal/connection_pool.go | 85 +
pulsar/internal/connection_reader.go | 136 +
pulsar/internal/default_router.go | 69 +
pulsar/internal/default_router_test.go | 85 +
pulsar/internal/hash.go | 38 +
pulsar/internal/hash_test.go | 59 +
pulsar/internal/lookup_service.go | 132 +
pulsar/internal/lookup_service_test.go | 268 ++
pulsar/internal/pulsar_proto/PulsarApi.pb.go | 4043 +++++++++++++++++++++++
pulsar/internal/rpc_client.go | 124 +
pulsar/internal/topic_name.go | 107 +
pulsar/internal/topic_name_test.go | 87 +
pulsar/internal/util/blocking_queue.go | 203 ++
pulsar/internal/util/blocking_queue_test.go | 137 +
pulsar/internal/util/semaphore.go | 30 +
pulsar/internal/utils.go | 39 +
pulsar/message.go | 88 +
pulsar/producer.go | 167 +
pulsar/producer_test.go | 181 +
pulsar/reader.go | 84 +
pulsar/test_helper.go | 43 +
68 files changed, 10783 insertions(+)
[pulsar-client-go] 21/38: Producer last sequence id
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit b2c9d8ca7c069e68cdb931e08ce211fba881ed0d
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Fri May 3 16:07:44 2019 -0700
Producer last sequence id
---
pulsar/impl_partition_producer.go | 7 +++++--
pulsar/producer_test.go | 31 +++++++++++++++++++++++++++++++
2 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index b87384d..7b32fdc 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -8,6 +8,7 @@ import (
"pulsar-client-go-native/pulsar/impl/util"
pb "pulsar-client-go-native/pulsar/pulsar_proto"
"sync"
+ "sync/atomic"
"time"
)
@@ -39,6 +40,7 @@ type partitionProducer struct {
publishSemaphore util.Semaphore
pendingQueue util.BlockingQueue
+ lastSequenceID int64
}
const defaultBatchingMaxPublishDelay = 10 * time.Millisecond
@@ -70,6 +72,7 @@ func newPartitionProducer(client *client, topic string, options *ProducerOptions
batchFlushTicker: time.NewTicker(batchingMaxPublishDelay),
publishSemaphore: make(util.Semaphore, maxPendingMessages),
pendingQueue: util.NewBlockingQueue(maxPendingMessages),
+ lastSequenceID: -1,
}
if options.Name != "" {
@@ -313,6 +316,7 @@ func (p *partitionProducer) ReceivedSendReceipt(response *pb.CommandSendReceipt)
p.publishSemaphore.Release()
for _, i := range pi.sendRequests {
sr := i.(*sendRequest)
+ atomic.StoreInt64(&p.lastSequenceID, int64(pi.sequenceId))
if sr.callback != nil {
sr.callback(nil, sr.msg, nil)
}
@@ -347,8 +351,7 @@ func (p *partitionProducer) internalClose(req *closeProducer) {
}
func (p *partitionProducer) LastSequenceID() int64 {
- // TODO: return real last sequence id
- return -1
+ return atomic.LoadInt64(&p.lastSequenceID)
}
func (p *partitionProducer) Flush() error {
diff --git a/pulsar/producer_test.go b/pulsar/producer_test.go
index ab3d739..fa197b4 100644
--- a/pulsar/producer_test.go
+++ b/pulsar/producer_test.go
@@ -78,3 +78,34 @@ func TestProducerCompression(t *testing.T) {
})
}
}
+
+func TestProducerLastSequenceID(t *testing.T) {
+ client, err := NewClient(ClientOptions{
+ URL: serviceUrl,
+ })
+ assert.NoError(t, err)
+
+ producer, err := client.CreateProducer(ProducerOptions{
+ Topic: newTopicName(),
+ })
+
+ assert.NoError(t, err)
+ assert.NotNil(t, producer)
+
+ assert.Equal(t, int64(-1), producer.LastSequenceID())
+
+ for i := 0; i < 10; i++ {
+ err := producer.Send(context.Background(), &ProducerMessage{
+ Payload: []byte("hello"),
+ })
+
+ assert.NoError(t, err)
+ assert.Equal(t, int64(i), producer.LastSequenceID())
+ }
+
+ err = producer.Close()
+ assert.NoError(t, err)
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
\ No newline at end of file
[pulsar-client-go] 29/38: Renamed to pulsar-client-go
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit dfd7550791033554fd5f2d3f55ccc2fb76749756
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Sun May 5 16:36:29 2019 -0700
Renamed to pulsar-client-go
---
perf/perf-consumer.go | 2 +-
perf/perf-producer.go | 2 +-
pulsar/impl/batch_builder.go | 4 ++--
pulsar/impl/commands.go | 2 +-
pulsar/impl/connection.go | 2 +-
pulsar/impl/connection_reader.go | 2 +-
pulsar/impl/lookup_service.go | 2 +-
pulsar/impl/lookup_service_test.go | 2 +-
pulsar/impl/rpc_client.go | 2 +-
pulsar/impl_client.go | 4 ++--
pulsar/impl_message.go | 2 +-
pulsar/impl_partition_producer.go | 6 +++---
pulsar/impl_producer.go | 2 +-
pulsar/producer_test.go | 2 +-
14 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/perf/perf-consumer.go b/perf/perf-consumer.go
index e6fdf77..ee315ba 100644
--- a/perf/perf-consumer.go
+++ b/perf/perf-consumer.go
@@ -22,7 +22,7 @@ package main
import (
"context"
"encoding/json"
- "pulsar-client-go-native/pulsar"
+ "pulsar-client-go/pulsar"
"github.com/spf13/cobra"
log "github.com/sirupsen/logrus"
"sync/atomic"
diff --git a/perf/perf-producer.go b/perf/perf-producer.go
index c40af30..e8fd76f 100644
--- a/perf/perf-producer.go
+++ b/perf/perf-producer.go
@@ -26,7 +26,7 @@ import (
"github.com/bmizerany/perks/quantile"
"github.com/spf13/cobra"
log "github.com/sirupsen/logrus"
- "pulsar-client-go-native/pulsar"
+ "pulsar-client-go/pulsar"
"time"
)
diff --git a/pulsar/impl/batch_builder.go b/pulsar/impl/batch_builder.go
index 0619154..6675d8d 100644
--- a/pulsar/impl/batch_builder.go
+++ b/pulsar/impl/batch_builder.go
@@ -3,8 +3,8 @@ package impl
import (
"github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
- "pulsar-client-go-native/pulsar/impl/compression"
- pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ "pulsar-client-go/pulsar/impl/compression"
+ pb "pulsar-client-go/pulsar/pulsar_proto"
"time"
)
diff --git a/pulsar/impl/commands.go b/pulsar/impl/commands.go
index c2db791..7a55a89 100644
--- a/pulsar/impl/commands.go
+++ b/pulsar/impl/commands.go
@@ -3,7 +3,7 @@ package impl
import (
"github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
- pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/pulsar_proto"
)
const MaxFrameSize = 5 * 1024 * 1024
diff --git a/pulsar/impl/connection.go b/pulsar/impl/connection.go
index 580a821..75ad6e3 100644
--- a/pulsar/impl/connection.go
+++ b/pulsar/impl/connection.go
@@ -6,7 +6,7 @@ import (
log "github.com/sirupsen/logrus"
"net"
"net/url"
- pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/pulsar_proto"
"sync"
"sync/atomic"
"time"
diff --git a/pulsar/impl/connection_reader.go b/pulsar/impl/connection_reader.go
index 3b45dc4..8277507 100644
--- a/pulsar/impl/connection_reader.go
+++ b/pulsar/impl/connection_reader.go
@@ -5,7 +5,7 @@ import (
"github.com/golang/protobuf/proto"
"github.com/pkg/errors"
"io"
- pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/pulsar_proto"
)
type connectionReader struct {
diff --git a/pulsar/impl/lookup_service.go b/pulsar/impl/lookup_service.go
index 3dfe758..ce1360e 100644
--- a/pulsar/impl/lookup_service.go
+++ b/pulsar/impl/lookup_service.go
@@ -6,7 +6,7 @@ import (
"github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
"net/url"
- pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/pulsar_proto"
)
type LookupResult struct {
diff --git a/pulsar/impl/lookup_service_test.go b/pulsar/impl/lookup_service_test.go
index 7e18198..62f0ea7 100644
--- a/pulsar/impl/lookup_service_test.go
+++ b/pulsar/impl/lookup_service_test.go
@@ -4,7 +4,7 @@ import (
"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert"
"net/url"
- pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/pulsar_proto"
"testing"
)
diff --git a/pulsar/impl/rpc_client.go b/pulsar/impl/rpc_client.go
index 706b9a1..137d6f0 100644
--- a/pulsar/impl/rpc_client.go
+++ b/pulsar/impl/rpc_client.go
@@ -3,7 +3,7 @@ package impl
import (
"github.com/golang/protobuf/proto"
"net/url"
- pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/pulsar_proto"
"sync"
"sync/atomic"
)
diff --git a/pulsar/impl_client.go b/pulsar/impl_client.go
index a1f6e10..f688208 100644
--- a/pulsar/impl_client.go
+++ b/pulsar/impl_client.go
@@ -4,8 +4,8 @@ import (
"fmt"
log "github.com/sirupsen/logrus"
"net/url"
- "pulsar-client-go-native/pulsar/impl"
- pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ "pulsar-client-go/pulsar/impl"
+ pb "pulsar-client-go/pulsar/pulsar_proto"
)
type client struct {
diff --git a/pulsar/impl_message.go b/pulsar/impl_message.go
index 5d54678..651bab3 100644
--- a/pulsar/impl_message.go
+++ b/pulsar/impl_message.go
@@ -2,7 +2,7 @@ package pulsar
import (
"github.com/golang/protobuf/proto"
- pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ pb "pulsar-client-go/pulsar/pulsar_proto"
)
type messageId struct {
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index 78f14af..9e8800c 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -4,9 +4,9 @@ import (
"context"
"github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
- "pulsar-client-go-native/pulsar/impl"
- "pulsar-client-go-native/pulsar/impl/util"
- pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ "pulsar-client-go/pulsar/impl"
+ "pulsar-client-go/pulsar/impl/util"
+ pb "pulsar-client-go/pulsar/pulsar_proto"
"sync"
"sync/atomic"
"time"
diff --git a/pulsar/impl_producer.go b/pulsar/impl_producer.go
index aec4eb5..f1b5509 100644
--- a/pulsar/impl_producer.go
+++ b/pulsar/impl_producer.go
@@ -2,7 +2,7 @@ package pulsar
import (
"context"
- "pulsar-client-go-native/pulsar/impl"
+ "pulsar-client-go/pulsar/impl"
)
type producer struct {
diff --git a/pulsar/producer_test.go b/pulsar/producer_test.go
index f7455ce..1408170 100644
--- a/pulsar/producer_test.go
+++ b/pulsar/producer_test.go
@@ -4,7 +4,7 @@ import (
"context"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
- "pulsar-client-go-native/pulsar/impl/util"
+ "pulsar-client-go/pulsar/impl/util"
"sync"
"testing"
"time"
[pulsar-client-go] 18/38: Added compression codecs and tests
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit f9fa72736270b99fb95476645d81cc3fd0704993
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Thu Apr 11 17:50:11 2019 -0700
Added compression codecs and tests
---
pulsar/impl/compression/compression.go | 14 ++++++++
pulsar/impl/compression/compression_test.go | 52 +++++++++++++++++++++++++++++
pulsar/impl/compression/lz4.go | 28 ++++++++++++++++
pulsar/impl/compression/noop.go | 16 +++++++++
pulsar/impl/compression/zlib.go | 35 +++++++++++++++++++
pulsar/impl/compression/zstd.go | 20 +++++++++++
6 files changed, 165 insertions(+)
diff --git a/pulsar/impl/compression/compression.go b/pulsar/impl/compression/compression.go
new file mode 100644
index 0000000..107485b
--- /dev/null
+++ b/pulsar/impl/compression/compression.go
@@ -0,0 +1,14 @@
+package compression
+
+type Provider interface {
+ Compress(data []byte) []byte
+
+ Decompress(compressedData []byte, originalSize int) ([]byte, error)
+}
+
+var (
+ NoopProvider = NewNoopProvider()
+ ZLibProvider = NewZLibProvider()
+ Lz4Provider = NewLz4Provider()
+ ZStdProvider = NewZStdProvider()
+)
diff --git a/pulsar/impl/compression/compression_test.go b/pulsar/impl/compression/compression_test.go
new file mode 100644
index 0000000..ef57402
--- /dev/null
+++ b/pulsar/impl/compression/compression_test.go
@@ -0,0 +1,52 @@
+package compression
+
+import (
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+type testProvider struct {
+ name string
+ provider Provider
+
+ // Compressed data for "hello"
+ compressedHello []byte
+}
+
+var providers = []testProvider{
+ {"zlib", ZLibProvider, []byte{0x78, 0x9c, 0xca, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00, 0x00, 0x00, 0xff, 0xff}},
+ {"lz4", Lz4Provider, []byte{0x50, 0x68, 0x65, 0x6c, 0x6c, 0x6f}},
+ {"zstd", ZStdProvider, []byte{0x28, 0xb5, 0x2f, 0xfd, 0x20, 0x05, 0x29, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f}},
+}
+
+func TestCompression(t *testing.T) {
+ for _, p := range providers {
+ t.Run(p.name, func(t *testing.T) {
+ hello := []byte("test compression data")
+ compressed := p.provider.Compress(hello)
+ uncompressed, err := p.provider.Decompress(compressed, len(hello))
+ assert.Nil(t, err)
+ assert.ElementsMatch(t, hello, uncompressed)
+ })
+ }
+}
+
+func TestJavaCompatibility(t *testing.T) {
+ for _, p := range providers {
+ t.Run(p.name, func(t *testing.T) {
+ hello := []byte("hello")
+ uncompressed, err := p.provider.Decompress(p.compressedHello, len(hello))
+ assert.Nil(t, err)
+ assert.ElementsMatch(t, hello, uncompressed)
+ })
+ }
+}
+
+func TestDecompressionError(t *testing.T) {
+ for _, p := range providers {
+ t.Run(p.name, func(t *testing.T) {
+ _, err := p.provider.Decompress([]byte{0x05}, 0)
+ assert.NotNil(t, err)
+ })
+ }
+}
diff --git a/pulsar/impl/compression/lz4.go b/pulsar/impl/compression/lz4.go
new file mode 100644
index 0000000..cb725dd
--- /dev/null
+++ b/pulsar/impl/compression/lz4.go
@@ -0,0 +1,28 @@
+package compression
+
+import (
+ "github.com/cloudflare/golz4"
+)
+
+type lz4Provider struct {
+}
+
+func NewLz4Provider() Provider {
+ return &lz4Provider{}
+}
+
+func (lz4Provider) Compress(data []byte) []byte {
+ maxSize := lz4.CompressBound(data)
+ compressed := make([]byte, maxSize)
+ size, err := lz4.Compress(data, compressed)
+ if err != nil {
+ panic("Failed to compress")
+ }
+ return compressed[:size]
+}
+
+func (lz4Provider) Decompress(compressedData []byte, originalSize int) ([]byte, error) {
+ uncompressed := make([]byte, originalSize)
+ err := lz4.Uncompress(compressedData, uncompressed)
+ return uncompressed, err
+}
diff --git a/pulsar/impl/compression/noop.go b/pulsar/impl/compression/noop.go
new file mode 100644
index 0000000..2267d66
--- /dev/null
+++ b/pulsar/impl/compression/noop.go
@@ -0,0 +1,16 @@
+package compression
+
+type noopProvider struct {
+}
+
+func NewNoopProvider() Provider {
+ return &noopProvider{}
+}
+
+func (noopProvider) Compress(data []byte) []byte {
+ return data
+}
+
+func (noopProvider) Decompress(compressedData []byte, originalSize int) ([]byte, error) {
+ return compressedData, nil
+}
diff --git a/pulsar/impl/compression/zlib.go b/pulsar/impl/compression/zlib.go
new file mode 100644
index 0000000..ea184e6
--- /dev/null
+++ b/pulsar/impl/compression/zlib.go
@@ -0,0 +1,35 @@
+package compression
+
+import (
+ "bytes"
+ "compress/zlib"
+)
+
+type zlibProvider struct {
+}
+
+func NewZLibProvider() Provider {
+ return &zlibProvider{}
+}
+
+func (zlibProvider) Compress(data []byte) []byte {
+ var b bytes.Buffer
+ w := zlib.NewWriter(&b)
+ w.Write(data)
+ w.Close()
+
+ return b.Bytes()
+}
+
+func (zlibProvider) Decompress(compressedData []byte, originalSize int) ([]byte, error) {
+ r, err := zlib.NewReader(bytes.NewBuffer(compressedData))
+ if err != nil {
+ return nil, err
+ }
+
+ uncompressed := make([]byte, originalSize)
+ r.Read(uncompressed)
+ r.Close()
+
+ return uncompressed, nil
+}
diff --git a/pulsar/impl/compression/zstd.go b/pulsar/impl/compression/zstd.go
new file mode 100644
index 0000000..bf61be8
--- /dev/null
+++ b/pulsar/impl/compression/zstd.go
@@ -0,0 +1,20 @@
+package compression
+
+import (
+ zstd "github.com/valyala/gozstd"
+)
+
+type zstdProvider struct {
+}
+
+func NewZStdProvider() Provider {
+ return &zstdProvider{}
+}
+
+func (zstdProvider) Compress(data []byte) []byte {
+ return zstd.Compress(nil, data)
+}
+
+func (zstdProvider) Decompress(compressedData []byte, originalSize int) ([]byte, error) {
+ return zstd.Decompress(nil, compressedData)
+}
[pulsar-client-go] 24/38: Added perf producer/consumer
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 585500e59e10e71ad74bb982e8fab5d0eb216fb8
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Sat May 4 08:32:38 2019 -0700
Added perf producer/consumer
---
perf/perf-consumer.go | 114 +++++++++++++++++++++++++++++++++++++
perf/perf-producer.go | 148 +++++++++++++++++++++++++++++++++++++++++++++++++
perf/pulsar-perf-go.go | 49 ++++++++++++++++
3 files changed, 311 insertions(+)
diff --git a/perf/perf-consumer.go b/perf/perf-consumer.go
new file mode 100644
index 0000000..4ffa36f
--- /dev/null
+++ b/perf/perf-consumer.go
@@ -0,0 +1,114 @@
+//
+// 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 main
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "pulsar-client-go-native/pulsar"
+ "github.com/spf13/cobra"
+ "log"
+ "sync/atomic"
+ "time"
+)
+
+type ConsumeArgs struct {
+ Topic string
+ SubscriptionName string
+ ReceiverQueueSize int
+}
+
+var consumeArgs ConsumeArgs
+
+var cmdConsume = &cobra.Command{
+ Use: "consume <topic>",
+ Short: "Consume from topic",
+ Args: cobra.ExactArgs(1),
+ Run: func(cmd *cobra.Command, args []string) {
+ consumeArgs.Topic = args[0]
+ consume()
+ },
+}
+
+func initConsumer() {
+ cmdConsume.Flags().StringVarP(&consumeArgs.SubscriptionName, "subscription", "s", "sub", "Subscription name")
+ cmdConsume.Flags().IntVarP(&consumeArgs.ReceiverQueueSize, "receiver-queue-size", "r", 1000, "Receiver queue size")
+}
+
+func consume() {
+ b, _ := json.MarshalIndent(clientArgs, "", " ")
+ fmt.Println("Client config: ", string(b))
+ b, _ = json.MarshalIndent(consumeArgs, "", " ")
+ fmt.Println("Consumer config: ", string(b))
+
+ client, err := pulsar.NewClient(pulsar.ClientOptions{
+ URL: clientArgs.ServiceUrl,
+ })
+
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ defer client.Close()
+
+ consumer, err := client.Subscribe(pulsar.ConsumerOptions{
+ Topic: consumeArgs.Topic,
+ SubscriptionName: consumeArgs.SubscriptionName,
+ })
+
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ defer consumer.Close()
+
+ ctx := context.Background()
+
+ var msgReceived int64 = 0
+ var bytesReceived int64 = 0
+
+ go func() {
+ for {
+ msg, _ := consumer.Receive(ctx)
+
+ atomic.AddInt64(&msgReceived, 1)
+ atomic.AddInt64(&bytesReceived, int64(len(msg.Payload())))
+
+ consumer.Ack(msg)
+ }
+ }()
+
+ // Print stats of the consume rate
+ tick := time.NewTicker(10 * time.Second)
+
+ for {
+ select {
+ case <-tick.C:
+ currentMsgReceived := atomic.SwapInt64(&msgReceived, 0)
+ currentBytesReceived := atomic.SwapInt64(&bytesReceived, 0)
+ msgRate := float64(currentMsgReceived) / float64(10)
+ bytesRate := float64(currentBytesReceived) / float64(10)
+
+ log.Printf(`Stats - Consume rate: %6.1f msg/s - %6.1f Mbps`,
+ msgRate, bytesRate*8/1024/1024)
+ }
+ }
+}
\ No newline at end of file
diff --git a/perf/perf-producer.go b/perf/perf-producer.go
new file mode 100644
index 0000000..8b5c0fd
--- /dev/null
+++ b/perf/perf-producer.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 main
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "github.com/beefsack/go-rate"
+ "github.com/bmizerany/perks/quantile"
+ "github.com/spf13/cobra"
+ "log"
+ "pulsar-client-go-native/pulsar"
+ "time"
+)
+
+type ProduceArgs struct {
+ Topic string
+ Rate int
+ Batching bool
+ MessageSize int
+ ProducerQueueSize int
+}
+
+var produceArgs ProduceArgs
+
+var cmdProduce = &cobra.Command{
+ Use: "produce ",
+ Short: "Produce on a topic and measure performance",
+ Args: cobra.ExactArgs(1),
+ Run: func(cmd *cobra.Command, args []string) {
+ produceArgs.Topic = args[0]
+ produce()
+ },
+}
+
+func initProducer() {
+ cmdProduce.Flags().IntVarP(&produceArgs.Rate, "rate", "r", 100, "Publish rate. Set to 0 to go unthrottled")
+ cmdProduce.Flags().BoolVarP(&produceArgs.Batching, "batching", "b", true, "Enable batching")
+ cmdProduce.Flags().IntVarP(&produceArgs.MessageSize, "size", "s", 1024, "Message size")
+ cmdProduce.Flags().IntVarP(&produceArgs.ProducerQueueSize, "queue-size", "q", 1000, "Produce queue size")
+}
+
+func produce() {
+ b, _ := json.MarshalIndent(clientArgs, "", " ")
+ fmt.Println("Client config: ", string(b))
+ b, _ = json.MarshalIndent(produceArgs, "", " ")
+ fmt.Println("Producer config: ", string(b))
+
+ client, err := pulsar.NewClient(pulsar.ClientOptions{
+ URL: clientArgs.ServiceUrl,
+ })
+
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ defer client.Close()
+
+ producer, err := client.CreateProducer(pulsar.ProducerOptions{
+ Topic: produceArgs.Topic,
+ MaxPendingMessages: produceArgs.ProducerQueueSize,
+ BatchingMaxPublishDelay: 1 * time.Millisecond,
+ SendTimeout: 0,
+ BlockIfQueueFull: true,
+ })
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ defer producer.Close()
+
+ ctx := context.Background()
+
+ payload := make([]byte, produceArgs.MessageSize)
+
+ ch := make(chan float64)
+
+ go func() {
+ var rateLimiter *rate.RateLimiter = nil
+ if produceArgs.Rate > 0 {
+ rateLimiter = rate.New(produceArgs.Rate, time.Second)
+ }
+
+ for {
+ if rateLimiter != nil {
+ rateLimiter.Wait()
+ }
+
+ start := time.Now()
+
+ producer.SendAsync(ctx, &pulsar.ProducerMessage{
+ Payload: payload,
+ }, func(msgID pulsar.MessageID, message *pulsar.ProducerMessage, e error) {
+ if e != nil {
+ log.Fatal("Failed to publish", e)
+ }
+
+ latency := time.Since(start).Seconds()
+ ch <- latency
+ })
+ }
+ }()
+
+ // Print stats of the publish rate and latencies
+ tick := time.NewTicker(10 * time.Second)
+ q := quantile.NewTargeted(0.90, 0.95, 0.99, 0.999, 1.0)
+ messagesPublished := 0
+
+ for {
+ select {
+ case <-tick.C:
+ messageRate := float64(messagesPublished) / float64(10)
+ log.Printf(`Stats - Publish rate: %6.1f msg/s - %6.1f Mbps - Latency ms: 50%% %5.1f - 95%% %5.1f - 99%% %5.1f - 99.9%% %5.1f - max %6.1f`,
+ messageRate,
+ messageRate*float64(produceArgs.MessageSize)/1024/1024*8,
+ q.Query(0.5)*1000,
+ q.Query(0.95)*1000,
+ q.Query(0.99)*1000,
+ q.Query(0.999)*1000,
+ q.Query(1.0)*1000,
+ )
+
+ q.Reset()
+ messagesPublished = 0
+ case latency := <-ch:
+ messagesPublished += 1
+ q.Insert(latency)
+ }
+ }
+}
diff --git a/perf/pulsar-perf-go.go b/perf/pulsar-perf-go.go
new file mode 100644
index 0000000..7a6d101
--- /dev/null
+++ b/perf/pulsar-perf-go.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 main
+
+import (
+ "github.com/spf13/cobra"
+ log "github.com/sirupsen/logrus"
+)
+
+type ClientArgs struct {
+ ServiceUrl string
+}
+
+var clientArgs ClientArgs
+
+func main() {
+ log.SetFormatter(&log.TextFormatter{
+ FullTimestamp: true,
+ TimestampFormat: "15:04:05.000",
+ })
+ log.SetLevel(log.InfoLevel)
+
+ initProducer()
+ initConsumer()
+
+ var rootCmd = &cobra.Command{Use: "pulsar-perf-go"}
+ rootCmd.Flags().StringVarP(&clientArgs.ServiceUrl, "service-url", "u",
+ "pulsar://localhost:6650", "The Pulsar service URL")
+ rootCmd.AddCommand(cmdProduce, cmdConsume)
+
+ rootCmd.Execute()
+}
[pulsar-client-go] 03/38: Use string for result errors
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 0c2da14b1242290507109a1be7f5b1149aea26a5
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Thu Mar 28 09:21:42 2019 -0700
Use string for result errors
---
pulsar/client.go | 2 +-
pulsar/error.go | 94 ++++++++++++++++++++++++---------------
pulsar/impl_client.go | 21 +++++----
pulsar/impl_client_test.go | 14 ++++++
pulsar/impl_partition_producer.go | 42 ++++++++---------
pulsar/impl_producer.go | 8 ++--
pulsar/message.go | 8 ++--
7 files changed, 117 insertions(+), 72 deletions(-)
diff --git a/pulsar/client.go b/pulsar/client.go
index 21db637..e68f09c 100644
--- a/pulsar/client.go
+++ b/pulsar/client.go
@@ -28,7 +28,7 @@ func NewClient(options ClientOptions) (Client, error) {
}
// Opaque interface that represents the authentication credentials
-type Authentication interface {}
+type Authentication interface{}
// Create new Authentication provider with specified auth token
func NewAuthenticationToken(token string) Authentication {
diff --git a/pulsar/error.go b/pulsar/error.go
index 929b250..24e1536 100644
--- a/pulsar/error.go
+++ b/pulsar/error.go
@@ -18,45 +18,48 @@
//
package pulsar
+
import "C"
import "fmt"
type Result int
const (
- UnknownError Result = 1 // Unknown error happened on broker
- InvalidConfiguration Result = 2 // Invalid configuration
- TimeoutError Result = 3 // Operation timed out
- LookupError Result = 4 // Broker lookup failed
- ConnectError Result = 5 // Failed to connect to broker
- ReadError Result = 6 // Failed to read from socket
- AuthenticationError Result = 7 // Authentication failed on broker
- AuthorizationError Result = 8 // Client is not authorized to create producer/consumer
- ErrorGettingAuthenticationData Result = 9 // Client cannot find authorization data
- BrokerMetadataError Result = 10 // Broker failed in updating metadata
- BrokerPersistenceError Result = 11 // Broker failed to persist entry
- ChecksumError Result = 12 // Corrupt message checksum failure
- ConsumerBusy Result = 13 // Exclusive consumer is already connected
- NotConnectedError Result = 14 // Producer/Consumer is not currently connected to broker
- AlreadyClosedError Result = 15 // Producer/Consumer is already closed and not accepting any operation
- InvalidMessage Result = 16 // Error in publishing an already used message
- ConsumerNotInitialized Result = 17 // Consumer is not initialized
- ProducerNotInitialized Result = 18 // Producer is not initialized
- TooManyLookupRequestException Result = 19 // Too Many concurrent LookupRequest
- InvalidTopicName Result = 20 // Invalid topic name
- InvalidUrl Result = 21 // Client Initialized with Invalid Broker Url (VIP Url passed to Client Constructor)
- ServiceUnitNotReady Result = 22 // Service Unit unloaded between client did lookup and producer/consumer got created
- OperationNotSupported Result = 23
- ProducerBlockedQuotaExceededError Result = 24 // Producer is blocked
- ProducerBlockedQuotaExceededException Result = 25 // Producer is getting exception
- ProducerQueueIsFull Result = 26 // Producer queue is full
- MessageTooBig Result = 27 // Trying to send a messages exceeding the max size
- TopicNotFound Result = 28 // Topic not found
- SubscriptionNotFound Result = 29 // Subscription not found
- ConsumerNotFound Result = 30 // Consumer not found
- UnsupportedVersionError Result = 31 // Error when an older client/version doesn't support a required feature
- TopicTerminated Result = 32 // Topic was already terminated
- CryptoError Result = 33 // Error when crypto operation fails
+ ResultOk = iota // No errors
+ ResultUnknownError // Unknown error happened on broker
+ ResultInvalidConfiguration // Invalid configuration
+ ResultTimeoutError // Operation timed out
+ ResultLookupError // Broker lookup failed
+ ResultInvalidTopicName // Invalid topic name
+ ResultConnectError // Failed to connect to broker
+
+ //ReadError Result = 6 // Failed to read from socket
+ //AuthenticationError Result = 7 // Authentication failed on broker
+ //AuthorizationError Result = 8 // Client is not authorized to create producer/consumer
+ //ErrorGettingAuthenticationData Result = 9 // Client cannot find authorization data
+ //BrokerMetadataError Result = 10 // Broker failed in updating metadata
+ //BrokerPersistenceError Result = 11 // Broker failed to persist entry
+ //ChecksumError Result = 12 // Corrupt message checksum failure
+ //ConsumerBusy Result = 13 // Exclusive consumer is already connected
+ //NotConnectedError Result = 14 // Producer/Consumer is not currently connected to broker
+ //AlreadyClosedError Result = 15 // Producer/Consumer is already closed and not accepting any operation
+ //InvalidMessage Result = 16 // Error in publishing an already used message
+ //ConsumerNotInitialized Result = 17 // Consumer is not initialized
+ //ProducerNotInitialized Result = 18 // Producer is not initialized
+ //TooManyLookupRequestException Result = 19 // Too Many concurrent LookupRequest
+ //InvalidUrl Result = 21 // Client Initialized with Invalid Broker Url (VIP Url passed to Client Constructor)
+ //ServiceUnitNotReady Result = 22 // Service Unit unloaded between client did lookup and producer/consumer got created
+ //OperationNotSupported Result = 23
+ //ProducerBlockedQuotaExceededError Result = 24 // Producer is blocked
+ //ProducerBlockedQuotaExceededException Result = 25 // Producer is getting exception
+ //ProducerQueueIsFull Result = 26 // Producer queue is full
+ //MessageTooBig Result = 27 // Trying to send a messages exceeding the max size
+ //TopicNotFound Result = 28 // Topic not found
+ //SubscriptionNotFound Result = 29 // Subscription not found
+ //ConsumerNotFound Result = 30 // Consumer not found
+ //UnsupportedVersionError Result = 31 // Error when an older client/version doesn't support a required feature
+ //TopicTerminated Result = 32 // Topic was already terminated
+ //CryptoError Result = 33 // Error when crypto operation fails
)
type Error struct {
@@ -74,7 +77,28 @@ func (e *Error) Error() string {
func newError(result Result, msg string) error {
return &Error{
- msg: fmt.Sprintf("%s: %d", msg, result),
+ msg: fmt.Sprintf("%s: %s", msg, getResultStr(result)),
result: result,
}
-}
\ No newline at end of file
+}
+
+func getResultStr(r Result) string {
+ switch r {
+ case ResultOk:
+ return "OK"
+ case ResultUnknownError:
+ return "Unknown error"
+ case ResultInvalidConfiguration:
+ return "InvalidConfiguration"
+ case ResultTimeoutError:
+ return "TimeoutError"
+ case ResultLookupError:
+ return "LookupError"
+ case ResultInvalidTopicName:
+ return "InvalidTopicName"
+ case ResultConnectError:
+ return "ConnectError"
+ default:
+ return fmt.Sprintf("Result(%d)", r)
+ }
+}
diff --git a/pulsar/impl_client.go b/pulsar/impl_client.go
index e143601..4a7047f 100644
--- a/pulsar/impl_client.go
+++ b/pulsar/impl_client.go
@@ -20,17 +20,17 @@ type client struct {
func newClient(options ClientOptions) (Client, error) {
if options.URL == "" {
- return nil, newError(InvalidConfiguration, "URL is required for client")
+ return nil, newError(ResultInvalidConfiguration, "URL is required for client")
}
url, err := url.Parse(options.URL)
if err != nil {
log.WithError(err).Error("Failed to parse service URL")
- return nil, newError(InvalidConfiguration, "Invalid service URL")
+ return nil, newError(ResultInvalidConfiguration, "Invalid service URL")
}
if url.Scheme != "pulsar" {
- return nil, newError(InvalidConfiguration, fmt.Sprintf("Invalid URL scheme '%s'", url.Scheme))
+ return nil, newError(ResultInvalidConfiguration, fmt.Sprintf("Invalid URL scheme '%s'", url.Scheme))
}
c := &client{
@@ -77,14 +77,19 @@ func (client *client) TopicPartitions(topic string) ([]string, error) {
r := res.Response.PartitionMetadataResponse
if r.Error != nil {
- return nil, newError(LookupError, r.GetError().String())
+ return nil, newError(ResultLookupError, r.GetError().String())
}
- partitions := make([]string, r.GetPartitions())
- for i := 0; i < int(r.GetPartitions()); i++ {
- partitions[i] = fmt.Sprintf("%s-partition-%d", topic, i)
+ if r.GetPartitions() > 0 {
+ partitions := make([]string, r.GetPartitions())
+ for i := 0; i < int(r.GetPartitions()); i++ {
+ partitions[i] = fmt.Sprintf("%s-partition-%d", topic, i)
+ }
+ return partitions, nil
+ } else {
+ // Non-partitioned topic
+ return []string{topicName.Name}, nil
}
- return partitions, nil
}
func (client *client) Close() error {
diff --git a/pulsar/impl_client_test.go b/pulsar/impl_client_test.go
new file mode 100644
index 0000000..99f0c78
--- /dev/null
+++ b/pulsar/impl_client_test.go
@@ -0,0 +1,14 @@
+package pulsar
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestClient(t *testing.T) {
+ client, err := NewClient(ClientOptions{})
+ assert.Nil(t, client)
+ assert.NotNil(t, err)
+ assert.Equal(t, Result(ResultInvalidConfiguration), err.(*Error).Result())
+}
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index bb96a27..d035ad1 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -3,8 +3,8 @@ package pulsar
import (
"context"
log "github.com/sirupsen/logrus"
- "pulsar-client-go-native/pulsar/impl"
- pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ //"pulsar-client-go-native/pulsar/impl"
+ //pb "pulsar-client-go-native/pulsar/pulsar_proto"
"sync"
)
@@ -33,25 +33,25 @@ func newPartitionProducer(client *client, topic string, options *ProducerOptions
}
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
- }
-
- id := p.client.rpcClient.NewRequestId()
- p.client.rpcClient.Request(lr.LogicalAddr.Host, lr.PhysicalAddr.Host, id, pb.BaseCommand_PRODUCER, *pb.CommandProducer{
-
- })
-
- var cnx impl.Connection
- cnx, err = p.client.cnxPool.GetConnection(lr.LogicalAddr.Host, lr.PhysicalAddr.Host)
- if err != nil {
- p.log.WithError(err).Warn("Failed to get connection")
- return err
- }
-
- cnx.
+ //lr, err := p.client.lookupService.Lookup(p.topic)
+ //if err != nil {
+ // p.log.WithError(err).Warn("Failed to lookup topic")
+ // return err
+ //}
+
+ //id := p.client.rpcClient.NewRequestId()
+ //p.client.rpcClient.Request(lr.LogicalAddr.Host, lr.PhysicalAddr.Host, id, pb.BaseCommand_PRODUCER, *pb.CommandProducer{
+ //
+ //})
+ //
+ //var cnx impl.Connection
+ //cnx, err = p.client.cnxPool.GetConnection(lr.LogicalAddr.Host, lr.PhysicalAddr.Host)
+ //if err != nil {
+ // p.log.WithError(err).Warn("Failed to get connection")
+ // return err
+ //}
+
+ //cnx.
return nil
}
diff --git a/pulsar/impl_producer.go b/pulsar/impl_producer.go
index f2332ea..587b09d 100644
--- a/pulsar/impl_producer.go
+++ b/pulsar/impl_producer.go
@@ -2,6 +2,7 @@ package pulsar
import (
"context"
+ "fmt"
"pulsar-client-go-native/pulsar/impl"
"sync"
)
@@ -14,7 +15,7 @@ type producer struct {
func newProducer(client *client, options ProducerOptions) (*producer, error) {
if options.Topic == "" {
- return nil, newError(InvalidTopicName, "Topic name is required for producer")
+ return nil, newError(ResultInvalidTopicName, "Topic name is required for producer")
}
p := &producer{
@@ -47,7 +48,8 @@ func newProducer(client *client, options ProducerOptions) (*producer, error) {
for i := 0; i < numPartitions; i++ {
partition := i
go func() {
- prod, err := newPartitionProducer(client, &options)
+ partitionName := fmt.Sprintf("%s-partition-%d", options.Topic, partition)
+ prod, err := newPartitionProducer(client, partitionName, &options)
c <- ProducerError{partition, prod, err}
}()
}
@@ -62,7 +64,7 @@ func newProducer(client *client, options ProducerOptions) (*producer, error) {
// 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()
+ _ = producer.Close()
}
}
return nil, err
diff --git a/pulsar/message.go b/pulsar/message.go
index b829b96..ad61704 100644
--- a/pulsar/message.go
+++ b/pulsar/message.go
@@ -82,9 +82,9 @@ func DeserializeMessageID(data []byte) MessageID {
}
var (
- // MessageID that points to the earliest message avaialable in a topic
- //EarliestMessage MessageID = earliestMessageID()
+// MessageID that points to the earliest message avaialable in a topic
+//EarliestMessage MessageID = earliestMessageID()
- // MessageID that points to the latest message
- //LatestMessage MessageID = latestMessageID()
+// MessageID that points to the latest message
+//LatestMessage MessageID = latestMessageID()
)
[pulsar-client-go] 37/38: Added token auth provider
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit e058b846ceb683d06a0793fc8af0873705b35d68
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Wed May 8 18:13:09 2019 -0700
Added token auth provider
---
Dockerfile | 9 +---
integration-tests/tokens/secret.key | 1 +
integration-tests/tokens/token.txt | 1 +
pulsar/client.go | 10 ++--
pulsar/impl_client.go | 28 -----------
pulsar/impl_client_test.go | 42 +++++++++++++++-
pulsar/internal/auth/provider.go | 3 ++
pulsar/internal/auth/token.go | 98 +++++++++++++++++++++++++++++++++++++
pulsar/test_helper.go | 3 +-
9 files changed, 151 insertions(+), 44 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index 3451983..1186f96 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -27,15 +27,8 @@ ENV PATH /root/go/bin:/usr/local/go/bin:$PATH
### Add test scripts
COPY integration-tests/certs /pulsar/certs
+COPY integration-tests/tokens /pulsar/tokens
COPY integration-tests/standalone.conf /pulsar/conf
COPY integration-tests/client.conf /pulsar/conf
COPY pulsar-test-service-start.sh /pulsar/bin
COPY pulsar-test-service-stop.sh /pulsar/bin
-
-# Initialize test configuration and credentials
-RUN mkdir /pulsar/tokens
-RUN /pulsar/bin/pulsar tokens create-secret-key --output /pulsar/tokens/secret.key
-RUN /pulsar/bin/pulsar tokens create \
- --subject token-principal \
- --secret-key file:///pulsar/tokens/secret.key \
- > /pulsar/tokens/token.txt
diff --git a/integration-tests/tokens/secret.key b/integration-tests/tokens/secret.key
new file mode 100644
index 0000000..92e05b9
--- /dev/null
+++ b/integration-tests/tokens/secret.key
@@ -0,0 +1 @@
+=Z��kHKX��w<��H�߾V�`}
h�
\ No newline at end of file
diff --git a/integration-tests/tokens/token.txt b/integration-tests/tokens/token.txt
new file mode 100644
index 0000000..b1b8309
--- /dev/null
+++ b/integration-tests/tokens/token.txt
@@ -0,0 +1 @@
+eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0b2tlbi1wcmluY2lwYWwifQ.tSfgR8l7dKC6LoWCxQgNkuSB8our7xV_nAM7wpgCbG4
diff --git a/pulsar/client.go b/pulsar/client.go
index 1a838ac..0225a83 100644
--- a/pulsar/client.go
+++ b/pulsar/client.go
@@ -37,14 +37,12 @@ func NewAuthentication(name string, params string) (Authentication, error) {
// Create new Authentication provider with specified auth token
func NewAuthenticationToken(token string) Authentication {
- // TODO: return newAuthenticationToken(token)
- return nil
+ return auth.NewAuthenticationToken(token)
}
-// Create new Authentication provider with specified auth token supplier
-func NewAuthenticationTokenSupplier(tokenSupplier func() string) Authentication {
- // TODO: return newAuthenticationTokenSupplier(tokenSupplier)
- return nil
+// Create new Authentication provider with specified auth token from a file
+func NewAuthenticationTokenFromFile(tokenFilePath string) Authentication {
+ return auth.NewAuthenticationTokenFromFile(tokenFilePath)
}
// Create new Authentication provider with specified TLS certificate and private key
diff --git a/pulsar/impl_client.go b/pulsar/impl_client.go
index b84ac82..a952efc 100644
--- a/pulsar/impl_client.go
+++ b/pulsar/impl_client.go
@@ -20,12 +20,9 @@
package pulsar
import (
- "crypto/tls"
- "crypto/x509"
"fmt"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
- "io/ioutil"
"net/url"
"pulsar-client-go/pulsar/internal"
"pulsar-client-go/pulsar/internal/auth"
@@ -153,28 +150,3 @@ func (client *client) Close() error {
return nil
}
-
-func getTlsConfig(options ClientOptions) (*tls.Config, error) {
- tlsConfig := &tls.Config{
- InsecureSkipVerify: options.TLSAllowInsecureConnection,
- }
-
- if options.TLSTrustCertsFilePath != "" {
- caCerts, err := ioutil.ReadFile(options.TLSTrustCertsFilePath)
- if err != nil {
- return nil, err
- }
-
- tlsConfig.RootCAs = x509.NewCertPool()
- ok := tlsConfig.RootCAs.AppendCertsFromPEM([]byte(caCerts))
- if !ok {
- return nil, errors.New("failed to parse root CAs certificates")
- }
- }
-
- if options.TLSValidateHostname {
- tlsConfig.ServerName = options.URL
- }
-
- return tlsConfig, nil
-}
diff --git a/pulsar/impl_client_test.go b/pulsar/impl_client_test.go
index 218587f..4d11ee6 100644
--- a/pulsar/impl_client_test.go
+++ b/pulsar/impl_client_test.go
@@ -20,6 +20,7 @@
package pulsar
import (
+ "io/ioutil"
"testing"
"github.com/stretchr/testify/assert"
@@ -147,7 +148,46 @@ func TestTLSAuth(t *testing.T) {
client, err := NewClient(ClientOptions{
URL: serviceUrlTls,
TLSTrustCertsFilePath: caCertsPath,
- Authentication: NewAuthenticationTLS(tlsClientCertPath, tlsClientKeyPath),
+ Authentication: NewAuthenticationTLS(tlsClientCertPath, tlsClientKeyPath),
+ })
+ assert.NoError(t, err)
+
+ producer, err := client.CreateProducer(ProducerOptions{
+ Topic: newAuthTopicName(),
+ })
+
+ assert.NoError(t, err)
+ assert.NotNil(t, producer)
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
+
+func TestTokenAuth(t *testing.T) {
+ token, err := ioutil.ReadFile(tokenFilePath)
+ assert.NoError(t, err)
+
+ client, err := NewClient(ClientOptions{
+ URL: serviceUrl,
+ Authentication: NewAuthenticationToken(string(token)),
+ })
+ assert.NoError(t, err)
+
+ producer, err := client.CreateProducer(ProducerOptions{
+ Topic: newAuthTopicName(),
+ })
+
+ assert.NoError(t, err)
+ assert.NotNil(t, producer)
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
+
+func TestTokenAuthFromFile(t *testing.T) {
+ client, err := NewClient(ClientOptions{
+ URL: serviceUrl,
+ Authentication: NewAuthenticationTokenFromFile(tokenFilePath),
})
assert.NoError(t, err)
diff --git a/pulsar/internal/auth/provider.go b/pulsar/internal/auth/provider.go
index c23a662..48c20dc 100644
--- a/pulsar/internal/auth/provider.go
+++ b/pulsar/internal/auth/provider.go
@@ -50,6 +50,9 @@ func NewProvider(name string, params string) (Provider, error) {
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)
+
default:
return nil, errors.New(fmt.Sprintf("invalid auth provider '%s'", name))
}
diff --git a/pulsar/internal/auth/token.go b/pulsar/internal/auth/token.go
new file mode 100644
index 0000000..d14279b
--- /dev/null
+++ b/pulsar/internal/auth/token.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"
+ "github.com/pkg/errors"
+ "io/ioutil"
+ "strings"
+)
+
+type tokenAuthProvider struct {
+ tokenSupplier func() (string, error)
+}
+
+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")
+ }
+}
+
+func NewAuthenticationToken(token string) Provider {
+ return &tokenAuthProvider{
+ tokenSupplier: func() (string, error) {
+ if token == "" {
+ return "", errors.New("empty token credentials")
+ } else {
+ return token, nil
+ }
+ },
+ }
+}
+
+func NewAuthenticationTokenFromFile(tokenFilePath string) Provider {
+ return &tokenAuthProvider{
+ tokenSupplier: func() (string, error) {
+ data, err := ioutil.ReadFile(tokenFilePath)
+ if err != nil {
+ return "", err
+ }
+
+ token := strings.Trim(string(data), " \n")
+ if token == "" {
+ return "", errors.New("empty token credentials")
+ } else {
+ 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
+ } else {
+ return []byte(t), nil
+ }
+}
+
+func (tokenAuthProvider) Close() error {
+ return nil
+}
diff --git a/pulsar/test_helper.go b/pulsar/test_helper.go
index 1e84a92..f4c9d7d 100644
--- a/pulsar/test_helper.go
+++ b/pulsar/test_helper.go
@@ -30,7 +30,8 @@ const (
caCertsPath = "../integration-tests/certs/cacert.pem"
tlsClientCertPath = "../integration-tests/certs/client-cert.pem"
- tlsClientKeyPath = "../integration-tests/certs/client-key.pem"
+ tlsClientKeyPath = "../integration-tests/certs/client-key.pem"
+ tokenFilePath = "../integration-tests/tokens/token.txt"
)
func newTopicName() string {
[pulsar-client-go] 13/38: Added blocking queue iterator
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit ecab9cf16eed5095bf39cbb376ca80248417db1c
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Wed Apr 10 14:46:44 2019 -0700
Added blocking queue iterator
---
pulsar/impl/util/blocking_queue.go | 44 +++++++++++++++++++++++++++++++++
pulsar/impl/util/blocking_queue_test.go | 15 +++++++++++
2 files changed, 59 insertions(+)
diff --git a/pulsar/impl/util/blocking_queue.go b/pulsar/impl/util/blocking_queue.go
index 281d6ba..1b6a609 100644
--- a/pulsar/impl/util/blocking_queue.go
+++ b/pulsar/impl/util/blocking_queue.go
@@ -1,6 +1,7 @@
package util
import (
+ log "github.com/sirupsen/logrus"
"sync"
)
@@ -19,6 +20,14 @@ type BlockingQueue interface {
// Return the current size of the queue
Size() int
+
+ // Return an iterator for the queue
+ Iterator() BlockingQueueIterator
+}
+
+type BlockingQueueIterator interface {
+ HasNext() bool
+ Next() interface{}
}
type blockingQueue struct {
@@ -33,6 +42,12 @@ type blockingQueue struct {
isNotFull *sync.Cond
}
+type blockingQueueIterator struct {
+ bq *blockingQueue
+ readIdx int
+ toRead int
+}
+
func NewBlockingQueue(maxSize int) BlockingQueue {
bq := &blockingQueue{
items: make([]interface{}, maxSize),
@@ -123,3 +138,32 @@ func (bq *blockingQueue) Size() int {
return bq.size
}
+
+func (bq *blockingQueue) Iterator() BlockingQueueIterator {
+ bq.mutex.Lock()
+ defer bq.mutex.Unlock()
+
+ return &blockingQueueIterator{
+ bq: bq,
+ readIdx: bq.headIdx,
+ toRead: bq.size,
+ }
+}
+
+func (bqi *blockingQueueIterator) HasNext() bool {
+ return bqi.toRead > 0
+}
+
+func (bqi *blockingQueueIterator) Next() interface{} {
+ if bqi.toRead == 0 {
+ log.Panic("Trying to read past the end of the iterator")
+ }
+
+ item := bqi.bq.items[bqi.readIdx]
+ bqi.toRead--
+ bqi.readIdx++
+ if bqi.readIdx == bqi.bq.maxSize {
+ bqi.readIdx = 0
+ }
+ return item
+}
diff --git a/pulsar/impl/util/blocking_queue_test.go b/pulsar/impl/util/blocking_queue_test.go
index 0ecc8d1..dd17db4 100644
--- a/pulsar/impl/util/blocking_queue_test.go
+++ b/pulsar/impl/util/blocking_queue_test.go
@@ -95,3 +95,18 @@ func TestBlockingQueueWaitWhenFull(t *testing.T) {
close(ch)
}
+
+func TestBlockingQueueIterator(t *testing.T) {
+ q := NewBlockingQueue(10)
+
+ q.Put(1)
+ q.Put(2)
+ q.Put(3)
+ assert.Equal(t, 3, q.Size())
+
+ i := 1
+ for it := q.Iterator(); it.HasNext(); {
+ assert.Equal(t, i, it.Next())
+ i++
+ }
+}
[pulsar-client-go] 05/38: Implemented keep-alive logic
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 1bdf19ff647f585ef792fdb35eaf084b9de44d04
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Sat Mar 30 11:17:12 2019 -0700
Implemented keep-alive logic
---
pulsar/impl/commands.go | 11 +++----
pulsar/impl/connection.go | 74 +++++++++++++++++++++++++++++++----------------
2 files changed, 53 insertions(+), 32 deletions(-)
diff --git a/pulsar/impl/commands.go b/pulsar/impl/commands.go
index 16e5b60..c803602 100644
--- a/pulsar/impl/commands.go
+++ b/pulsar/impl/commands.go
@@ -15,19 +15,16 @@ func baseCommand(cmdType pb.BaseCommand_Type, msg proto.Message) *pb.BaseCommand
switch cmdType {
case pb.BaseCommand_CONNECT:
cmd.Connect = msg.(*pb.CommandConnect)
- break
case pb.BaseCommand_LOOKUP:
cmd.LookupTopic = msg.(*pb.CommandLookupTopic)
- break
-
case pb.BaseCommand_PARTITIONED_METADATA:
cmd.PartitionMetadata = msg.(*pb.CommandPartitionedTopicMetadata)
- break
-
case pb.BaseCommand_PRODUCER:
cmd.Producer = msg.(*pb.CommandProducer)
- break
-
+ case pb.BaseCommand_PING:
+ cmd.Ping = msg.(*pb.CommandPing)
+ case pb.BaseCommand_PONG:
+ cmd.Pong = msg.(*pb.CommandPong)
default:
log.Panic("Missing command type: ", cmdType)
}
diff --git a/pulsar/impl/connection.go b/pulsar/impl/connection.go
index 28871cb..2bd2984 100644
--- a/pulsar/impl/connection.go
+++ b/pulsar/impl/connection.go
@@ -9,6 +9,7 @@ import (
pb "pulsar-client-go-native/pulsar/pulsar_proto"
"sync"
"sync/atomic"
+ "time"
)
type Connection interface {
@@ -26,6 +27,8 @@ const (
connectionClosed
)
+const keepAliveInterval = 30 * time.Second
+
type request struct {
id uint64
cmd *pb.BaseCommand
@@ -41,8 +44,10 @@ type connection struct {
physicalAddr string
cnx net.Conn
- writeBuffer Buffer
- reader *connectionReader
+ writeBuffer Buffer
+ reader *connectionReader
+ lastDataReceivedTime time.Time
+ pingTicker *time.Ticker
log *log.Entry
@@ -54,12 +59,14 @@ type connection struct {
func newConnection(logicalAddr *url.URL, physicalAddr *url.URL) *connection {
cnx := &connection{
- state: connectionInit,
- logicalAddr: logicalAddr.Host,
- physicalAddr: physicalAddr.Host,
- writeBuffer: NewBuffer(4096),
- log: log.WithField("raddr", physicalAddr),
- pendingReqs: make(map[uint64]*request),
+ state: connectionInit,
+ logicalAddr: logicalAddr.Host,
+ physicalAddr: physicalAddr.Host,
+ writeBuffer: NewBuffer(4096),
+ log: log.WithField("raddr", physicalAddr),
+ pendingReqs: make(map[uint64]*request),
+ lastDataReceivedTime: time.Now(),
+ pingTicker: time.NewTicker(keepAliveInterval),
}
cnx.reader = newConnectionReader(cnx)
cnx.cond = sync.NewCond(cnx)
@@ -156,6 +163,9 @@ func (c *connection) run() {
case req := <-c.incomingRequests:
c.pendingReqs[req.id] = req
c.writeCommand(req.cmd)
+
+ case _ = <-c.pingTicker.C:
+ c.sendPing()
}
}
}
@@ -189,59 +199,46 @@ func (c *connection) writeCommand(cmd proto.Message) {
func (c *connection) receivedCommand(cmd *pb.BaseCommand, headersAndPayload []byte) {
c.log.Infof("Received command: %s -- payload: %v", cmd, headersAndPayload)
+ c.lastDataReceivedTime = time.Now()
switch *cmd.Type {
case pb.BaseCommand_SUCCESS:
c.handleResponse(*cmd.Success.RequestId, cmd)
- break
case pb.BaseCommand_PRODUCER_SUCCESS:
c.handleResponse(*cmd.ProducerSuccess.RequestId, cmd)
- break
case pb.BaseCommand_PARTITIONED_METADATA_RESPONSE:
c.handleResponse(*cmd.PartitionMetadataResponse.RequestId, cmd)
- break
case pb.BaseCommand_LOOKUP_RESPONSE:
c.handleResponse(*cmd.LookupTopicResponse.RequestId, cmd)
- break
case pb.BaseCommand_CONSUMER_STATS_RESPONSE:
c.handleResponse(*cmd.ConsumerStatsResponse.RequestId, cmd)
- break
case pb.BaseCommand_GET_LAST_MESSAGE_ID_RESPONSE:
c.handleResponse(*cmd.GetLastMessageIdResponse.RequestId, cmd)
- break
case pb.BaseCommand_GET_TOPICS_OF_NAMESPACE_RESPONSE:
c.handleResponse(*cmd.GetTopicsOfNamespaceResponse.RequestId, cmd)
- break
case pb.BaseCommand_GET_SCHEMA_RESPONSE:
c.handleResponse(*cmd.GetSchemaResponse.RequestId, cmd)
- break
case pb.BaseCommand_ERROR:
- break
-
case pb.BaseCommand_CLOSE_PRODUCER:
case pb.BaseCommand_CLOSE_CONSUMER:
-
case pb.BaseCommand_SEND_RECEIPT:
- break
case pb.BaseCommand_SEND_ERROR:
- break
case pb.BaseCommand_MESSAGE:
- break
-
+ case pb.BaseCommand_PING:
+ c.handlePing()
case pb.BaseCommand_PONG:
+ c.handlePong()
case pb.BaseCommand_ACTIVE_CONSUMER_CHANGE:
- // TODO
- break
default:
c.log.Errorf("Received invalid command type: %s", cmd.Type)
@@ -269,6 +266,27 @@ func (c *connection) handleResponse(requestId uint64, response *pb.BaseCommand)
request.callback(response)
}
+func (c *connection) sendPing() {
+ if c.lastDataReceivedTime.Add(2 * keepAliveInterval).Before(time.Now()) {
+ // We have not received a response to the previous Ping request, the
+ // connection to broker is stale
+ c.log.Info("Detected stale connection to broker")
+ c.internalClose()
+ return
+ }
+
+ c.log.Debug("Sending PING")
+ c.writeCommand(baseCommand(pb.BaseCommand_PING, &pb.CommandPing{}))
+}
+
+func (c *connection) handlePong() {
+ c.writeCommand(baseCommand(pb.BaseCommand_PONG, &pb.CommandPong{}))
+}
+
+func (c *connection) handlePing() {
+ c.writeCommand(baseCommand(pb.BaseCommand_PONG, &pb.CommandPong{}))
+}
+
func (c *connection) Close() {
// TODO
}
@@ -285,10 +303,16 @@ func (c *connection) newRequestId() uint64 {
}
func (c *connection) internalClose() {
+ c.Lock()
+ defer c.Unlock()
+
c.state = connectionClosed
c.cond.Broadcast()
if c.cnx != nil {
+ c.log.Info("Connection closed")
c.cnx.Close()
+ c.pingTicker.Stop()
+ c.cnx = nil
}
}
[pulsar-client-go] 17/38: Implemented producer flush
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit ea44ac94fdb99a0d8317a94d000b878c656d027b
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Thu Apr 11 12:16:36 2019 -0700
Implemented producer flush
---
pulsar/impl/util/blocking_queue.go | 17 +++++++++-
pulsar/impl/util/blocking_queue_test.go | 6 ++++
pulsar/impl_partition_producer.go | 56 +++++++++++++++++++++++++--------
3 files changed, 65 insertions(+), 14 deletions(-)
diff --git a/pulsar/impl/util/blocking_queue.go b/pulsar/impl/util/blocking_queue.go
index 1b6a609..bdf6099 100644
--- a/pulsar/impl/util/blocking_queue.go
+++ b/pulsar/impl/util/blocking_queue.go
@@ -15,9 +15,12 @@ type BlockingQueue interface {
// Dequeue one item, return nil if queue is empty
Poll() interface{}
- // Return one item without dequeing, return nil if queue is empty
+ // Return the first item without dequeing, return nil if queue is empty
Peek() interface{}
+ // Return last item in queue without dequeing, return nil if queue is empty
+ PeekLast() interface{}
+
// Return the current size of the queue
Size() int
@@ -118,6 +121,18 @@ func (bq *blockingQueue) Peek() interface{} {
}
}
+func (bq *blockingQueue) PeekLast() interface{} {
+ bq.mutex.Lock()
+ defer bq.mutex.Unlock()
+
+ if bq.size == 0 {
+ return nil
+ } else {
+ 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
diff --git a/pulsar/impl/util/blocking_queue_test.go b/pulsar/impl/util/blocking_queue_test.go
index dd17db4..15cda0c 100644
--- a/pulsar/impl/util/blocking_queue_test.go
+++ b/pulsar/impl/util/blocking_queue_test.go
@@ -14,14 +14,18 @@ func TestBlockingQueue(t *testing.T) {
assert.Equal(t, 0, q.Size())
assert.Equal(t, nil, q.Poll())
assert.Equal(t, nil, q.Peek())
+ assert.Equal(t, nil, q.PeekLast())
q.Put("test")
assert.Equal(t, 1, q.Size())
assert.Equal(t, "test", q.Peek())
+ assert.Equal(t, "test", q.PeekLast())
assert.Equal(t, 1, q.Size())
assert.Equal(t, "test", q.Take())
+ assert.Equal(t, nil, q.Peek())
+ assert.Equal(t, nil, q.PeekLast())
assert.Equal(t, 0, q.Size())
ch := make(chan string)
@@ -65,6 +69,8 @@ func TestBlockingQueueWaitWhenFull(t *testing.T) {
q.Put("test-2")
q.Put("test-3")
assert.Equal(t, 3, q.Size())
+ assert.Equal(t, "test-1", q.Peek())
+ assert.Equal(t, "test-3", q.PeekLast())
ch := make(chan bool)
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index c99ea67..2557d1d 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -168,21 +168,20 @@ func (p *partitionProducer) runEventsLoop() {
for {
select {
case i := <-p.eventsChan:
- if i == nil {
- return
- }
-
switch v := i.(type) {
case *sendRequest:
p.internalSend(v)
case *connectionClosed:
p.reconnectToBroker()
+ case *flushRequest:
+ p.internalFlush(v)
case *closeProducer:
p.internalClose(v)
+ return
}
case _ = <-p.batchFlushTicker.C:
- p.internalFlush()
+ p.internalFlushCurrentBatch()
}
}
}
@@ -222,26 +221,26 @@ func (p *partitionProducer) internalSend(request *sendRequest) {
if sendAsBatch {
for ; p.batchBuilder.Add(smm, sequenceId, msg.Payload, request, msg.ReplicationClusters) == false; {
// The current batch is full.. flush it and retry
- p.internalFlush()
+ p.internalFlushCurrentBatch()
}
} else {
// Send individually
p.batchBuilder.Add(smm, sequenceId, msg.Payload, request, msg.ReplicationClusters)
- p.internalFlush()
+ p.internalFlushCurrentBatch()
}
if request.flushImmediately {
- p.internalFlush()
+ p.internalFlushCurrentBatch()
}
}
type pendingItem struct {
batchData []byte
sequenceId uint64
- sendRequest []interface{}
+ sendRequests []interface{}
}
-func (p *partitionProducer) internalFlush() {
+func (p *partitionProducer) internalFlushCurrentBatch() {
batchData, sequenceId, callbacks := p.batchBuilder.Flush()
if batchData == nil {
return
@@ -251,6 +250,18 @@ func (p *partitionProducer) internalFlush() {
p.cnx.WriteData(batchData)
}
+func (p *partitionProducer) internalFlush(fr *flushRequest) {
+ p.internalFlushCurrentBatch()
+
+ pi := p.pendingQueue.PeekLast().(*pendingItem)
+ pi.sendRequests = append(pi.sendRequests, &sendRequest{
+ callback: func(id MessageID, message *ProducerMessage, e error) {
+ fr.err = e
+ fr.waitGroup.Done()
+ },
+ })
+}
+
func (p *partitionProducer) Send(ctx context.Context, msg *ProducerMessage) error {
wg := sync.WaitGroup{}
wg.Add(1)
@@ -299,9 +310,11 @@ func (p *partitionProducer) ReceivedSendReceipt(response *pb.CommandSendReceipt)
// The ack was indeed for the expected item in the queue, we can remove it and trigger the callback
p.pendingQueue.Poll()
p.publishSemaphore.Release()
- for _, i := range pi.sendRequest {
+ for _, i := range pi.sendRequests {
sr := i.(*sendRequest)
- sr.callback(nil, sr.msg, nil)
+ if sr.callback != nil {
+ sr.callback(nil, sr.msg, nil)
+ }
}
}
@@ -338,10 +351,21 @@ func (p *partitionProducer) LastSequenceID() int64 {
}
func (p *partitionProducer) Flush() error {
- return nil
+ wg := sync.WaitGroup{}
+ wg.Add(1)
+
+ cp := &flushRequest{&wg, nil}
+ p.eventsChan <- cp
+
+ wg.Wait()
+ return cp.err
}
func (p *partitionProducer) Close() error {
+ if p.state != producerReady {
+ // Producer is closing
+ return nil
+ }
wg := sync.WaitGroup{}
wg.Add(1)
@@ -364,3 +388,9 @@ type closeProducer struct {
waitGroup *sync.WaitGroup
err error
}
+
+type flushRequest struct {
+ waitGroup *sync.WaitGroup
+ err error
+}
+
[pulsar-client-go] 32/38: Addressed comments
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 617f0d5647347d16e15df8e9db7a6d852df54d38
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Tue May 7 13:16:16 2019 -0700
Addressed comments
---
pulsar/error.go | 1 -
pulsar/impl/backoff.go | 6 ++++--
pulsar/impl/batch_builder.go | 10 +++++-----
pulsar/{util_test.go => test_helper.go} | 0
4 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/pulsar/error.go b/pulsar/error.go
index 24e1536..38b9d64 100644
--- a/pulsar/error.go
+++ b/pulsar/error.go
@@ -19,7 +19,6 @@
package pulsar
-import "C"
import "fmt"
type Result int
diff --git a/pulsar/impl/backoff.go b/pulsar/impl/backoff.go
index afd6c4f..3e7629e 100644
--- a/pulsar/impl/backoff.go
+++ b/pulsar/impl/backoff.go
@@ -27,8 +27,10 @@ type Backoff struct {
backoff time.Duration
}
-const minBackoff = 100 * time.Millisecond
-const maxBackoff = 60 * time.Second
+const (
+ minBackoff = 100 * time.Millisecond
+ maxBackoff = 60 * time.Second
+)
func (b *Backoff) Next() time.Duration {
// Double the delay each time
diff --git a/pulsar/impl/batch_builder.go b/pulsar/impl/batch_builder.go
index 0cb19f0..a3b41a2 100644
--- a/pulsar/impl/batch_builder.go
+++ b/pulsar/impl/batch_builder.go
@@ -27,11 +27,11 @@ import (
"time"
)
-const MaxMessageSize = 5 * 1024 * 1024
-
-const MaxBatchSize = 128 * 1024
-
-const DefaultMaxMessagesPerBatch = 1000
+const (
+ MaxMessageSize = 5 * 1024 * 1024
+ MaxBatchSize = 128 * 1024
+ DefaultMaxMessagesPerBatch = 1000
+)
type BatchBuilder struct {
buffer Buffer
diff --git a/pulsar/util_test.go b/pulsar/test_helper.go
similarity index 100%
rename from pulsar/util_test.go
rename to pulsar/test_helper.go
[pulsar-client-go] 10/38: Reconnection logic
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 2e74112c2e6162bfdf702ed03af2550d0d3ddd49
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Sat Apr 6 08:35:50 2019 -0700
Reconnection logic
---
pulsar/impl/backoff.go | 24 ++++++++++++++++++++
pulsar/impl/batch_builder.go | 2 +-
pulsar/impl/connection.go | 48 ++++++++++++++++++++++++++++++++-------
pulsar/impl/connection_pool.go | 3 ++-
pulsar/impl_partition_producer.go | 28 +++++++++++++++++++++++
5 files changed, 95 insertions(+), 10 deletions(-)
diff --git a/pulsar/impl/backoff.go b/pulsar/impl/backoff.go
new file mode 100644
index 0000000..451509f
--- /dev/null
+++ b/pulsar/impl/backoff.go
@@ -0,0 +1,24 @@
+package impl
+
+import (
+ "time"
+)
+
+type Backoff struct {
+ backoff time.Duration
+}
+
+const minBackoff = 100 * time.Millisecond
+const maxBackoff = 60 * time.Second
+
+func (b *Backoff) Next() time.Duration {
+ // 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
+ }
+
+ return b.backoff
+}
diff --git a/pulsar/impl/batch_builder.go b/pulsar/impl/batch_builder.go
index 6b0df8e..53bf081 100644
--- a/pulsar/impl/batch_builder.go
+++ b/pulsar/impl/batch_builder.go
@@ -84,7 +84,7 @@ func (bb *BatchBuilder) reset() {
}
func (bb *BatchBuilder) Flush() []byte {
- log.Info("BatchBuilder flush: messages: ", bb.numMessages)
+ log.Debug("BatchBuilder flush: messages: ", bb.numMessages)
if bb.numMessages == 0 {
// No-Op for empty batch
return nil
diff --git a/pulsar/impl/connection.go b/pulsar/impl/connection.go
index 04fa10f..18a3b63 100644
--- a/pulsar/impl/connection.go
+++ b/pulsar/impl/connection.go
@@ -12,9 +12,17 @@ import (
"time"
)
+// 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 {
+ ConnectionClosed()
+}
+
type Connection interface {
SendRequest(requestId uint64, req *pb.BaseCommand, callback func(command *pb.BaseCommand))
WriteData(data []byte)
+ RegisterListener(listener ConnectionListener)
Close()
}
@@ -57,6 +65,7 @@ type connection struct {
incomingRequests chan *request
writeRequests chan []byte
pendingReqs map[uint64]*request
+ listeners []ConnectionListener
}
func newConnection(logicalAddr *url.URL, physicalAddr *url.URL) *connection {
@@ -72,6 +81,7 @@ func newConnection(logicalAddr *url.URL, physicalAddr *url.URL) *connection {
incomingRequests: make(chan *request),
writeRequests: make(chan []byte),
+ listeners: make([]ConnectionListener, 0),
}
cnx.reader = newConnectionReader(cnx)
cnx.cond = sync.NewCond(cnx)
@@ -142,13 +152,15 @@ func (c *connection) waitUntilReady() error {
defer c.Unlock()
for {
+ c.log.Debug("Wait until connection is ready. State: ", c.state)
switch c.state {
case connectionInit:
+ fallthrough
case connectionConnecting:
+ fallthrough
case connectionTcpConnected:
// Wait for the state to change
c.cond.Wait()
- break
case connectionReady:
return nil
@@ -166,10 +178,16 @@ func (c *connection) run() {
for {
select {
case req := <-c.incomingRequests:
+ if req == nil {
+ return
+ }
c.pendingReqs[req.id] = req
c.writeCommand(req.cmd)
case data := <-c.writeRequests:
+ if data == nil {
+ return
+ }
c.internalWriteData(data)
case _ = <-c.pingTicker.C:
@@ -183,7 +201,7 @@ func (c *connection) WriteData(data []byte) {
}
func (c *connection) internalWriteData(data []byte) {
- c.log.Info("Write data: ", len(data))
+ c.log.Debug("Write data: ", len(data))
if _, err := c.cnx.Write(data); err != nil {
c.log.WithError(err).Warn("Failed to write on connection")
c.Close()
@@ -313,20 +331,34 @@ func (c *connection) handlePing() {
c.writeCommand(baseCommand(pb.BaseCommand_PONG, &pb.CommandPong{}))
}
+func (c *connection) RegisterListener(listener ConnectionListener) {
+ c.Lock()
+ defer c.Unlock()
+
+ c.listeners = append(c.listeners, listener)
+}
+
func (c *connection) Close() {
c.Lock()
defer c.Unlock()
- c.state = connectionClosed
c.cond.Broadcast()
+ if c.state == connectionClosed {
+ return
+ }
+
+ c.log.Info("Connection closed")
+ c.state = connectionClosed
if c.cnx != nil {
- c.log.Info("Connection closed")
c.cnx.Close()
- c.pingTicker.Stop()
- close(c.incomingRequests)
- close(c.writeRequests)
- c.cnx = nil
+ }
+ c.pingTicker.Stop()
+ close(c.incomingRequests)
+ close(c.writeRequests)
+ //c.cnx = nil
+ for _, listener := range c.listeners {
+ listener.ConnectionClosed()
}
}
diff --git a/pulsar/impl/connection_pool.go b/pulsar/impl/connection_pool.go
index 1fa647f..ef5ca8b 100644
--- a/pulsar/impl/connection_pool.go
+++ b/pulsar/impl/connection_pool.go
@@ -32,7 +32,8 @@ func (p *connectionPool) GetConnection(logicalAddr *url.URL, physicalAddr *url.U
return cnx, nil
} else {
// The cached connection is failed
- p.pool.Delete(logicalAddr)
+ p.pool.Delete(logicalAddr.Host)
+ log.Debug("Removed failed connection from pool:", cnx.logicalAddr, cnx.physicalAddr)
}
}
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index 2677770..60ae76c 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -99,10 +99,36 @@ func (p *partitionProducer) grabCnx() error {
p.sequenceIdGenerator = &nextSequenceId
}
p.cnx = res.Cnx
+ p.cnx.RegisterListener(p)
p.log.WithField("cnx", res.Cnx).Debug("Connected producer")
return nil
}
+type connectionClosed struct {
+}
+
+func (p *partitionProducer) ConnectionClosed() {
+ // Trigger reconnection in the produce goroutine
+ p.eventsChan <- &connectionClosed{}
+}
+
+func (p *partitionProducer) reconnectToBroker() {
+ backoff := impl.Backoff{}
+ for {
+ err := p.grabCnx()
+ if err == nil {
+ // Successfully reconnected
+ return
+ }
+
+ d := backoff.Next()
+ p.log.Info("Retrying reconnection after ", d)
+
+ time.Sleep(d)
+ }
+}
+
+
func (p *partitionProducer) run() {
for {
select {
@@ -110,6 +136,8 @@ func (p *partitionProducer) run() {
switch v := i.(type) {
case *sendRequest:
p.internalSend(v)
+ case *connectionClosed:
+ p.reconnectToBroker()
}
case _ = <-p.batchFlushTicker.C:
[pulsar-client-go] 22/38: Added hash functions and tests
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 0ac78681c6337874e250154a6d9ad4431edf0f24
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Fri May 3 17:25:02 2019 -0700
Added hash functions and tests
---
pulsar/impl/hash.go | 19 +++++++++++++++++++
pulsar/impl/hash_test.go | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+)
diff --git a/pulsar/impl/hash.go b/pulsar/impl/hash.go
new file mode 100644
index 0000000..bd65da1
--- /dev/null
+++ b/pulsar/impl/hash.go
@@ -0,0 +1,19 @@
+package impl
+
+import "github.com/spaolacci/murmur3"
+
+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
+}
+
+func Murmur3_32Hash(s string) uint32 {
+ h := murmur3.New32()
+ h.Write([]byte(s))
+ // Maintain compatibility with values used in Java client
+ return h.Sum32() & 0x7fffffff
+}
diff --git a/pulsar/impl/hash_test.go b/pulsar/impl/hash_test.go
new file mode 100644
index 0000000..76b418a
--- /dev/null
+++ b/pulsar/impl/hash_test.go
@@ -0,0 +1,40 @@
+package impl
+
+import (
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+type testProvider struct {
+ str string
+
+ hash uint32
+}
+
+var javaHashValues = []testProvider{
+ {"", 0x0,},
+ {"hello", 0x5e918d2},
+ {"test", 0x364492},
+}
+
+var murmurHashValues = []testProvider{
+ {"", 0x0},
+ {"hello", 0x248bfa47},
+ {"test", 0x3a6bd213},
+}
+
+func TestJavaHash(t *testing.T) {
+ for _, p := range javaHashValues {
+ t.Run(p.str, func(t *testing.T) {
+ assert.Equal(t, p.hash, JavaStringHash(p.str))
+ })
+ }
+}
+
+func TestMurmurHash(t *testing.T) {
+ for _, p := range murmurHashValues {
+ t.Run(p.str, func(t *testing.T) {
+ assert.Equal(t, p.hash, Murmur3_32Hash(p.str))
+ })
+ }
+}
[pulsar-client-go] 14/38: Resend pending messages after reconnection
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 427fe05cdec379e4a773a6a911a90fb6b3820506
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Wed Apr 10 15:20:27 2019 -0700
Resend pending messages after reconnection
---
pulsar/impl/connection.go | 2 +-
pulsar/impl_partition_producer.go | 9 +++++++++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/pulsar/impl/connection.go b/pulsar/impl/connection.go
index fa32889..0cba51d 100644
--- a/pulsar/impl/connection.go
+++ b/pulsar/impl/connection.go
@@ -369,7 +369,7 @@ func (c *connection) Close() {
c.pingTicker.Stop()
close(c.incomingRequests)
close(c.writeRequests)
- //c.cnx = nil
+
for _, listener := range c.listeners {
listener.ConnectionClosed()
}
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index cdd34d5..5f50296 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -114,6 +114,13 @@ func (p *partitionProducer) grabCnx() error {
p.cnx = res.Cnx
p.cnx.RegisterListener(p.producerId, p)
p.log.WithField("cnx", res.Cnx).Debug("Connected producer")
+
+ if p.pendingQueue.Size() > 0 {
+ p.log.Infof("Resending %v pending batches", p.pendingQueue.Size())
+ for it := p.pendingQueue.Iterator(); it.HasNext(); {
+ p.cnx.WriteData(it.Next().(*pendingItem).batchData)
+ }
+ }
return nil
}
@@ -126,6 +133,7 @@ func (p *partitionProducer) ConnectionClosed() {
}
func (p *partitionProducer) reconnectToBroker() {
+ p.log.Info("Reconnecting to broker")
backoff := impl.Backoff{}
for {
err := p.grabCnx()
@@ -255,6 +263,7 @@ func (p *partitionProducer) ReceivedSendReceipt(response *pb.CommandSendReceipt)
// The ack was indeed for the expected item in the queue, we can remove it and trigger the callback
p.pendingQueue.Poll()
+ p.publishSemaphore.Release()
for _ ,i := range pi.sendRequest {
sr := i.(*sendRequest)
sr.callback(nil, sr.msg, nil)
[pulsar-client-go] 31/38: Added README
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit b212407d84ca781cea30a584ba05aa34c1f4ca3d
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Mon May 6 14:58:39 2019 -0700
Added README
---
README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/README.md b/README.md
index e69de29..3e6a279 100644
--- a/README.md
+++ b/README.md
@@ -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.
+
+-->
+
+# Apache Pulsar Go Client Library
+
+> Note: this library is still a work in progress. For production usage, please
+refer to the CGo based client library, documented at
+http://pulsar.apache.org/docs/en/client-libraries-go/
+
+## Goal
+
+This projects is developing a pure-Go client library for Pulsar that does not
+depend on the C++ Pulsar library.
+
+Once feature parity and stability are reached, this will supersede the current
+CGo based library.
+
+## Status
+
+Check the Projects page at https://github.com/apache/pulsar-client-go/projects for
+tracking the status and the progress.
+
+## Contact
+
+##### Mailing lists
+
+| Name | Scope | | | |
+|:------------------------------------------------------------------------------|:--------------------------------|:----------------------------------------------------------------|:--------------------------------------------------------------------|:-----------------------------------------------------------------------------|
+| [users@pulsar.apache.org](mailto:users@pulsar.apache.org) | User-related discussions | [Subscribe](mailto:users-subscribe@pulsar.apache.org) | [Unsubscribe](mailto:users-unsubscribe@pulsar.apache.org) | [Archives](http://mail-archives.apache.org/mod_mbox/pulsar-users/) |
+| [dev@pulsar.apache.org](mailto:dev@pulsar.apache.org) | Development-related discussions | [Subscribe](mailto:dev-subscribe@pulsar.apache.org) | [Unsubscribe](mailto:dev-unsubscribe@pulsar.apache.org) | [Archives](http://mail-archives.apache.org/mod_mbox/pulsar-dev/) |
+
+##### Slack
+
+Pulsar slack channel `#dev-go` at https://apache-pulsar.slack.com/
+
+You can self-register at https://apache-pulsar.herokuapp.com/
+
+## License
+
+Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
+
+
[pulsar-client-go] 25/38: Added auto-resize when writing to buffer
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 9c6d52f2ed619999d72dea3a40e8022babd799f2
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Sat May 4 12:43:19 2019 -0700
Added auto-resize when writing to buffer
---
pulsar/impl/buffer.go | 18 +++++++++++++++++-
pulsar/impl/connection.go | 5 -----
2 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/pulsar/impl/buffer.go b/pulsar/impl/buffer.go
index 3d03002..3f8dcc0 100644
--- a/pulsar/impl/buffer.go
+++ b/pulsar/impl/buffer.go
@@ -1,6 +1,8 @@
package impl
-import "encoding/binary"
+import (
+ "encoding/binary"
+)
type Buffer interface {
ReadableBytes() uint32
@@ -121,6 +123,17 @@ func (b *buffer) Resize(newSize uint32) {
b.writerIdx = size
}
+func (b *buffer) resizeIfNeeded(spaceNeeded int) {
+ if b.WritableBytes() < uint32(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))
}
@@ -130,6 +143,7 @@ func (b *buffer) ReadUint16() uint16 {
}
func (b *buffer) WriteUint32(n uint32) {
+ b.resizeIfNeeded(4)
binary.BigEndian.PutUint32(b.WritableSlice(), n)
b.writerIdx += 4
}
@@ -139,11 +153,13 @@ func (b *buffer) PutUint32(n uint32, idx uint32) {
}
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(len(s))
copy(b.WritableSlice(), s)
b.writerIdx += uint32(len(s))
}
diff --git a/pulsar/impl/connection.go b/pulsar/impl/connection.go
index 8cdcf8b..580a821 100644
--- a/pulsar/impl/connection.go
+++ b/pulsar/impl/connection.go
@@ -216,13 +216,8 @@ func (c *connection) writeCommand(cmd proto.Message) {
// [FRAME_SIZE] [CMD_SIZE][CMD]
cmdSize := uint32(proto.Size(cmd))
frameSize := cmdSize + 4
- bufferSize := frameSize + 4
c.writeBuffer.Clear()
- if c.writeBuffer.WritableBytes() < bufferSize {
- c.writeBuffer.Resize(c.writeBuffer.Capacity() * 2)
- }
-
c.writeBuffer.WriteUint32(frameSize)
c.writeBuffer.WriteUint32(cmdSize)
serialized, err := proto.Marshal(cmd)
[pulsar-client-go] 35/38: Added TLS connection support
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit ddc789e1e2ea8706556bd7ace71fd2c3f662b217
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Wed May 8 12:14:44 2019 -0700
Added TLS connection support
---
pulsar/client.go | 4 +-
pulsar/impl_client.go | 46 +++++++++++++++++--
pulsar/impl_client_test.go | 94 ++++++++++++++++++++++++++++++++++++++
pulsar/internal/connection.go | 70 +++++++++++++++++++++++++---
pulsar/internal/connection_pool.go | 11 +++--
pulsar/test_helper.go | 7 ++-
6 files changed, 215 insertions(+), 17 deletions(-)
diff --git a/pulsar/client.go b/pulsar/client.go
index e68f09c..d870dcd 100644
--- a/pulsar/client.go
+++ b/pulsar/client.go
@@ -20,6 +20,7 @@
package pulsar
import (
+ "pulsar-client-go/pulsar/internal/auth"
"time"
)
@@ -44,8 +45,7 @@ func NewAuthenticationTokenSupplier(tokenSupplier func() string) Authentication
// Create new Authentication provider with specified TLS certificate and private key
func NewAuthenticationTLS(certificatePath string, privateKeyPath string) Authentication {
- // TODO: return newAuthenticationTLS(certificatePath, privateKeyPath)
- return nil
+ return auth.NewAuthenticationTLS(certificatePath, privateKeyPath)
}
// Create new Athenz Authentication provider with configuration in JSON form
diff --git a/pulsar/impl_client.go b/pulsar/impl_client.go
index 0db2ee8..9a3ee7d 100644
--- a/pulsar/impl_client.go
+++ b/pulsar/impl_client.go
@@ -20,8 +20,12 @@
package pulsar
import (
+ "crypto/tls"
+ "crypto/x509"
"fmt"
+ "github.com/pkg/errors"
log "github.com/sirupsen/logrus"
+ "io/ioutil"
"net/url"
"pulsar-client-go/pulsar/internal"
pb "pulsar-client-go/pulsar/internal/pulsar_proto"
@@ -50,12 +54,24 @@ func newClient(options ClientOptions) (Client, error) {
return nil, newError(ResultInvalidConfiguration, "Invalid service URL")
}
- if url.Scheme != "pulsar" {
+ var tlsConfig *internal.TLSOptions
+ if url.Scheme == "pulsar" {
+ tlsConfig = nil
+ } else if url.Scheme == "pulsar+ssl" {
+ tlsConfig = &internal.TLSOptions{
+ AllowInsecureConnection: options.TLSAllowInsecureConnection,
+ TrustCertsFilePath: options.TLSTrustCertsFilePath,
+ ValidateHostname: options.TLSValidateHostname,
+ }
+ if err != nil {
+ return nil, err
+ }
+ } else {
return nil, newError(ResultInvalidConfiguration, fmt.Sprintf("Invalid URL scheme '%s'", url.Scheme))
}
c := &client{
- cnxPool: internal.NewConnectionPool(),
+ cnxPool: internal.NewConnectionPool(tlsConfig),
}
c.rpcClient = internal.NewRpcClient(url, c.cnxPool)
c.lookupService = internal.NewLookupService(c.rpcClient, url)
@@ -114,7 +130,6 @@ func (client *client) TopicPartitions(topic string) ([]string, error) {
}
}
-
func (client *client) Close() error {
for handler := range client.handlers {
if err := handler.Close(); err != nil {
@@ -124,3 +139,28 @@ func (client *client) Close() error {
return nil
}
+
+func getTlsConfig(options ClientOptions) (*tls.Config, error) {
+ tlsConfig := &tls.Config{
+ InsecureSkipVerify: options.TLSAllowInsecureConnection,
+ }
+
+ if options.TLSTrustCertsFilePath != "" {
+ caCerts, err := ioutil.ReadFile(options.TLSTrustCertsFilePath)
+ if err != nil {
+ return nil, err
+ }
+
+ tlsConfig.RootCAs = x509.NewCertPool()
+ ok := tlsConfig.RootCAs.AppendCertsFromPEM([]byte(caCerts))
+ if !ok {
+ return nil, errors.New("failed to parse root CAs certificates")
+ }
+ }
+
+ if options.TLSValidateHostname {
+ tlsConfig.ServerName = options.URL
+ }
+
+ return tlsConfig, nil
+}
diff --git a/pulsar/impl_client_test.go b/pulsar/impl_client_test.go
index 4542740..9fd4231 100644
--- a/pulsar/impl_client_test.go
+++ b/pulsar/impl_client_test.go
@@ -31,3 +31,97 @@ func TestClient(t *testing.T) {
assert.NotNil(t, err)
assert.Equal(t, Result(ResultInvalidConfiguration), err.(*Error).Result())
}
+
+func TestTLSConnectionCAError(t *testing.T) {
+ client, err := NewClient(ClientOptions{
+ URL: serviceUrlTls,
+ })
+ assert.NoError(t, err)
+
+ producer, err := client.CreateProducer(ProducerOptions{
+ Topic: newTopicName(),
+ })
+
+ // The client should fail because it wouldn't trust the
+ // broker certificate
+ assert.Error(t, err)
+ assert.Nil(t, producer)
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
+
+func TestTLSInsecureConnection(t *testing.T) {
+ client, err := NewClient(ClientOptions{
+ URL: serviceUrlTls,
+ TLSAllowInsecureConnection: true,
+ })
+ assert.NoError(t, err)
+
+ producer, err := client.CreateProducer(ProducerOptions{
+ Topic: newTopicName(),
+ })
+
+ assert.NoError(t, err)
+ assert.NotNil(t, producer)
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
+
+func TestTLSConnection(t *testing.T) {
+ client, err := NewClient(ClientOptions{
+ URL: serviceUrlTls,
+ TLSTrustCertsFilePath: caCertsPath,
+ })
+ assert.NoError(t, err)
+
+ producer, err := client.CreateProducer(ProducerOptions{
+ Topic: newTopicName(),
+ })
+
+ assert.NoError(t, err)
+ assert.NotNil(t, producer)
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
+
+func TestTLSConnectionHostNameVerification(t *testing.T) {
+ client, err := NewClient(ClientOptions{
+ URL: serviceUrlTls,
+ TLSTrustCertsFilePath: caCertsPath,
+ TLSValidateHostname: true,
+ })
+ assert.NoError(t, err)
+
+ producer, err := client.CreateProducer(ProducerOptions{
+ Topic: newTopicName(),
+ })
+
+ assert.NoError(t, err)
+ assert.NotNil(t, producer)
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
+
+func TestTLSConnectionHostNameVerificationError(t *testing.T) {
+ client, err := NewClient(ClientOptions{
+ URL: "pulsar+ssl://127.0.0.1:6651",
+ TLSTrustCertsFilePath: caCertsPath,
+ TLSValidateHostname: true,
+ })
+ assert.NoError(t, err)
+
+ producer, err := client.CreateProducer(ProducerOptions{
+ Topic: newTopicName(),
+ })
+
+ assert.Error(t, err)
+ assert.Nil(t, producer)
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
+
diff --git a/pulsar/internal/connection.go b/pulsar/internal/connection.go
index affa8cc..fdcfd60 100644
--- a/pulsar/internal/connection.go
+++ b/pulsar/internal/connection.go
@@ -20,9 +20,12 @@
package internal
import (
+ "crypto/tls"
+ "crypto/x509"
"errors"
"github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
+ "io/ioutil"
"net"
"net/url"
pb "pulsar-client-go/pulsar/internal/pulsar_proto"
@@ -31,6 +34,12 @@ import (
"time"
)
+type TLSOptions struct {
+ TrustCertsFilePath string
+ AllowInsecureConnection bool
+ ValidateHostname bool
+}
+
// 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.
@@ -71,8 +80,8 @@ type connection struct {
cond *sync.Cond
state connectionState
- logicalAddr string
- physicalAddr string
+ logicalAddr *url.URL
+ physicalAddr *url.URL
cnx net.Conn
writeBuffer Buffer
@@ -88,18 +97,21 @@ type connection struct {
writeRequests chan []byte
pendingReqs map[uint64]*request
listeners map[uint64]ConnectionListener
+
+ tlsOptions *TLSOptions
}
-func newConnection(logicalAddr *url.URL, physicalAddr *url.URL) *connection {
+func newConnection(logicalAddr *url.URL, physicalAddr *url.URL, tlsOptions *TLSOptions) *connection {
cnx := &connection{
state: connectionInit,
- logicalAddr: logicalAddr.Host,
- physicalAddr: physicalAddr.Host,
+ logicalAddr: logicalAddr,
+ physicalAddr: physicalAddr,
writeBuffer: NewBuffer(4096),
log: log.WithField("raddr", physicalAddr),
pendingReqs: make(map[uint64]*request),
lastDataReceivedTime: time.Now(),
pingTicker: time.NewTicker(keepAliveInterval),
+ tlsOptions: tlsOptions,
incomingRequests: make(chan *request),
writeRequests: make(chan []byte),
@@ -128,13 +140,32 @@ func (c *connection) start() {
func (c *connection) connect() (ok bool) {
c.log.Info("Connecting to broker")
- var err error
- c.cnx, err = net.Dial("tcp", c.physicalAddr)
+ var (
+ err error
+ cnx net.Conn
+ tlsConfig *tls.Config
+ )
+
+ if c.tlsOptions == nil {
+ // Clear text connection
+ cnx, err = net.Dial("tcp", c.physicalAddr.Host)
+ } else {
+ // TLS connection
+ tlsConfig, err = c.getTlsConfig()
+ if err != nil {
+ c.log.WithError(err).Warn("Failed to configure TLS ")
+ return false
+ }
+
+ cnx, err = tls.Dial("tcp", c.physicalAddr.Host, tlsConfig)
+ }
+
if err != nil {
c.log.WithError(err).Warn("Failed to connect to broker.")
c.Close()
return false
} else {
+ c.cnx = cnx
c.log = c.log.WithField("laddr", c.cnx.LocalAddr())
c.log.Debug("TCP connection established")
c.state = connectionTcpConnected
@@ -407,3 +438,28 @@ func (c *connection) changeState(state connectionState) {
func (c *connection) newRequestId() uint64 {
return atomic.AddUint64(&c.requestIdGenerator, 1)
}
+
+func (c *connection) getTlsConfig() (*tls.Config, error) {
+ tlsConfig := &tls.Config{
+ InsecureSkipVerify: c.tlsOptions.AllowInsecureConnection,
+ }
+
+ if c.tlsOptions.TrustCertsFilePath != "" {
+ caCerts, err := ioutil.ReadFile(c.tlsOptions.TrustCertsFilePath)
+ if err != nil {
+ return nil, err
+ }
+
+ tlsConfig.RootCAs = x509.NewCertPool()
+ ok := tlsConfig.RootCAs.AppendCertsFromPEM([]byte(caCerts))
+ if !ok {
+ return nil, errors.New("failed to parse root CAs certificates")
+ }
+ }
+
+ if c.tlsOptions.ValidateHostname {
+ tlsConfig.ServerName = c.physicalAddr.Hostname()
+ }
+
+ return tlsConfig, nil
+}
diff --git a/pulsar/internal/connection_pool.go b/pulsar/internal/connection_pool.go
index 4b56484..6540137 100644
--- a/pulsar/internal/connection_pool.go
+++ b/pulsar/internal/connection_pool.go
@@ -33,11 +33,14 @@ type ConnectionPool interface {
}
type connectionPool struct {
- pool sync.Map
+ pool sync.Map
+ tlsOptions *TLSOptions
}
-func NewConnectionPool() ConnectionPool {
- return &connectionPool{}
+func NewConnectionPool(tlsOptions *TLSOptions) ConnectionPool {
+ return &connectionPool{
+ tlsOptions: tlsOptions,
+ }
}
func (p *connectionPool) GetConnection(logicalAddr *url.URL, physicalAddr *url.URL) (Connection, error) {
@@ -57,7 +60,7 @@ func (p *connectionPool) GetConnection(logicalAddr *url.URL, physicalAddr *url.U
}
// Try to create a new connection
- newCnx, wasCached := p.pool.LoadOrStore(logicalAddr.Host, newConnection(logicalAddr, physicalAddr))
+ newCnx, wasCached := p.pool.LoadOrStore(logicalAddr.Host, newConnection(logicalAddr, physicalAddr, p.tlsOptions))
cnx := newCnx.(*connection)
if !wasCached {
cnx.start()
diff --git a/pulsar/test_helper.go b/pulsar/test_helper.go
index 1795e41..c6c78e1 100644
--- a/pulsar/test_helper.go
+++ b/pulsar/test_helper.go
@@ -24,7 +24,12 @@ import (
"time"
)
-const serviceUrl = "pulsar://localhost:6650"
+const (
+ serviceUrl = "pulsar://localhost:6650"
+ serviceUrlTls = "pulsar+ssl://localhost:6651"
+
+ caCertsPath = "../integration-tests/certs/cacert.pem"
+)
func newTopicName() string {
return fmt.Sprintf("my-topic-%v", time.Now().Nanosecond())
[pulsar-client-go] 06/38: Set right level for logs
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit d31030ecc8373ba80ff33f03a13d8a54fdf7f880
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Sat Mar 30 11:37:23 2019 -0700
Set right level for logs
---
pulsar/impl/connection.go | 4 ++--
pulsar/impl/lookup_service.go | 6 +++---
pulsar/impl_partition_producer.go | 9 +++++----
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/pulsar/impl/connection.go b/pulsar/impl/connection.go
index 2bd2984..2f09690 100644
--- a/pulsar/impl/connection.go
+++ b/pulsar/impl/connection.go
@@ -99,7 +99,7 @@ func (c *connection) connect() (ok bool) {
return false
} else {
c.log = c.log.WithField("laddr", c.cnx.LocalAddr())
- c.log.Info("TCP connection established")
+ c.log.Debug("TCP connection established")
c.state = connectionTcpConnected
return true
}
@@ -198,7 +198,7 @@ func (c *connection) writeCommand(cmd proto.Message) {
}
func (c *connection) receivedCommand(cmd *pb.BaseCommand, headersAndPayload []byte) {
- c.log.Infof("Received command: %s -- payload: %v", cmd, headersAndPayload)
+ c.log.Debugf("Received command: %s -- payload: %v", cmd, headersAndPayload)
c.lastDataReceivedTime = time.Now()
switch *cmd.Type {
diff --git a/pulsar/impl/lookup_service.go b/pulsar/impl/lookup_service.go
index afd0dda..e3753d9 100644
--- a/pulsar/impl/lookup_service.go
+++ b/pulsar/impl/lookup_service.go
@@ -44,17 +44,17 @@ func (ls *lookupService) Lookup(topic string) (*LookupResult, error) {
return nil, err
}
- log.Infof("Got lookup response: %s", res)
+ log.WithField("topic", topic).Debugf("Got topic lookup response: %s", res)
lr := res.Response.LookupTopicResponse
switch *lr.Response {
case pb.CommandLookupTopicResponse_Redirect:
// TODO: Handle redirects
- log.WithField("topic", topic).Infof("Follow redirect to broker. %v / %v - Use proxy: %v",
+ log.WithField("topic", topic).Debugf("Follow redirect to broker. %v / %v - Use proxy: %v",
lr.BrokerServiceUrl, lr.BrokerServiceUrlTls, lr.ProxyThroughServiceUrl)
break
case pb.CommandLookupTopicResponse_Connect:
- log.WithField("topic", topic).Infof("Successfully looked up topic on broker. %s / %s - Use proxy: %t",
+ log.WithField("topic", topic).Debugf("Successfully looked up topic on broker. %s / %s - Use proxy: %t",
lr.GetBrokerServiceUrl(), lr.GetBrokerServiceUrlTls(), lr.GetProxyThroughServiceUrl())
logicalAddress, err := url.Parse(lr.GetBrokerServiceUrl())
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index 4ba5506..7bb2165 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -42,7 +42,8 @@ func newPartitionProducer(client *client, topic string, options *ProducerOptions
log.WithError(err).Errorf("Failed to create producer")
return nil, err
} else {
- log.Info("Created producer on cnx: ")
+ p.log = p.log.WithField("name", *p.producerName)
+ p.log.Info("Created producer")
go p.run()
return p, nil
}
@@ -55,7 +56,7 @@ func (p *partitionProducer) grabCnx() error {
return err
}
- p.log.Info("Lookup result: ", lr)
+ p.log.Debug("Lookup result: ", lr)
id := p.client.rpcClient.NewRequestId()
res, err := p.client.rpcClient.Request(lr.LogicalAddr, lr.PhysicalAddr, id, pb.BaseCommand_PRODUCER, &pb.CommandProducer{
RequestId: &id,
@@ -74,7 +75,7 @@ func (p *partitionProducer) grabCnx() error {
p.producerName = res.Response.ProducerSuccess.ProducerName
p.cnx = res.Cnx
- p.log.WithField("cnx", res.Cnx).Info("Created producer")
+ p.log.WithField("cnx", res.Cnx).Debug("Connected producer")
return nil
}
@@ -83,7 +84,7 @@ func (p *partitionProducer) run() {
i := <-p.eventsChan
switch v := i.(type) {
case *sendRequest:
- p.log.Info("Received send request: ", v)
+ p.log.Debug("Received send request: ", v)
v.callback(nil, v.msg, nil)
}
}
[pulsar-client-go] 20/38: Completed lookup service with tests
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit b924b7823c4b971222ddeee9a6e31a236c3bba2f
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Fri May 3 15:52:50 2019 -0700
Completed lookup service with tests
---
pulsar/impl/lookup_service.go | 73 +++++++----
pulsar/impl/lookup_service_test.go | 249 +++++++++++++++++++++++++++++++++++++
2 files changed, 300 insertions(+), 22 deletions(-)
diff --git a/pulsar/impl/lookup_service.go b/pulsar/impl/lookup_service.go
index e3753d9..3dfe758 100644
--- a/pulsar/impl/lookup_service.go
+++ b/pulsar/impl/lookup_service.go
@@ -3,6 +3,7 @@ package impl
import (
"errors"
"fmt"
+ "github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
"net/url"
pb "pulsar-client-go-native/pulsar/pulsar_proto"
@@ -29,17 +30,34 @@ func NewLookupService(rpcClient RpcClient, serviceUrl *url.URL) LookupService {
}
}
+func (ls *lookupService) getBrokerAddress(lr *pb.CommandLookupTopicResponse) (logicalAddress *url.URL, physicalAddress *url.URL, err error) {
+ logicalAddress, err = url.ParseRequestURI(lr.GetBrokerServiceUrl())
+ if err != nil {
+ return nil, nil, err
+ }
+
+ var physicalAddr *url.URL
+ if lr.GetProxyThroughServiceUrl() {
+ physicalAddr = ls.serviceUrl
+ } 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) {
- // Follow brokers redirect up to certain number of times
- const lookupResultMaxRedirect = 20
+ id := ls.rpcClient.NewRequestId()
+ res, err := ls.rpcClient.RequestToAnyBroker(id, pb.BaseCommand_LOOKUP, &pb.CommandLookupTopic{
+ RequestId: &id,
+ Topic: &topic,
+ Authoritative: proto.Bool(false),
+ })
for i := 0; i < lookupResultMaxRedirect; i++ {
- id := ls.rpcClient.NewRequestId()
- res, err := ls.rpcClient.RequestToAnyBroker(id, pb.BaseCommand_LOOKUP, &pb.CommandLookupTopic{
- RequestId: &id,
- Topic: &topic,
- })
-
if err != nil {
return nil, err
}
@@ -47,38 +65,49 @@ func (ls *lookupService) Lookup(topic string) (*LookupResult, error) {
log.WithField("topic", topic).Debugf("Got topic lookup response: %s", res)
lr := res.Response.LookupTopicResponse
switch *lr.Response {
+
case pb.CommandLookupTopicResponse_Redirect:
- // TODO: Handle redirects
+ logicalAddress, physicalAddr, err := ls.getBrokerAddress(lr)
+ if err != nil {
+ return nil, err
+ }
+
log.WithField("topic", topic).Debugf("Follow redirect to broker. %v / %v - Use proxy: %v",
lr.BrokerServiceUrl, lr.BrokerServiceUrlTls, lr.ProxyThroughServiceUrl)
- break
+
+ id := ls.rpcClient.NewRequestId()
+ res, err = ls.rpcClient.Request(logicalAddress, physicalAddr, id, pb.BaseCommand_LOOKUP, &pb.CommandLookupTopic{
+ RequestId: &id,
+ Topic: &topic,
+ Authoritative: lr.Authoritative,
+ })
+
+ // Process the response at the top of the loop
+ continue
case pb.CommandLookupTopicResponse_Connect:
log.WithField("topic", topic).Debugf("Successfully looked up topic on broker. %s / %s - Use proxy: %t",
lr.GetBrokerServiceUrl(), lr.GetBrokerServiceUrlTls(), lr.GetProxyThroughServiceUrl())
- logicalAddress, err := url.Parse(lr.GetBrokerServiceUrl())
+ logicalAddress, physicalAddress, err := ls.getBrokerAddress(lr)
if err != nil {
return nil, err
}
- var physicalAddr *url.URL
- if lr.GetProxyThroughServiceUrl() {
- physicalAddr = ls.serviceUrl
- } else {
- physicalAddr = logicalAddress
- }
return &LookupResult{
LogicalAddr: logicalAddress,
- PhysicalAddr: physicalAddr,
+ PhysicalAddr: physicalAddress,
}, nil
case pb.CommandLookupTopicResponse_Failed:
- log.WithField("topic", topic).Warn("Failed to lookup topic",
- lr.Error.String())
- return nil, errors.New(fmt.Sprintf("failed to lookup topic: %s", lr.Error.String()))
+ errorMsg := ""
+ if lr.Error != nil {
+ errorMsg = lr.Error.String()
+ }
+ log.WithField("topic", topic).Warn("Failed to lookup topic", errorMsg)
+ return nil, errors.New(fmt.Sprintf("failed to lookup topic: %s", errorMsg))
}
}
- return nil, nil
+ return nil, errors.New("exceeded max number of redirection during topic lookup")
}
diff --git a/pulsar/impl/lookup_service_test.go b/pulsar/impl/lookup_service_test.go
new file mode 100644
index 0000000..7e18198
--- /dev/null
+++ b/pulsar/impl/lookup_service_test.go
@@ -0,0 +1,249 @@
+package impl
+
+import (
+ "github.com/golang/protobuf/proto"
+ "github.com/stretchr/testify/assert"
+ "net/url"
+ pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ "testing"
+)
+
+type mockedRpcClient struct {
+ requestIdGenerator uint64
+ t *testing.T
+
+ expectedUrl string
+ expectedRequests []pb.CommandLookupTopic
+ mockedResponses []pb.CommandLookupTopicResponse
+}
+
+// Create a new unique request id
+func (c *mockedRpcClient) NewRequestId() uint64 {
+ c.requestIdGenerator += 1
+ return c.requestIdGenerator
+}
+
+func (c *mockedRpcClient) NewProducerId() uint64 {
+ return 1
+}
+
+func (c *mockedRpcClient) NewConsumerId() uint64 {
+ return 1
+}
+
+func (c *mockedRpcClient) RequestToAnyBroker(requestId uint64, cmdType pb.BaseCommand_Type, message proto.Message) (*RpcResult, error) {
+ assert.Equal(c.t, cmdType, pb.BaseCommand_LOOKUP)
+
+ expectedRequest := &c.expectedRequests[0]
+ c.expectedRequests = c.expectedRequests[1:]
+
+ assert.Equal(c.t, expectedRequest, message)
+
+ mockedResponse := &c.mockedResponses[0]
+ c.mockedResponses = c.mockedResponses[1:]
+
+ return &RpcResult{
+ &pb.BaseCommand{
+ LookupTopicResponse: mockedResponse,
+ },
+ nil,
+ }, nil
+}
+
+func (c *mockedRpcClient) Request(logicalAddr *url.URL, physicalAddr *url.URL, requestId uint64,
+ cmdType pb.BaseCommand_Type, message proto.Message) (*RpcResult, error) {
+ assert.Equal(c.t, cmdType, pb.BaseCommand_LOOKUP)
+ expectedRequest := &c.expectedRequests[0]
+ c.expectedRequests = c.expectedRequests[1:]
+
+ assert.Equal(c.t, expectedRequest, message)
+
+ mockedResponse := &c.mockedResponses[0]
+ c.mockedResponses = c.mockedResponses[1:]
+
+ assert.Equal(c.t, c.expectedUrl, logicalAddr.String())
+ assert.Equal(c.t, c.expectedUrl, physicalAddr.String())
+
+ return &RpcResult{
+ &pb.BaseCommand{
+ LookupTopicResponse: mockedResponse,
+ },
+ nil,
+ }, nil
+}
+
+func (c *mockedRpcClient) RequestOnCnx(cnx Connection, requestId uint64, cmdType pb.BaseCommand_Type, message proto.Message) (*RpcResult, error) {
+ assert.Fail(c.t, "Shouldn't be called")
+ return nil, nil
+}
+
+func responseType(r pb.CommandLookupTopicResponse_LookupType) *pb.CommandLookupTopicResponse_LookupType {
+ return &r
+}
+
+func TestLookupSuccess(t *testing.T) {
+ url, err := url.Parse("pulsar://example:6650")
+ assert.NoError(t, err)
+
+ ls := NewLookupService(&mockedRpcClient{
+ t: t,
+
+ expectedRequests: []pb.CommandLookupTopic{
+ {
+ RequestId: proto.Uint64(1),
+ Topic: proto.String("my-topic"),
+ Authoritative: proto.Bool(false),
+ },
+ },
+ mockedResponses: []pb.CommandLookupTopicResponse{
+ {
+ RequestId: proto.Uint64(1),
+ Response: responseType(pb.CommandLookupTopicResponse_Connect),
+ Authoritative: proto.Bool(true),
+ BrokerServiceUrl: proto.String("pulsar://broker-1:6650"),
+ },
+ },
+ }, url)
+
+ lr, err := ls.Lookup("my-topic")
+ assert.NoError(t, err)
+ assert.NotNil(t, lr)
+
+ assert.Equal(t, "pulsar://broker-1:6650", lr.LogicalAddr.String())
+ assert.Equal(t, "pulsar://broker-1:6650", lr.PhysicalAddr.String())
+}
+
+func TestLookupWithProxy(t *testing.T) {
+ url, err := url.Parse("pulsar://example:6650")
+ assert.NoError(t, err)
+
+ ls := NewLookupService(&mockedRpcClient{
+ t: t,
+
+ expectedRequests: []pb.CommandLookupTopic{
+ {
+ RequestId: proto.Uint64(1),
+ Topic: proto.String("my-topic"),
+ Authoritative: proto.Bool(false),
+ },
+ },
+ mockedResponses: []pb.CommandLookupTopicResponse{
+ {
+ RequestId: proto.Uint64(1),
+ Response: responseType(pb.CommandLookupTopicResponse_Connect),
+ Authoritative: proto.Bool(true),
+ BrokerServiceUrl: proto.String("pulsar://broker-1:6650"),
+ ProxyThroughServiceUrl: proto.Bool(true),
+ },
+ },
+ }, url)
+
+ lr, err := ls.Lookup("my-topic")
+ assert.NoError(t, err)
+ assert.NotNil(t, lr)
+
+ assert.Equal(t, "pulsar://broker-1:6650", lr.LogicalAddr.String())
+ assert.Equal(t, "pulsar://example:6650", lr.PhysicalAddr.String())
+}
+
+func TestLookupWithRedirect(t *testing.T) {
+ url, err := url.Parse("pulsar://example:6650")
+ assert.NoError(t, err)
+
+ ls := NewLookupService(&mockedRpcClient{
+ t: t,
+ expectedUrl: "pulsar://broker-2:6650",
+
+ expectedRequests: []pb.CommandLookupTopic{
+ {
+ RequestId: proto.Uint64(1),
+ Topic: proto.String("my-topic"),
+ Authoritative: proto.Bool(false),
+ },
+ {
+ RequestId: proto.Uint64(2),
+ Topic: proto.String("my-topic"),
+ Authoritative: proto.Bool(true),
+ },
+ },
+ mockedResponses: []pb.CommandLookupTopicResponse{
+ {
+ RequestId: proto.Uint64(1),
+ Response: responseType(pb.CommandLookupTopicResponse_Redirect),
+ Authoritative: proto.Bool(true),
+ BrokerServiceUrl: proto.String("pulsar://broker-2:6650"),
+ },
+ {
+ RequestId: proto.Uint64(2),
+ Response: responseType(pb.CommandLookupTopicResponse_Connect),
+ Authoritative: proto.Bool(true),
+ BrokerServiceUrl: proto.String("pulsar://broker-1:6650"),
+ },
+ },
+ }, url)
+
+ lr, err := ls.Lookup("my-topic")
+ assert.NoError(t, err)
+ assert.NotNil(t, lr)
+
+ assert.Equal(t, "pulsar://broker-1:6650", lr.LogicalAddr.String())
+ assert.Equal(t, "pulsar://broker-1:6650", lr.PhysicalAddr.String())
+}
+
+func TestLookupWithInvalidUrlResponse(t *testing.T) {
+ url, err := url.Parse("pulsar://example:6650")
+ assert.NoError(t, err)
+
+ ls := NewLookupService(&mockedRpcClient{
+ t: t,
+
+ expectedRequests: []pb.CommandLookupTopic{
+ {
+ RequestId: proto.Uint64(1),
+ Topic: proto.String("my-topic"),
+ Authoritative: proto.Bool(false),
+ },
+ },
+ mockedResponses: []pb.CommandLookupTopicResponse{
+ {
+ RequestId: proto.Uint64(1),
+ Response: responseType(pb.CommandLookupTopicResponse_Connect),
+ Authoritative: proto.Bool(true),
+ BrokerServiceUrl: proto.String("foo.html") /* invalid url */,
+ ProxyThroughServiceUrl: proto.Bool(false),
+ },
+ },
+ }, url)
+
+ lr, err := ls.Lookup("my-topic")
+ assert.Error(t, err)
+ assert.Nil(t, lr)
+}
+
+func TestLookupWithLookupFailure(t *testing.T) {
+ url, err := url.Parse("pulsar://example:6650")
+ assert.NoError(t, err)
+
+ ls := NewLookupService(&mockedRpcClient{
+ t: t,
+
+ expectedRequests: []pb.CommandLookupTopic{
+ {
+ RequestId: proto.Uint64(1),
+ Topic: proto.String("my-topic"),
+ Authoritative: proto.Bool(false),
+ },
+ },
+ mockedResponses: []pb.CommandLookupTopicResponse{
+ {
+ RequestId: proto.Uint64(1),
+ Response: responseType(pb.CommandLookupTopicResponse_Failed),
+ Authoritative: proto.Bool(true),
+ },
+ },
+ }, url)
+
+ lr, err := ls.Lookup("my-topic")
+ assert.Error(t, err)
+ assert.Nil(t, lr)
+}
[pulsar-client-go] 36/38: TLS Auth provider
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit 1a6dfaae40f93e6e1f59f1bfa66610c66620f931
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Wed May 8 17:28:43 2019 -0700
TLS Auth provider
---
pulsar/client.go | 4 ++
pulsar/impl_client.go | 16 +++++-
pulsar/impl_client_test.go | 36 ++++++++++++
.../{test_helper.go => internal/auth/disabled.go} | 37 +++++++++----
.../{test_helper.go => internal/auth/provider.go} | 42 +++++++++++---
pulsar/internal/auth/tls.go | 64 ++++++++++++++++++++++
pulsar/internal/connection.go | 27 +++++++--
pulsar/internal/connection_pool.go | 8 ++-
pulsar/test_helper.go | 8 ++-
9 files changed, 213 insertions(+), 29 deletions(-)
diff --git a/pulsar/client.go b/pulsar/client.go
index d870dcd..1a838ac 100644
--- a/pulsar/client.go
+++ b/pulsar/client.go
@@ -31,6 +31,10 @@ func NewClient(options ClientOptions) (Client, error) {
// Opaque interface that represents the authentication credentials
type Authentication interface{}
+func NewAuthentication(name string, params string) (Authentication, error) {
+ return auth.NewProvider(name, params)
+}
+
// Create new Authentication provider with specified auth token
func NewAuthenticationToken(token string) Authentication {
// TODO: return newAuthenticationToken(token)
diff --git a/pulsar/impl_client.go b/pulsar/impl_client.go
index 9a3ee7d..b84ac82 100644
--- a/pulsar/impl_client.go
+++ b/pulsar/impl_client.go
@@ -28,6 +28,7 @@ import (
"io/ioutil"
"net/url"
"pulsar-client-go/pulsar/internal"
+ "pulsar-client-go/pulsar/internal/auth"
pb "pulsar-client-go/pulsar/internal/pulsar_proto"
)
@@ -37,6 +38,7 @@ type client struct {
cnxPool internal.ConnectionPool
rpcClient internal.RpcClient
lookupService internal.LookupService
+ auth auth.Provider
handlers map[internal.Closable]bool
producerIdGenerator uint64
@@ -70,8 +72,20 @@ func newClient(options ClientOptions) (Client, error) {
return nil, newError(ResultInvalidConfiguration, 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, errors.New("invalid auth provider interface")
+ }
+ }
+
c := &client{
- cnxPool: internal.NewConnectionPool(tlsConfig),
+ cnxPool: internal.NewConnectionPool(tlsConfig, authProvider),
}
c.rpcClient = internal.NewRpcClient(url, c.cnxPool)
c.lookupService = internal.NewLookupService(c.rpcClient, url)
diff --git a/pulsar/impl_client_test.go b/pulsar/impl_client_test.go
index 9fd4231..218587f 100644
--- a/pulsar/impl_client_test.go
+++ b/pulsar/impl_client_test.go
@@ -125,3 +125,39 @@ func TestTLSConnectionHostNameVerificationError(t *testing.T) {
assert.NoError(t, err)
}
+func TestTLSAuthError(t *testing.T) {
+ client, err := NewClient(ClientOptions{
+ URL: serviceUrlTls,
+ TLSTrustCertsFilePath: caCertsPath,
+ })
+ assert.NoError(t, err)
+
+ producer, err := client.CreateProducer(ProducerOptions{
+ Topic: newAuthTopicName(),
+ })
+
+ assert.Error(t, err)
+ assert.Nil(t, producer)
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
+
+func TestTLSAuth(t *testing.T) {
+ client, err := NewClient(ClientOptions{
+ URL: serviceUrlTls,
+ TLSTrustCertsFilePath: caCertsPath,
+ Authentication: NewAuthenticationTLS(tlsClientCertPath, tlsClientKeyPath),
+ })
+ assert.NoError(t, err)
+
+ producer, err := client.CreateProducer(ProducerOptions{
+ Topic: newAuthTopicName(),
+ })
+
+ assert.NoError(t, err)
+ assert.NotNil(t, producer)
+
+ err = client.Close()
+ assert.NoError(t, err)
+}
diff --git a/pulsar/test_helper.go b/pulsar/internal/auth/disabled.go
similarity index 67%
copy from pulsar/test_helper.go
copy to pulsar/internal/auth/disabled.go
index c6c78e1..7d8bbf7 100644
--- a/pulsar/test_helper.go
+++ b/pulsar/internal/auth/disabled.go
@@ -17,20 +17,33 @@
// under the License.
//
-package pulsar
+package auth
-import (
- "fmt"
- "time"
-)
+import "crypto/tls"
-const (
- serviceUrl = "pulsar://localhost:6650"
- serviceUrlTls = "pulsar+ssl://localhost:6651"
+type disabled struct {
+}
+
+func NewAuthDisabled() Provider {
+ return &disabled{}
+}
+
+func (disabled) Init() error {
+ return nil
+}
- caCertsPath = "../integration-tests/certs/cacert.pem"
-)
+func (disabled) GetData() ([]byte, error) {
+ return nil, nil
+}
+
+func (disabled) Name() string {
+ return ""
+}
+
+func (disabled) GetTlsCertificate() (*tls.Certificate, error) {
+ return nil, nil
+}
-func newTopicName() string {
- return fmt.Sprintf("my-topic-%v", time.Now().Nanosecond())
+func (disabled) Close() error {
+ return nil
}
diff --git a/pulsar/test_helper.go b/pulsar/internal/auth/provider.go
similarity index 54%
copy from pulsar/test_helper.go
copy to pulsar/internal/auth/provider.go
index c6c78e1..c23a662 100644
--- a/pulsar/test_helper.go
+++ b/pulsar/internal/auth/provider.go
@@ -17,20 +17,44 @@
// under the License.
//
-package pulsar
+package auth
import (
+ "crypto/tls"
"fmt"
- "time"
+ "github.com/pkg/errors"
+ "io"
)
-const (
- serviceUrl = "pulsar://localhost:6650"
- serviceUrlTls = "pulsar+ssl://localhost:6651"
+type Provider interface {
+ Init() error
- caCertsPath = "../integration-tests/certs/cacert.pem"
-)
+ Name() string
+
+ // return a client certificate chain, or nil if the data are not available
+ GetTlsCertificate() (*tls.Certificate, error)
+
+ //
+ GetData() ([]byte, error)
+
+ io.Closer
+}
+
+func NewProvider(name string, params string) (Provider, error) {
+ m := parseParams(params)
+
+ switch name {
+ case "":
+ return NewAuthDisabled(), nil
+
+ case "tls", "org.apache.pulsar.client.impl.auth.AuthenticationTls":
+ return NewAuthenticationTLSWithParams(m), nil
+
+ default:
+ return nil, errors.New(fmt.Sprintf("invalid auth provider '%s'", name))
+ }
+}
-func newTopicName() string {
- return fmt.Sprintf("my-topic-%v", time.Now().Nanosecond())
+func parseParams(params string) map[string]string {
+ return nil
}
diff --git a/pulsar/internal/auth/tls.go b/pulsar/internal/auth/tls.go
new file mode 100644
index 0000000..2f7e262
--- /dev/null
+++ b/pulsar/internal/auth/tls.go
@@ -0,0 +1,64 @@
+//
+// 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"
+
+type tlsAuthProvider struct {
+ certificatePath string
+ privateKeyPath string
+}
+
+func NewAuthenticationTLSWithParams(params map[string]string) Provider {
+ return NewAuthenticationTLS(
+ params["tlsCertFile"],
+ params["tlsKeyFile"],
+ )
+}
+
+func NewAuthenticationTLS(certificatePath string, privateKeyPath string) Provider {
+ return &tlsAuthProvider{
+ certificatePath: certificatePath,
+ privateKeyPath: privateKeyPath,
+ }
+}
+
+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) {
+ 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
+}
diff --git a/pulsar/internal/connection.go b/pulsar/internal/connection.go
index fdcfd60..07b1d68 100644
--- a/pulsar/internal/connection.go
+++ b/pulsar/internal/connection.go
@@ -28,6 +28,7 @@ import (
"io/ioutil"
"net"
"net/url"
+ "pulsar-client-go/pulsar/internal/auth"
pb "pulsar-client-go/pulsar/internal/pulsar_proto"
"sync"
"sync/atomic"
@@ -99,9 +100,10 @@ type connection struct {
listeners map[uint64]ConnectionListener
tlsOptions *TLSOptions
+ auth auth.Provider
}
-func newConnection(logicalAddr *url.URL, physicalAddr *url.URL, tlsOptions *TLSOptions) *connection {
+func newConnection(logicalAddr *url.URL, physicalAddr *url.URL, tlsOptions *TLSOptions, auth auth.Provider) *connection {
cnx := &connection{
state: connectionInit,
logicalAddr: logicalAddr,
@@ -112,6 +114,7 @@ func newConnection(logicalAddr *url.URL, physicalAddr *url.URL, tlsOptions *TLSO
lastDataReceivedTime: time.Now(),
pingTicker: time.NewTicker(keepAliveInterval),
tlsOptions: tlsOptions,
+ auth: auth,
incomingRequests: make(chan *request),
writeRequests: make(chan []byte),
@@ -151,7 +154,7 @@ func (c *connection) connect() (ok bool) {
cnx, err = net.Dial("tcp", c.physicalAddr.Host)
} else {
// TLS connection
- tlsConfig, err = c.getTlsConfig()
+ tlsConfig, err = c.getTlsConfig()
if err != nil {
c.log.WithError(err).Warn("Failed to configure TLS ")
return false
@@ -176,11 +179,18 @@ func (c *connection) connect() (ok bool) {
func (c *connection) doHandshake() (ok bool) {
// Send 'Connect' command to initiate handshake
version := int32(pb.ProtocolVersion_v13)
+
+ authData, err := c.auth.GetData()
+ if err != nil {
+ c.log.WithError(err).Warn("Failed to load auth credentials")
+ return false
+ }
+
c.writeCommand(baseCommand(pb.BaseCommand_CONNECT, &pb.CommandConnect{
ProtocolVersion: &version,
ClientVersion: proto.String("Pulsar Go 0.1"),
- // AuthMethodName: "token",
- // AuthData: authData,
+ AuthMethodName: proto.String(c.auth.Name()),
+ AuthData: authData,
}))
cmd, _, err := c.reader.readSingleCommand()
@@ -461,5 +471,14 @@ func (c *connection) getTlsConfig() (*tls.Config, error) {
tlsConfig.ServerName = c.physicalAddr.Hostname()
}
+ cert, err := c.auth.GetTlsCertificate()
+ if err != nil {
+ return nil, err
+ }
+
+ if cert != nil {
+ tlsConfig.Certificates = []tls.Certificate{*cert}
+ }
+
return tlsConfig, nil
}
diff --git a/pulsar/internal/connection_pool.go b/pulsar/internal/connection_pool.go
index 6540137..b8cdd0f 100644
--- a/pulsar/internal/connection_pool.go
+++ b/pulsar/internal/connection_pool.go
@@ -22,6 +22,7 @@ package internal
import (
log "github.com/sirupsen/logrus"
"net/url"
+ "pulsar-client-go/pulsar/internal/auth"
"sync"
)
@@ -35,11 +36,13 @@ type ConnectionPool interface {
type connectionPool struct {
pool sync.Map
tlsOptions *TLSOptions
+ auth auth.Provider
}
-func NewConnectionPool(tlsOptions *TLSOptions) ConnectionPool {
+func NewConnectionPool(tlsOptions *TLSOptions, auth auth.Provider) ConnectionPool {
return &connectionPool{
tlsOptions: tlsOptions,
+ auth: auth,
}
}
@@ -60,7 +63,8 @@ func (p *connectionPool) GetConnection(logicalAddr *url.URL, physicalAddr *url.U
}
// Try to create a new connection
- newCnx, wasCached := p.pool.LoadOrStore(logicalAddr.Host, newConnection(logicalAddr, physicalAddr, p.tlsOptions))
+ newCnx, wasCached := p.pool.LoadOrStore(logicalAddr.Host,
+ newConnection(logicalAddr, physicalAddr, p.tlsOptions, p.auth))
cnx := newCnx.(*connection)
if !wasCached {
cnx.start()
diff --git a/pulsar/test_helper.go b/pulsar/test_helper.go
index c6c78e1..1e84a92 100644
--- a/pulsar/test_helper.go
+++ b/pulsar/test_helper.go
@@ -28,9 +28,15 @@ const (
serviceUrl = "pulsar://localhost:6650"
serviceUrlTls = "pulsar+ssl://localhost:6651"
- caCertsPath = "../integration-tests/certs/cacert.pem"
+ caCertsPath = "../integration-tests/certs/cacert.pem"
+ tlsClientCertPath = "../integration-tests/certs/client-cert.pem"
+ tlsClientKeyPath = "../integration-tests/certs/client-key.pem"
)
func newTopicName() string {
return fmt.Sprintf("my-topic-%v", time.Now().Nanosecond())
}
+
+func newAuthTopicName() string {
+ return fmt.Sprintf("private/auth/my-topic-%v", time.Now().Nanosecond())
+}
[pulsar-client-go] 11/38: Added blocking queue implementation
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit b95a97191e2a5c63d67ab41940dcd57c1032c7ee
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Tue Apr 9 21:28:31 2019 -0700
Added blocking queue implementation
---
pulsar/impl/util/blocking_queue.go | 125 ++++++++++++++++++++++++++++++++
pulsar/impl/util/blocking_queue_test.go | 97 +++++++++++++++++++++++++
2 files changed, 222 insertions(+)
diff --git a/pulsar/impl/util/blocking_queue.go b/pulsar/impl/util/blocking_queue.go
new file mode 100644
index 0000000..281d6ba
--- /dev/null
+++ b/pulsar/impl/util/blocking_queue.go
@@ -0,0 +1,125 @@
+package util
+
+import (
+ "sync"
+)
+
+type BlockingQueue interface {
+ // Enqueue one item, block if the queue is full
+ Put(item interface{})
+
+ // Dequeue one item, block until it's available
+ Take() interface{}
+
+ // Dequeue one item, return nil if queue is empty
+ Poll() interface{}
+
+ // Return one item without dequeing, return nil if queue is empty
+ Peek() interface{}
+
+ // Return the current size of the queue
+ Size() int
+}
+
+type blockingQueue struct {
+ items []interface{}
+ headIdx int
+ tailIdx int
+ size int
+ maxSize int
+
+ mutex sync.Mutex
+ isNotEmpty *sync.Cond
+ isNotFull *sync.Cond
+}
+
+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 += 1
+ bq.tailIdx += 1
+ 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) Peek() interface{} {
+ bq.mutex.Lock()
+ defer bq.mutex.Unlock()
+
+ if bq.size == 0 {
+ return nil
+ } else {
+ return bq.items[bq.headIdx]
+ }
+}
+
+func (bq *blockingQueue) dequeue() interface{} {
+ item := bq.items[bq.headIdx]
+ bq.items[bq.headIdx] = nil
+
+ bq.headIdx += 1
+ if bq.headIdx == len(bq.items) {
+ bq.headIdx = 0
+ }
+
+ bq.size -= 1
+ bq.isNotFull.Signal()
+ return item
+}
+
+func (bq *blockingQueue) Size() int {
+ bq.mutex.Lock()
+ defer bq.mutex.Unlock()
+
+ return bq.size
+}
diff --git a/pulsar/impl/util/blocking_queue_test.go b/pulsar/impl/util/blocking_queue_test.go
new file mode 100644
index 0000000..0ecc8d1
--- /dev/null
+++ b/pulsar/impl/util/blocking_queue_test.go
@@ -0,0 +1,97 @@
+package util
+
+import (
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestBlockingQueue(t *testing.T) {
+ q := NewBlockingQueue(10)
+
+ assert.Equal(t, 0, q.Size())
+ assert.Equal(t, nil, q.Poll())
+ assert.Equal(t, nil, q.Peek())
+
+ q.Put("test")
+ assert.Equal(t, 1, q.Size())
+
+ assert.Equal(t, "test", q.Peek())
+ assert.Equal(t, 1, q.Size())
+
+ assert.Equal(t, "test", q.Take())
+ assert.Equal(t, 0, q.Size())
+
+ ch := make(chan string)
+
+ go func() {
+ // Stays blocked until item is available
+ ch <- q.Take().(string)
+ }()
+
+ time.Sleep(100 * time.Millisecond)
+
+ select {
+ case _ = <-ch:
+ assert.Fail(t, "Should not have had a value at this point")
+ default:
+ // Good, no value yet
+ }
+
+ q.Put("test-2")
+
+ x := <-ch
+ assert.Equal(t, "test-2", x)
+
+ // Fill the queue
+ for i := 0; i < 10; i++ {
+ q.Put(fmt.Sprintf("i-%d", i))
+ assert.Equal(t, i+1, q.Size())
+ }
+
+ for i := 0; i < 10; i++ {
+ assert.Equal(t, fmt.Sprintf("i-%d", i), q.Take())
+ }
+
+ close(ch)
+}
+
+func TestBlockingQueueWaitWhenFull(t *testing.T) {
+ q := NewBlockingQueue(3)
+
+ q.Put("test-1")
+ q.Put("test-2")
+ q.Put("test-3")
+ assert.Equal(t, 3, q.Size())
+
+ ch := make(chan bool)
+
+ go func() {
+ // Stays blocked until space is available
+ q.Put("test-4")
+ ch <- true
+ }()
+
+ time.Sleep(100 * time.Millisecond)
+
+ select {
+ case _ = <-ch:
+ assert.Fail(t, "Should not have had a value at this point")
+ default:
+ // Good, no value yet
+ }
+
+ assert.Equal(t, "test-1", q.Poll())
+
+ // Now the go-routine should have completed
+ _ = <-ch
+ assert.Equal(t, 3, q.Size())
+
+ assert.Equal(t, "test-2", q.Take())
+ assert.Equal(t, "test-3", q.Take())
+ assert.Equal(t, "test-4", q.Take())
+
+ close(ch)
+}
[pulsar-client-go] 09/38: Basic publishing works
Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git
commit f7cac7a6506b0091b9a5a291c48b968603a1c07a
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Fri Apr 5 15:38:20 2019 -0700
Basic publishing works
---
pulsar/impl/batch_builder.go | 92 +++++++++++++++++++++++++++++++++++---
pulsar/impl/buffer.go | 39 ++++++++++++++++
pulsar/impl/checksum.go | 9 ++++
pulsar/impl/commands.go | 61 +++++++++++++++++++++++++
pulsar/impl/connection.go | 42 +++++++++++++----
pulsar/impl/utils.go | 20 +++++++++
pulsar/impl_partition_producer.go | 94 +++++++++++++++++++++++++++++++++------
pulsar/message.go | 4 +-
8 files changed, 331 insertions(+), 30 deletions(-)
diff --git a/pulsar/impl/batch_builder.go b/pulsar/impl/batch_builder.go
index 7eb2030..6b0df8e 100644
--- a/pulsar/impl/batch_builder.go
+++ b/pulsar/impl/batch_builder.go
@@ -1,23 +1,101 @@
package impl
+import (
+ "github.com/golang/protobuf/proto"
+ log "github.com/sirupsen/logrus"
+ pb "pulsar-client-go-native/pulsar/pulsar_proto"
+ "time"
+)
+
+const MaxMessageSize = 5 * 1024 * 1024
+
+const MaxBatchSize = 128 * 1024
+
+const DefaultMaxMessagesPerBatch = 1000
+
type BatchBuilder struct {
buffer Buffer
+
+ // Current number of messages in the batch
+ numMessages uint
+
+ // Max number of message allowed in the batch
+ maxMessages uint
+
+ producerName string
+ producerId uint64
+
+ cmdSend *pb.BaseCommand
+ msgMetadata *pb.MessageMetadata
}
-func NewBatchBuilder() *BatchBuilder {
+func NewBatchBuilder(maxMessages uint, producerName string, producerId uint64) *BatchBuilder {
+ if maxMessages == 0 {
+ maxMessages = DefaultMaxMessagesPerBatch
+ }
return &BatchBuilder{
- buffer: NewBuffer(4096),
+ buffer: NewBuffer(4096),
+ numMessages: 0,
+ maxMessages: maxMessages,
+ producerName: producerName,
+ producerId: producerId,
+ cmdSend: baseCommand(pb.BaseCommand_SEND,
+ &pb.CommandSend{
+ ProducerId: &producerId,
+ }),
+ msgMetadata: &pb.MessageMetadata{
+ ProducerName: &producerName,
+ },
}
}
-func (bb *BatchBuilder) isFull() bool {
- return false
+func (bb *BatchBuilder) IsFull() bool {
+ return bb.numMessages >= bb.maxMessages || bb.buffer.ReadableBytes() > MaxBatchSize
+}
+
+func (bb *BatchBuilder) hasSpace(payload []byte) bool {
+ msgSize := uint32(len(payload))
+ return bb.numMessages > 0 && (bb.buffer.ReadableBytes()+msgSize) > MaxBatchSize
}
-func (bb *BatchBuilder) hasSpace(size int) bool {
- return false
+func (bb *BatchBuilder) Add(metadata *pb.SingleMessageMetadata, sequenceId uint64, payload []byte) bool {
+ if bb.hasSpace(payload) {
+ // The current batch is full. Producer has to call Flush() to
+ return false
+ }
+
+ if bb.numMessages == 0 {
+ bb.msgMetadata.SequenceId = proto.Uint64(sequenceId)
+ bb.msgMetadata.PublishTime = proto.Uint64(TimestampMillis(time.Now()))
+ bb.msgMetadata.SequenceId = proto.Uint64(sequenceId)
+ bb.msgMetadata.ProducerName = &bb.producerName
+
+ bb.cmdSend.Send.SequenceId = proto.Uint64(sequenceId)
+ }
+ serializeSingleMessage(bb.buffer, metadata, payload)
+
+ bb.numMessages += 1
+ return true
+}
+
+func (bb *BatchBuilder) reset() {
+ bb.numMessages = 0
+ bb.buffer.Clear()
}
func (bb *BatchBuilder) Flush() []byte {
- return nil
+ log.Info("BatchBuilder flush: messages: ", bb.numMessages)
+ if bb.numMessages == 0 {
+ // No-Op for empty batch
+ return nil
+ }
+
+ bb.msgMetadata.NumMessagesInBatch = proto.Int32(int32(bb.numMessages))
+ bb.cmdSend.Send.NumMessages = proto.Int32(int32(bb.numMessages))
+
+ buffer := NewBuffer(4096)
+ serializeBatch(buffer, bb.cmdSend, bb.msgMetadata, bb.buffer.ReadableSlice())
+
+ bb.reset()
+ return buffer.ReadableSlice()
}
diff --git a/pulsar/impl/buffer.go b/pulsar/impl/buffer.go
index 8e81f0c..3d03002 100644
--- a/pulsar/impl/buffer.go
+++ b/pulsar/impl/buffer.go
@@ -13,6 +13,8 @@ type Buffer interface {
Read(size uint32) []byte
+ Get(readerIndex uint32, size uint32) []byte
+
ReadableSlice() []byte
WritableSlice() []byte
@@ -23,12 +25,20 @@ type Buffer interface {
// 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)
Clear()
@@ -71,6 +81,10 @@ func (b *buffer) Read(size uint32) []byte {
return res
}
+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]
}
@@ -83,6 +97,14 @@ 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))
@@ -103,16 +125,33 @@ 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) {
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) {
+ binary.BigEndian.PutUint16(b.WritableSlice(), n)
+ b.writerIdx += 2
+}
+
func (b *buffer) Write(s []byte) {
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/pulsar/impl/checksum.go b/pulsar/impl/checksum.go
new file mode 100644
index 0000000..cbea686
--- /dev/null
+++ b/pulsar/impl/checksum.go
@@ -0,0 +1,9 @@
+package impl
+
+import "hash/crc32"
+
+var crc32cTable = crc32.MakeTable(crc32.Castagnoli)
+
+func Crc32cCheckSum(data []byte) uint32 {
+ return crc32.Checksum(data, crc32cTable)
+}
\ No newline at end of file
diff --git a/pulsar/impl/commands.go b/pulsar/impl/commands.go
index ed9f6b9..6b1c840 100644
--- a/pulsar/impl/commands.go
+++ b/pulsar/impl/commands.go
@@ -8,6 +8,8 @@ import (
const MaxFrameSize = 5 * 1024 * 1024
+const magicCrc32c uint16 = 0x0e01
+
func baseCommand(cmdType pb.BaseCommand_Type, msg proto.Message) *pb.BaseCommand {
cmd := &pb.BaseCommand{
Type: &cmdType,
@@ -25,6 +27,8 @@ func baseCommand(cmdType pb.BaseCommand_Type, msg proto.Message) *pb.BaseCommand
cmd.Ping = msg.(*pb.CommandPing)
case pb.BaseCommand_PONG:
cmd.Pong = msg.(*pb.CommandPong)
+ case pb.BaseCommand_SEND:
+ cmd.Send = msg.(*pb.CommandSend)
default:
log.Panic("Missing command type: ", cmdType)
}
@@ -32,6 +36,63 @@ func baseCommand(cmdType pb.BaseCommand_Type, msg proto.Message) *pb.BaseCommand
return cmd
}
+func serializeSingleMessage(wb Buffer, smm *pb.SingleMessageMetadata, payload []byte) {
+ serialized, err := proto.Marshal(smm)
+ if err != nil {
+ log.WithError(err).Fatal("Protobuf serialization error")
+ }
+
+ wb.Write(serialized)
+ wb.Write(payload)
+}
+
+func serializeBatch(wb Buffer, cmdSend *pb.BaseCommand, msgMetadata *pb.MessageMetadata, payload []byte) {
+ // Wire format
+ // [TOTAL_SIZE] [CMD_SIZE][CMD] [MAGIC_NUMBER][CHECKSUM] [METADATA_SIZE][METADATA] [PAYLOAD]
+ cmdSize := proto.Size(cmdSend)
+ msgMetadataSize := proto.Size(msgMetadata)
+ payloadSize := len(payload)
+
+ magicAndChecksumLength := 2 + 4 /* magic + checksumLength */
+ headerContentSize := 4 + cmdSize + magicAndChecksumLength + 4 + msgMetadataSize
+ // cmdLength + cmdSize + magicLength + checksumSize + msgMetadataLength + msgMetadataSize
+ totalSize := headerContentSize + payloadSize
+
+ wb.WriteUint32(uint32(totalSize)) // External frame
+
+ // Write cmd
+ wb.WriteUint32(uint32(cmdSize))
+ serialized, err := proto.Marshal(cmdSend)
+ if err != nil {
+ log.WithError(err).Fatal("Protobuf error when serializing cmdSend")
+ }
+
+ wb.Write(serialized)
+
+ // Create checksum placeholder
+ wb.WriteUint16(magicCrc32c)
+ checksumIdx := wb.WriterIndex()
+ wb.WriteUint32(0) // skip 4 bytes of checksum
+
+ // Write metadata
+ metadataStartIdx := wb.WriterIndex()
+ wb.WriteUint32(uint32(msgMetadataSize))
+ serialized, err = proto.Marshal(msgMetadata)
+ if err != nil {
+ log.WithError(err).Fatal("Protobuf error when serializing msgMetadata")
+ }
+
+ wb.Write(serialized)
+ wb.Write(payload)
+
+ // Write checksum at created checksum-placeholder
+ endIdx := wb.WriterIndex()
+ checksum := Crc32cCheckSum(wb.Get(metadataStartIdx, endIdx-metadataStartIdx))
+
+ // set computed checksum
+ wb.PutUint32(checksum, checksumIdx)
+}
+
func ConvertFromStringMap(m map[string]string) []*pb.KeyValue {
list := make([]*pb.KeyValue, len(m))
diff --git a/pulsar/impl/connection.go b/pulsar/impl/connection.go
index 365f1b3..04fa10f 100644
--- a/pulsar/impl/connection.go
+++ b/pulsar/impl/connection.go
@@ -14,6 +14,7 @@ import (
type Connection interface {
SendRequest(requestId uint64, req *pb.BaseCommand, callback func(command *pb.BaseCommand))
+ WriteData(data []byte)
Close()
}
@@ -54,6 +55,7 @@ type connection struct {
requestIdGenerator uint64
incomingRequests chan *request
+ writeRequests chan []byte
pendingReqs map[uint64]*request
}
@@ -67,6 +69,9 @@ func newConnection(logicalAddr *url.URL, physicalAddr *url.URL) *connection {
pendingReqs: make(map[uint64]*request),
lastDataReceivedTime: time.Now(),
pingTicker: time.NewTicker(keepAliveInterval),
+
+ incomingRequests: make(chan *request),
+ writeRequests: make(chan []byte),
}
cnx.reader = newConnectionReader(cnx)
cnx.cond = sync.NewCond(cnx)
@@ -164,12 +169,27 @@ func (c *connection) run() {
c.pendingReqs[req.id] = req
c.writeCommand(req.cmd)
+ case data := <-c.writeRequests:
+ c.internalWriteData(data)
+
case _ = <-c.pingTicker.C:
c.sendPing()
}
}
}
+func (c *connection) WriteData(data []byte) {
+ c.writeRequests <- data
+}
+
+func (c *connection) internalWriteData(data []byte) {
+ c.log.Info("Write data: ", len(data))
+ if _, err := c.cnx.Write(data); err != nil {
+ c.log.WithError(err).Warn("Failed to write on connection")
+ c.Close()
+ }
+}
+
func (c *connection) writeCommand(cmd proto.Message) {
// Wire format
// [FRAME_SIZE] [CMD_SIZE][CMD]
@@ -190,11 +210,7 @@ func (c *connection) writeCommand(cmd proto.Message) {
}
c.writeBuffer.Write(serialized)
-
- if _, err := c.cnx.Write(c.writeBuffer.ReadableSlice()); err != nil {
- c.log.WithError(err).Warn("Failed to write on connection")
- c.Close()
- }
+ c.internalWriteData(c.writeBuffer.ReadableSlice())
}
func (c *connection) receivedCommand(cmd *pb.BaseCommand, headersAndPayload []byte) {
@@ -230,6 +246,8 @@ func (c *connection) receivedCommand(cmd *pb.BaseCommand, headersAndPayload []by
case pb.BaseCommand_CLOSE_PRODUCER:
case pb.BaseCommand_CLOSE_CONSUMER:
case pb.BaseCommand_SEND_RECEIPT:
+ c.log.Info("Got SEND_RECEIPT: ", cmd.GetSendReceipt())
+
case pb.BaseCommand_SEND_ERROR:
case pb.BaseCommand_MESSAGE:
@@ -246,13 +264,21 @@ func (c *connection) receivedCommand(cmd *pb.BaseCommand, headersAndPayload []by
}
}
+func (c *connection) Write(data []byte) {
+ c.writeRequests <- data
+}
+
func (c *connection) SendRequest(requestId uint64, req *pb.BaseCommand, callback func(command *pb.BaseCommand)) {
- c.pendingReqs[requestId] = &request{
+ c.incomingRequests <- &request{
id: requestId,
cmd: req,
callback: callback,
}
- c.writeCommand(req)
+}
+
+func (c *connection) internalSendRequest(req *request) {
+ c.pendingReqs[req.id] = req
+ c.writeCommand(req.cmd)
}
func (c *connection) handleResponse(requestId uint64, response *pb.BaseCommand) {
@@ -299,6 +325,7 @@ func (c *connection) Close() {
c.cnx.Close()
c.pingTicker.Stop()
close(c.incomingRequests)
+ close(c.writeRequests)
c.cnx = nil
}
}
@@ -313,4 +340,3 @@ func (c *connection) changeState(state connectionState) {
func (c *connection) newRequestId() uint64 {
return atomic.AddUint64(&c.requestIdGenerator, 1)
}
-
diff --git a/pulsar/impl/utils.go b/pulsar/impl/utils.go
new file mode 100644
index 0000000..02d15b3
--- /dev/null
+++ b/pulsar/impl/utils.go
@@ -0,0 +1,20 @@
+package impl
+
+import (
+ "sync/atomic"
+ "time"
+)
+
+func TimestampMillis(t time.Time) uint64 {
+ return uint64(t.UnixNano()) / uint64(time.Millisecond)
+}
+
+// Perform atomic read and update
+func GetAndAdd(n *uint64, diff uint64) uint64 {
+ for {
+ v := *n
+ if atomic.CompareAndSwapUint64(n, v, v+diff) {
+ return v
+ }
+ }
+}
diff --git a/pulsar/impl_partition_producer.go b/pulsar/impl_partition_producer.go
index 7bb2165..2677770 100644
--- a/pulsar/impl_partition_producer.go
+++ b/pulsar/impl_partition_producer.go
@@ -2,10 +2,12 @@ package pulsar
import (
"context"
+ "github.com/golang/protobuf/proto"
log "github.com/sirupsen/logrus"
"pulsar-client-go-native/pulsar/impl"
pb "pulsar-client-go-native/pulsar/pulsar_proto"
"sync"
+ "time"
)
type partitionProducer struct {
@@ -16,21 +18,36 @@ type partitionProducer struct {
cond *sync.Cond
cnx impl.Connection
- producerName *string
- producerId uint64
+ options *ProducerOptions
+ producerName *string
+ producerId uint64
+ batchBuilder *impl.BatchBuilder
+ sequenceIdGenerator *uint64
+ batchFlushTicker *time.Ticker
// Channel where app is posting messages to be published
eventsChan chan interface{}
}
+const defaultBatchingMaxPublishDelay = 10 * time.Millisecond
+
func newPartitionProducer(client *client, topic string, options *ProducerOptions) (*partitionProducer, error) {
+ var batchingMaxPublishDelay time.Duration
+ if options.BatchingMaxPublishDelay != 0 {
+ batchingMaxPublishDelay = options.BatchingMaxPublishDelay
+ } else {
+ batchingMaxPublishDelay = defaultBatchingMaxPublishDelay
+ }
+
p := &partitionProducer{
- log: log.WithField("topic", topic),
- client: client,
- topic: topic,
- producerId: client.rpcClient.NewProducerId(),
- eventsChan: make(chan interface{}),
+ log: log.WithField("topic", topic),
+ client: client,
+ topic: topic,
+ options: options,
+ producerId: client.rpcClient.NewProducerId(),
+ eventsChan: make(chan interface{}),
+ batchFlushTicker: time.NewTicker(batchingMaxPublishDelay),
}
if options.Name != "" {
@@ -74,6 +91,13 @@ func (p *partitionProducer) grabCnx() error {
}
p.producerName = res.Response.ProducerSuccess.ProducerName
+ if p.batchBuilder == nil {
+ p.batchBuilder = impl.NewBatchBuilder(p.options.BatchingMaxMessages, *p.producerName, p.producerId)
+ }
+ if p.sequenceIdGenerator == nil {
+ nextSequenceId := uint64(res.Response.ProducerSuccess.GetLastSequenceId() + 1)
+ p.sequenceIdGenerator = &nextSequenceId
+ }
p.cnx = res.Cnx
p.log.WithField("cnx", res.Cnx).Debug("Connected producer")
return nil
@@ -81,11 +105,15 @@ func (p *partitionProducer) grabCnx() error {
func (p *partitionProducer) run() {
for {
- i := <-p.eventsChan
- switch v := i.(type) {
- case *sendRequest:
- p.log.Debug("Received send request: ", v)
- v.callback(nil, v.msg, nil)
+ select {
+ case i := <-p.eventsChan:
+ switch v := i.(type) {
+ case *sendRequest:
+ p.internalSend(v)
+ }
+
+ case _ = <-p.batchFlushTicker.C:
+ p.internalFlush()
}
}
}
@@ -98,6 +126,47 @@ func (p *partitionProducer) Name() string {
return *p.producerName
}
+func (p *partitionProducer) internalSend(request *sendRequest) {
+ p.log.Debug("Received send request: ", *request)
+
+ msg := request.msg
+
+ if msg.ReplicationClusters == nil {
+ smm := &pb.SingleMessageMetadata{
+ PayloadSize: proto.Int(len(msg.Payload)),
+ }
+
+ if msg.EventTime != nil {
+ smm.EventTime = proto.Uint64(impl.TimestampMillis(*msg.EventTime))
+ }
+
+ if msg.Key != "" {
+ smm.PartitionKey = &msg.Key
+ }
+
+ if msg.Properties != nil {
+ smm.Properties = impl.ConvertFromStringMap(msg.Properties)
+ }
+
+ sequenceId := impl.GetAndAdd(p.sequenceIdGenerator, 1)
+ for ; p.batchBuilder.Add(smm, sequenceId, msg.Payload) == false; {
+ // The current batch is full.. flush it and retry
+ p.internalFlush()
+ }
+ } else {
+ p.log.Panic("TODO: serialize into single message")
+ }
+}
+
+func (p *partitionProducer) internalFlush() {
+ batchData := p.batchBuilder.Flush()
+ if batchData == nil {
+ return
+ }
+
+ p.cnx.WriteData(batchData)
+}
+
func (p *partitionProducer) Send(ctx context.Context, msg *ProducerMessage) error {
wg := sync.WaitGroup{}
wg.Add(1)
@@ -117,7 +186,6 @@ func (p *partitionProducer) Send(ctx context.Context, msg *ProducerMessage) erro
wg.Wait()
return err
- return nil
}
type sendRequest struct {
diff --git a/pulsar/message.go b/pulsar/message.go
index 60dd989..12bc269 100644
--- a/pulsar/message.go
+++ b/pulsar/message.go
@@ -32,13 +32,13 @@ type ProducerMessage struct {
Properties map[string]string
// Set the event time for a given message
- EventTime time.Time
+ EventTime *time.Time
// Override the replication clusters for this message.
ReplicationClusters []string
// Set the sequence id to assign to the current message
- SequenceID int64
+ SequenceID *int64
}
type Message interface {