pulsar_sdk 0.8.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|