pulsar_sdk 0.8.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +51 -0
- data/Gemfile +6 -0
- data/LICENSE +201 -0
- data/README.md +107 -0
- data/Rakefile +2 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/protobuf/pulsar_api.pb.rb +710 -0
- data/lib/protobuf/pulsar_api.proto +934 -0
- data/lib/protobuf/validate.rb +41 -0
- data/lib/pulsar_admin.rb +14 -0
- data/lib/pulsar_admin/api.rb +215 -0
- data/lib/pulsar_sdk.rb +55 -0
- data/lib/pulsar_sdk/client.rb +13 -0
- data/lib/pulsar_sdk/client/connection.rb +371 -0
- data/lib/pulsar_sdk/client/connection_pool.rb +79 -0
- data/lib/pulsar_sdk/client/rpc.rb +67 -0
- data/lib/pulsar_sdk/consumer.rb +13 -0
- data/lib/pulsar_sdk/consumer/base.rb +148 -0
- data/lib/pulsar_sdk/consumer/manager.rb +127 -0
- data/lib/pulsar_sdk/consumer/message_tracker.rb +86 -0
- data/lib/pulsar_sdk/options.rb +6 -0
- data/lib/pulsar_sdk/options/base.rb +10 -0
- data/lib/pulsar_sdk/options/connection.rb +51 -0
- data/lib/pulsar_sdk/options/consumer.rb +34 -0
- data/lib/pulsar_sdk/options/producer.rb +14 -0
- data/lib/pulsar_sdk/options/reader.rb +7 -0
- data/lib/pulsar_sdk/options/tls.rb +8 -0
- data/lib/pulsar_sdk/producer.rb +14 -0
- data/lib/pulsar_sdk/producer/base.rb +154 -0
- data/lib/pulsar_sdk/producer/manager.rb +67 -0
- data/lib/pulsar_sdk/producer/message.rb +47 -0
- data/lib/pulsar_sdk/producer/router.rb +100 -0
- data/lib/pulsar_sdk/protocol.rb +8 -0
- data/lib/pulsar_sdk/protocol/frame.rb +53 -0
- data/lib/pulsar_sdk/protocol/lookup.rb +55 -0
- data/lib/pulsar_sdk/protocol/message.rb +55 -0
- data/lib/pulsar_sdk/protocol/namespace.rb +22 -0
- data/lib/pulsar_sdk/protocol/partitioned.rb +54 -0
- data/lib/pulsar_sdk/protocol/reader.rb +67 -0
- data/lib/pulsar_sdk/protocol/structure.rb +93 -0
- data/lib/pulsar_sdk/protocol/topic.rb +74 -0
- data/lib/pulsar_sdk/tweaks.rb +10 -0
- data/lib/pulsar_sdk/tweaks/assign_attributes.rb +30 -0
- data/lib/pulsar_sdk/tweaks/base_command.rb +66 -0
- data/lib/pulsar_sdk/tweaks/binary_heap.rb +133 -0
- data/lib/pulsar_sdk/tweaks/clean_inspect.rb +15 -0
- data/lib/pulsar_sdk/tweaks/time_at_microsecond.rb +27 -0
- data/lib/pulsar_sdk/tweaks/timeout_queue.rb +52 -0
- data/lib/pulsar_sdk/tweaks/wait_map.rb +81 -0
- data/lib/pulsar_sdk/version.rb +3 -0
- data/pulsar_sdk.gemspec +31 -0
- metadata +151 -0
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'pulsar_sdk/protocol/frame'
|
2
|
+
require 'pulsar_sdk/protocol/message'
|
3
|
+
require 'pulsar_sdk/protocol/structure'
|
4
|
+
require 'pulsar_sdk/protocol/reader'
|
5
|
+
require 'pulsar_sdk/protocol/lookup'
|
6
|
+
require 'pulsar_sdk/protocol/namespace'
|
7
|
+
require 'pulsar_sdk/protocol/topic'
|
8
|
+
require 'pulsar_sdk/protocol/partitioned'
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'digest/crc32c'
|
2
|
+
|
3
|
+
module PulsarSdk
|
4
|
+
module Protocol
|
5
|
+
class Frame
|
6
|
+
# 预留4byte存放帧长度
|
7
|
+
PREPENDED_SIZE = 4
|
8
|
+
CHECKSUM_SIZE = 4
|
9
|
+
MAGIC_NUMBER = [0x0e, 0x01].pack('C*').freeze
|
10
|
+
|
11
|
+
def self.encode(command, message = nil)
|
12
|
+
raise "command MUST be Pulsar::Proto::BaseCommand but got #{command.class}" unless command.is_a?(Pulsar::Proto::BaseCommand)
|
13
|
+
|
14
|
+
pb_cmd = command.to_proto
|
15
|
+
|
16
|
+
# 非发送消息帧
|
17
|
+
return encode_command(pb_cmd) if message.nil?
|
18
|
+
|
19
|
+
# 消息发送帧
|
20
|
+
# [TOTAL_SIZE] [CMD_SIZE] [CMD] [MAGIC_NUMBER] [CHECKSUM] [METADATA_SIZE] [METADATA] [PAYLOAD]
|
21
|
+
raise "message MUST be PulsarSdk::Producer::Message but got #{message.class}" unless message.is_a?(PulsarSdk::Producer::Message)
|
22
|
+
|
23
|
+
metadata = message.metadata
|
24
|
+
pb_meta = metadata.to_proto
|
25
|
+
|
26
|
+
meta_payload = binary(pb_meta.size) + pb_meta + message.binary_string
|
27
|
+
checksum = crc32(meta_payload)
|
28
|
+
|
29
|
+
total_size = PREPENDED_SIZE + pb_cmd.size + MAGIC_NUMBER.size + CHECKSUM_SIZE + meta_payload.size
|
30
|
+
|
31
|
+
binary(total_size, pb_cmd.size) + pb_cmd + MAGIC_NUMBER + binary(checksum) + meta_payload
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.encode_command(pb_cmd)
|
35
|
+
binary(pb_cmd.size + PREPENDED_SIZE, pb_cmd.size) + pb_cmd
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.decode(byte)
|
39
|
+
Pulsar::Proto::BaseCommand.decode(byte)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.binary(*obj)
|
43
|
+
obj.map { |x| Array(x).pack('N') }.join
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.crc32(bytes)
|
47
|
+
crc = Digest::CRC32c.new
|
48
|
+
crc << bytes
|
49
|
+
crc.checksum
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Protocol
|
3
|
+
class Lookup
|
4
|
+
MAX_LOOKUP_TIMES = 20
|
5
|
+
|
6
|
+
def initialize(client, service_url)
|
7
|
+
@client = client
|
8
|
+
@service_url = service_url
|
9
|
+
end
|
10
|
+
|
11
|
+
# output
|
12
|
+
# [logical_addr, physical_addr]
|
13
|
+
def lookup(topic)
|
14
|
+
base_cmd = Pulsar::Proto::BaseCommand.new(
|
15
|
+
type: Pulsar::Proto::BaseCommand::Type::LOOKUP,
|
16
|
+
lookupTopic: Pulsar::Proto::CommandLookupTopic.new(
|
17
|
+
topic: topic,
|
18
|
+
authoritative: false
|
19
|
+
)
|
20
|
+
)
|
21
|
+
resp = @client.request_any_broker(base_cmd).lookupTopicResponse
|
22
|
+
|
23
|
+
# 最多查找这么多次
|
24
|
+
MAX_LOOKUP_TIMES.times do
|
25
|
+
case Pulsar::Proto::CommandLookupTopicResponse::LookupType.resolve(resp.response)
|
26
|
+
when Pulsar::Proto::CommandLookupTopicResponse::LookupType::Failed
|
27
|
+
PulsarSdk.logger.error(__method__){"Failed to lookup topic 「#{topic}」, #{resp.error}"}
|
28
|
+
break
|
29
|
+
when Pulsar::Proto::CommandLookupTopicResponse::LookupType::Redirect
|
30
|
+
logical_addr, physical_addr = extract_addr(resp)
|
31
|
+
base_cmd = Pulsar::Proto::BaseCommand.new(
|
32
|
+
type: Pulsar::Proto::BaseCommand::Type::LOOKUP,
|
33
|
+
lookupTopic: Pulsar::Proto::CommandLookupTopic.new(
|
34
|
+
topic: topic,
|
35
|
+
authoritative: resp.authoritative
|
36
|
+
)
|
37
|
+
)
|
38
|
+
# NOTE 从连接池拿
|
39
|
+
resp = @client.request(logical_addr, physical_addr, base_cmd).lookupTopicResponse
|
40
|
+
when Pulsar::Proto::CommandLookupTopicResponse::LookupType::Connect
|
41
|
+
return extract_addr(resp)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def extract_addr(resp)
|
48
|
+
logical_addr = resp.brokerServiceUrl
|
49
|
+
physical_addr = resp.proxy_through_service_url ? @service_url : logical_addr
|
50
|
+
|
51
|
+
[logical_addr, physical_addr]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Protocol
|
3
|
+
class Message
|
4
|
+
prepend ::PulsarSdk::Tweaks::AssignAttributes
|
5
|
+
prepend ::PulsarSdk::Tweaks::CleanInspect
|
6
|
+
|
7
|
+
attr_accessor :publish_time, :event_time, :partition_key, :payload,
|
8
|
+
:message_id, :properties, :consumer_id, :topic
|
9
|
+
|
10
|
+
attr_accessor :ack_handler
|
11
|
+
|
12
|
+
# def publish_at
|
13
|
+
# def event_at
|
14
|
+
[:publish, :event].each do |x|
|
15
|
+
define_method "#{x}_at" do
|
16
|
+
v = self.public_send("#{x}_time").to_i
|
17
|
+
return if v.zero?
|
18
|
+
TimeX.at_timestamp(v)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def ack(type = Pulsar::Proto::CommandAck::AckType::Individual)
|
23
|
+
base_cmd = Pulsar::Proto::BaseCommand.new(
|
24
|
+
type: Pulsar::Proto::BaseCommand::Type::ACK,
|
25
|
+
ack: Pulsar::Proto::CommandAck.new(
|
26
|
+
consumer_id: self.consumer_id,
|
27
|
+
message_id: [self.message_id],
|
28
|
+
ack_type: type
|
29
|
+
)
|
30
|
+
)
|
31
|
+
|
32
|
+
ack_handler.call(base_cmd)
|
33
|
+
@confirmed = true
|
34
|
+
end
|
35
|
+
|
36
|
+
# 检查是否有确认,无论是ack还是nack都算是确认
|
37
|
+
def confirmed?
|
38
|
+
!!@confirmed
|
39
|
+
end
|
40
|
+
|
41
|
+
def nack
|
42
|
+
base_cmd = Pulsar::Proto::BaseCommand.new(
|
43
|
+
type: Pulsar::Proto::BaseCommand::Type::REDELIVER_UNACKNOWLEDGED_MESSAGES,
|
44
|
+
redeliverUnacknowledgedMessages: Pulsar::Proto::CommandRedeliverUnacknowledgedMessages.new(
|
45
|
+
consumer_id: self.consumer_id,
|
46
|
+
message_ids: [self.message_id]
|
47
|
+
)
|
48
|
+
)
|
49
|
+
|
50
|
+
ack_handler.call(base_cmd)
|
51
|
+
@confirmed = true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Protocol
|
3
|
+
class Namespace
|
4
|
+
def initialize(client)
|
5
|
+
@client = client
|
6
|
+
end
|
7
|
+
|
8
|
+
def topics(namespace)
|
9
|
+
base_cmd = Pulsar::Proto::BaseCommand.new(
|
10
|
+
type: Pulsar::Proto::BaseCommand::Type::GET_TOPICS_OF_NAMESPACE,
|
11
|
+
getTopicsOfNamespace: Pulsar::Proto::CommandGetTopicsOfNamespace.new(
|
12
|
+
namespace: namespace,
|
13
|
+
mode: Pulsar::Proto::CommandGetTopicsOfNamespace::Mode.resolve(:ALL)
|
14
|
+
)
|
15
|
+
)
|
16
|
+
resp = @client.request_any_broker(base_cmd)
|
17
|
+
|
18
|
+
resp.getTopicsOfNamespaceResponse&.topics
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Protocol
|
3
|
+
class Partitioned
|
4
|
+
def initialize(client, topic)
|
5
|
+
@client = client
|
6
|
+
@tn = ::PulsarSdk::Protocol::Topic.parse(topic)
|
7
|
+
end
|
8
|
+
|
9
|
+
def partitions
|
10
|
+
pmr = topic_metadata
|
11
|
+
|
12
|
+
if !success_response?(pmr)
|
13
|
+
PulsarSdk.logger.error(__method__){"Get topic partitioned metadata failed, #{pmr.error}: #{pmr.message}"}
|
14
|
+
return []
|
15
|
+
end
|
16
|
+
|
17
|
+
return [@tn.to_s] if pmr.partitions.zero?
|
18
|
+
|
19
|
+
tn = @tn.dup
|
20
|
+
(0..pmr.partitions).map do |i|
|
21
|
+
tn.partition = i
|
22
|
+
tn.to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# 当前topic是否是分区topic
|
27
|
+
def partitioned?
|
28
|
+
topic_metadata.partitions > 0
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def success_response?(pmr)
|
33
|
+
result = false
|
34
|
+
Pulsar::Proto::CommandPartitionedTopicMetadataResponse::LookupType.tap do |x|
|
35
|
+
result = x.resolve(pmr.response) == x.const_get(:Success)
|
36
|
+
end
|
37
|
+
|
38
|
+
result
|
39
|
+
end
|
40
|
+
|
41
|
+
def topic_metadata
|
42
|
+
return @topic_metadata_ unless @topic_metadata_.nil?
|
43
|
+
|
44
|
+
base_cmd = Pulsar::Proto::BaseCommand.new(
|
45
|
+
type: Pulsar::Proto::BaseCommand::Type::PARTITIONED_METADATA,
|
46
|
+
partitionMetadata: Pulsar::Proto::CommandPartitionedTopicMetadata.new(
|
47
|
+
topic: @tn.to_s
|
48
|
+
)
|
49
|
+
)
|
50
|
+
@topic_metadata_ = @client.request_any_broker(base_cmd).partitionMetadataResponse
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Protocol
|
3
|
+
class Reader
|
4
|
+
prepend ::PulsarSdk::Tweaks::CleanInspect
|
5
|
+
|
6
|
+
FRAME_SIZE_LEN = 4
|
7
|
+
CMD_SIZE_LEN = 4
|
8
|
+
|
9
|
+
def initialize(io)
|
10
|
+
ensure_interface_implemented!(io)
|
11
|
+
@io = io
|
12
|
+
|
13
|
+
@readed = 0
|
14
|
+
end
|
15
|
+
|
16
|
+
# TODO add timeout?
|
17
|
+
def read_fully
|
18
|
+
frame_szie = read_frame_size
|
19
|
+
raise "IO reader is empty! maybe server error, please check server log for help." if frame_szie.nil?
|
20
|
+
|
21
|
+
base_cmd = read_command
|
22
|
+
|
23
|
+
buffer = read_remaining(frame_szie)
|
24
|
+
|
25
|
+
[base_cmd, buffer]
|
26
|
+
end
|
27
|
+
|
28
|
+
def read_frame_size
|
29
|
+
frame_size = read(FRAME_SIZE_LEN, 'N')
|
30
|
+
# reset cursor! let's read the frame
|
31
|
+
@readed = 0
|
32
|
+
frame_size
|
33
|
+
end
|
34
|
+
|
35
|
+
def read_command
|
36
|
+
cmd_size = read(CMD_SIZE_LEN, 'N')
|
37
|
+
cmd_bytes = read(cmd_size)
|
38
|
+
Pulsar::Proto::BaseCommand.decode(cmd_bytes)
|
39
|
+
end
|
40
|
+
|
41
|
+
def read_remaining(frame_szie)
|
42
|
+
meta_and_payload_size = frame_szie - @readed
|
43
|
+
return if meta_and_payload_size <= 0
|
44
|
+
read(meta_and_payload_size)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def ensure_interface_implemented!(io)
|
49
|
+
[:read, :closed?].each do |x|
|
50
|
+
raise "io must implement method: #{x}" unless io.respond_to?(x)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def read(size, unpack = nil)
|
55
|
+
raise Errno::ECONNRESET if @io.closed?
|
56
|
+
raise Errno::ETIMEDOUT unless IO.select([@io], nil)
|
57
|
+
|
58
|
+
bytes = @io.read(size)
|
59
|
+
@readed = @readed.to_i + size.to_i
|
60
|
+
|
61
|
+
return bytes if unpack.nil? || bytes.nil?
|
62
|
+
|
63
|
+
bytes.unpack(unpack).first
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Protocol
|
3
|
+
class Structure
|
4
|
+
prepend ::PulsarSdk::Tweaks::CleanInspect
|
5
|
+
|
6
|
+
# [MAGIC_NUMBER] [CHECKSUM] [METADATA_SIZE] [METADATA] [PAYLOAD]
|
7
|
+
MAGIC_NUMBER = [0x0e, 0x01].pack('C*').freeze
|
8
|
+
MAGIC_NUMBER_LEN = MAGIC_NUMBER.size
|
9
|
+
CHECKSUM_LEN = 4
|
10
|
+
METADATA_SIZE_LEN = 4
|
11
|
+
|
12
|
+
def initialize(buff)
|
13
|
+
@buff = buff
|
14
|
+
rewind
|
15
|
+
end
|
16
|
+
|
17
|
+
def decode
|
18
|
+
metadata = nil
|
19
|
+
|
20
|
+
message = PulsarSdk::Protocol::Message.new
|
21
|
+
|
22
|
+
mn_bytes = read_magic_number
|
23
|
+
if mn_bytes == MAGIC_NUMBER
|
24
|
+
_checksum = read_checksum
|
25
|
+
# TODO 可能需要校验一下,防止错误消息
|
26
|
+
metadata = read_metadata
|
27
|
+
else
|
28
|
+
rewind(MAGIC_NUMBER_LEN)
|
29
|
+
metadata = read_metadata
|
30
|
+
end
|
31
|
+
|
32
|
+
msg = read_remaining
|
33
|
+
|
34
|
+
# NOTE 同为Ruby SDK时可以根据Content-Type预先还原
|
35
|
+
# 复杂类型依旧为string,需要特别注意
|
36
|
+
metadata.properties.each do |x|
|
37
|
+
next unless x.key.to_s =~ /Content-Type/i
|
38
|
+
next unless x.value.to_s =~ /json/i
|
39
|
+
PulsarSdk.logger.info("#{self.class}::#{__method__}"){"Found json encode remark, parse JSON mesaage!"}
|
40
|
+
msg = JSON.parse(msg)
|
41
|
+
end
|
42
|
+
|
43
|
+
message.assign_attributes(
|
44
|
+
publish_time: metadata.publish_time,
|
45
|
+
event_time: metadata.event_time,
|
46
|
+
partition_key: metadata.partition_key,
|
47
|
+
properties: metadata.properties,
|
48
|
+
payload: msg
|
49
|
+
)
|
50
|
+
|
51
|
+
message
|
52
|
+
end
|
53
|
+
|
54
|
+
# 回退若干字节,方便处理非连续段
|
55
|
+
def rewind(x = nil)
|
56
|
+
return @readed = 0 if x.nil?
|
57
|
+
|
58
|
+
@readed -= x
|
59
|
+
end
|
60
|
+
|
61
|
+
def read_magic_number
|
62
|
+
read(MAGIC_NUMBER_LEN)
|
63
|
+
end
|
64
|
+
|
65
|
+
# crc32
|
66
|
+
def read_checksum
|
67
|
+
read(CHECKSUM_LEN)
|
68
|
+
end
|
69
|
+
|
70
|
+
def read_metadata
|
71
|
+
metadata_size = read(METADATA_SIZE_LEN, 'N')
|
72
|
+
metadata_bytes = read(metadata_size)
|
73
|
+
Pulsar::Proto::MessageMetadata.decode(metadata_bytes)
|
74
|
+
end
|
75
|
+
|
76
|
+
def read_remaining
|
77
|
+
payload_size = @buff.size - @readed
|
78
|
+
return if payload_size <= 0
|
79
|
+
read(payload_size)
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
def read(size, unpack = nil)
|
84
|
+
bytes = @buff[@readed..(@readed + size - 1)]
|
85
|
+
@readed += size
|
86
|
+
|
87
|
+
return bytes if unpack.nil? || bytes.nil?
|
88
|
+
|
89
|
+
bytes.unpack(unpack).first
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Protocol
|
3
|
+
class Topic
|
4
|
+
PUBLIC_TENANT = 'public'.freeze
|
5
|
+
DEFAULT_NAMESPACE = 'default'.freeze
|
6
|
+
PARTITIONED_TOPIC_SUFFIX = '-partition-'.freeze
|
7
|
+
|
8
|
+
prepend ::PulsarSdk::Tweaks::AssignAttributes
|
9
|
+
|
10
|
+
attr_accessor :domain, :namespace, :topic, :partition
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
[
|
14
|
+
mk_domain,
|
15
|
+
self.namespace,
|
16
|
+
mk_topic
|
17
|
+
].join('/')
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def mk_topic
|
22
|
+
return self.topic if self.partition.nil?
|
23
|
+
|
24
|
+
"#{self.topic}#{PARTITIONED_TOPIC_SUFFIX}#{self.partition}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def mk_domain
|
28
|
+
return if domain.nil?
|
29
|
+
"#{self.domain}:/"
|
30
|
+
end
|
31
|
+
|
32
|
+
# new: persistent://tenant/namespace/topic
|
33
|
+
# legacy: persistent://tenant/cluster/namespace/topic
|
34
|
+
def self.parse(topic)
|
35
|
+
if !topic.include?('://')
|
36
|
+
parts = topic.split('/')
|
37
|
+
if parts.size == 3 || parts.size == 4
|
38
|
+
topic = "persistent://#{topic}"
|
39
|
+
elsif parts.size == 1
|
40
|
+
topic = "persistent://#{PUBLIC_TENANT}/#{DEFAULT_NAMESPACE}/" + parts[0]
|
41
|
+
else
|
42
|
+
raise "Invalid short topic name: #{topic}, it should be in the format of <tenant>/<namespace>/<topic> or <topic>"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
domain, rest = topic.split('://', 2)
|
47
|
+
unless ['persistent', 'non-persistent'].include?(domain)
|
48
|
+
raise "Invalid topic domain: #{domain}"
|
49
|
+
end
|
50
|
+
|
51
|
+
tn = new(domain: domain)
|
52
|
+
topic_with_partition = nil
|
53
|
+
|
54
|
+
case rest.count('/')
|
55
|
+
when 2
|
56
|
+
tenant, namespace, topic_with_partition = rest.split('/', 3)
|
57
|
+
tn.namespace = [tenant, namespace].join('/')
|
58
|
+
when 3
|
59
|
+
tenant, cluster, namespace, topic_with_partition = rest.split('/', 4)
|
60
|
+
tn.namespace = [tenant, cluster, namespace].join('/')
|
61
|
+
else
|
62
|
+
raise "Invalid topic name: #{topic}"
|
63
|
+
end
|
64
|
+
|
65
|
+
tn.topic, partition = topic_with_partition.split(PARTITIONED_TOPIC_SUFFIX, 2)
|
66
|
+
|
67
|
+
tn.partition = partition&.to_i
|
68
|
+
|
69
|
+
tn
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|