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,10 @@
|
|
1
|
+
require 'pulsar_sdk/tweaks/assign_attributes'
|
2
|
+
require 'pulsar_sdk/tweaks/clean_inspect'
|
3
|
+
require 'pulsar_sdk/tweaks/base_command'
|
4
|
+
require 'pulsar_sdk/tweaks/time_at_microsecond'
|
5
|
+
require 'pulsar_sdk/tweaks/timeout_queue'
|
6
|
+
require 'pulsar_sdk/tweaks/wait_map'
|
7
|
+
require 'pulsar_sdk/tweaks/binary_heap'
|
8
|
+
|
9
|
+
# 扩展type的判断方法,方便书写,统一以 typeof_ 开头
|
10
|
+
Pulsar::Proto::BaseCommand.prepend PulsarSdk::Tweaks::BaseCommand
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Tweaks
|
3
|
+
module AssignAttributes
|
4
|
+
def initialize(opts = {})
|
5
|
+
set_default
|
6
|
+
|
7
|
+
assign_attributes(opts)
|
8
|
+
|
9
|
+
remove_empty_instance_variables!
|
10
|
+
end
|
11
|
+
|
12
|
+
def assign_attributes(opts)
|
13
|
+
opts.each do |k, v|
|
14
|
+
method = "#{k}="
|
15
|
+
next unless self.respond_to?(method)
|
16
|
+
self.public_send method, v
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def set_default; end
|
22
|
+
|
23
|
+
def remove_empty_instance_variables!
|
24
|
+
instance_variables.each do |x|
|
25
|
+
remove_instance_variable(x) if instance_variable_get(x).nil?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Tweaks
|
3
|
+
module BaseCommand
|
4
|
+
attr_accessor :seq_generator
|
5
|
+
|
6
|
+
# add some helper
|
7
|
+
# def set_request_id
|
8
|
+
# def set_consumer_id
|
9
|
+
# def set_producer_id
|
10
|
+
# def set_sequence_id
|
11
|
+
# def get_request_id
|
12
|
+
# def get_consumer_id
|
13
|
+
# def get_producer_id
|
14
|
+
# def get_sequence_id
|
15
|
+
# NOTE before use setter must set `seq_generator`
|
16
|
+
[:request_id, :consumer_id, :producer_id, :sequence_id].each do |x|
|
17
|
+
define_method "set_#{x}" do
|
18
|
+
if self.seq_generator.nil?
|
19
|
+
PulsarSdk.logger.warn(__method__){"seq_generator was not set!! action has no effect"}
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
method_ = "#{x}="
|
24
|
+
current_id = nil
|
25
|
+
attribute_names.each do |name|
|
26
|
+
next unless self[name].respond_to?(method_)
|
27
|
+
|
28
|
+
# NOTE keep same id name with same value, like sequence_id
|
29
|
+
current_id ||= self.seq_generator.public_send("new_#{x}")
|
30
|
+
|
31
|
+
self[name].public_send(method_, current_id)
|
32
|
+
end
|
33
|
+
|
34
|
+
current_id
|
35
|
+
end
|
36
|
+
|
37
|
+
define_method "get_#{x}" do
|
38
|
+
attribute_names.each do |name|
|
39
|
+
next unless self[name].respond_to?(x)
|
40
|
+
return self[name][x.to_s]
|
41
|
+
end
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Pulsar::Proto::BaseCommand::Type.constants.each do |x|
|
47
|
+
method = "typeof_#{x.to_s.downcase}?"
|
48
|
+
define_method method do
|
49
|
+
self.type == x
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def handle_ids
|
54
|
+
set_request_id
|
55
|
+
set_consumer_id
|
56
|
+
set_producer_id
|
57
|
+
set_sequence_id
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def attribute_names
|
62
|
+
self.class.descriptor.map(&:name)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Tweaks
|
3
|
+
class BinaryHeap
|
4
|
+
attr_reader :data
|
5
|
+
|
6
|
+
# default is max heap, custom compare lambda to build your sort
|
7
|
+
def initialize(ary=nil, &block)
|
8
|
+
@cmp = block || lambda{|parent, child| parent <=> child }
|
9
|
+
@mutex = Mutex.new
|
10
|
+
|
11
|
+
raise "type of ary must be Array or its subclass" unless ary.nil? || ary.is_a?(Array)
|
12
|
+
@data = build_from(ary)
|
13
|
+
end
|
14
|
+
|
15
|
+
# insert an element list into heap, it will automatic adjust
|
16
|
+
def insert(*elements)
|
17
|
+
@mutex.synchronize do
|
18
|
+
elements.each do |x|
|
19
|
+
data.push(x)
|
20
|
+
adjust(:bottom_up)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# take the heap element and adjust heap
|
26
|
+
def shift
|
27
|
+
@mutex.synchronize do
|
28
|
+
return if data.empty?
|
29
|
+
e = data.first
|
30
|
+
data[0] = data.last
|
31
|
+
data.pop
|
32
|
+
adjust(:top_down)
|
33
|
+
e
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# return the the top element of the heap
|
38
|
+
def top
|
39
|
+
data.first
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def build_from(ary)
|
44
|
+
return [] if ary.nil? || ary.empty?
|
45
|
+
|
46
|
+
heap = BinaryHeap.new(&(@cmp))
|
47
|
+
heap.insert(*ary)
|
48
|
+
heap.data
|
49
|
+
end
|
50
|
+
|
51
|
+
def swap(i, j)
|
52
|
+
data[i], data[j] = data[j], data[i]
|
53
|
+
end
|
54
|
+
|
55
|
+
def compare(i, j)
|
56
|
+
@cmp.call(data[i], data[j]) >= 0
|
57
|
+
end
|
58
|
+
|
59
|
+
def p_idx(child_idx)
|
60
|
+
return nil if child_idx == 0
|
61
|
+
child_idx%2 == 0 ? (child_idx-2)/2 : child_idx/2
|
62
|
+
end
|
63
|
+
|
64
|
+
def l_idx(parent_idx)
|
65
|
+
(parent_idx << 1) + 1
|
66
|
+
end
|
67
|
+
|
68
|
+
def r_idx(parent_idx)
|
69
|
+
(parent_idx << 1) + 2
|
70
|
+
end
|
71
|
+
|
72
|
+
def lchid(parent_idx)
|
73
|
+
data[l_idx(parent_idx)]
|
74
|
+
end
|
75
|
+
|
76
|
+
def rchild(parent_idx)
|
77
|
+
data[r_idx(parent_idx)]
|
78
|
+
end
|
79
|
+
|
80
|
+
def good?(idx)
|
81
|
+
if !lchid(idx).nil?
|
82
|
+
return false unless compare(idx, l_idx(idx))
|
83
|
+
end
|
84
|
+
|
85
|
+
if !rchild(idx).nil?
|
86
|
+
return false unless compare(idx, r_idx(idx))
|
87
|
+
end
|
88
|
+
|
89
|
+
true
|
90
|
+
end
|
91
|
+
|
92
|
+
# make the heap in good shape
|
93
|
+
def adjust(direction = :top_down)
|
94
|
+
return if data.size < 2
|
95
|
+
|
96
|
+
case direction
|
97
|
+
when :top_down
|
98
|
+
parent_idx = 0
|
99
|
+
until good?(parent_idx)
|
100
|
+
child_idx = find_child_idx(parent_idx)
|
101
|
+
swap(parent_idx, child_idx)
|
102
|
+
parent_idx = child_idx
|
103
|
+
end
|
104
|
+
when :bottom_up
|
105
|
+
child_idx = data.size - 1
|
106
|
+
parent_idx = p_idx(child_idx)
|
107
|
+
until child_idx == 0 || compare(parent_idx, child_idx)
|
108
|
+
swap(parent_idx, child_idx)
|
109
|
+
child_idx = parent_idx
|
110
|
+
parent_idx = p_idx(child_idx)
|
111
|
+
end
|
112
|
+
else
|
113
|
+
raise "invalid direction type"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def find_child_idx(parent_idx)
|
118
|
+
l = lchid(parent_idx)
|
119
|
+
r = rchild(parent_idx)
|
120
|
+
|
121
|
+
return if l.nil? && r.nil?
|
122
|
+
|
123
|
+
l_idx_ = l_idx(parent_idx)
|
124
|
+
r_idx_ = r_idx(parent_idx)
|
125
|
+
|
126
|
+
return r_idx_ if l.nil?
|
127
|
+
return l_idx_ if r.nil?
|
128
|
+
|
129
|
+
compare(l_idx_, r_idx_) ? l_idx_ : r_idx_
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Tweaks
|
3
|
+
module CleanInspect
|
4
|
+
def inspect
|
5
|
+
s = instance_variables.map do |x|
|
6
|
+
v = instance_variable_get(x)
|
7
|
+
next if v.is_a?(Proc)
|
8
|
+
"#{x}: #{v}"
|
9
|
+
end.join(', ')
|
10
|
+
|
11
|
+
"<#{self.class.name} #{s}>"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Tweaks
|
3
|
+
module TimeAtMicrosecond
|
4
|
+
def self.prepended(base)
|
5
|
+
class << base
|
6
|
+
prepend ClassMethods
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def timestamp
|
11
|
+
(self.to_f * 1000).floor
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def at_timestamp(v)
|
16
|
+
second, micro = v.divmod(1000)
|
17
|
+
self.at(second, micro * 1000)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# 扩展默认时间方法,增加毫秒时间戳相关处理
|
25
|
+
class TimeX < Time
|
26
|
+
prepend PulsarSdk::Tweaks::TimeAtMicrosecond
|
27
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Tweaks
|
3
|
+
class TimeoutQueue
|
4
|
+
def initialize
|
5
|
+
@mutex = Mutex.new
|
6
|
+
@queue = []
|
7
|
+
@received = ConditionVariable.new
|
8
|
+
@closed = false
|
9
|
+
end
|
10
|
+
|
11
|
+
def add(*args)
|
12
|
+
@mutex.synchronize do
|
13
|
+
@queue << args
|
14
|
+
@received.signal
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def clear
|
19
|
+
@mutex.synchronize do
|
20
|
+
@queue.clear
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def size
|
25
|
+
@queue.size
|
26
|
+
end
|
27
|
+
|
28
|
+
# timeout 数字,单位秒
|
29
|
+
def pop(timeout = nil)
|
30
|
+
@mutex.synchronize do
|
31
|
+
if timeout.nil?
|
32
|
+
while !@closed && @queue.empty?
|
33
|
+
@received.wait(@mutex)
|
34
|
+
end
|
35
|
+
elsif @queue.empty? && timeout != 0
|
36
|
+
timeout_at = TimeX.now.to_f + timeout
|
37
|
+
while !@closed && @queue.empty? && (res = timeout_at - TimeX.now.to_f) > 0
|
38
|
+
@received.wait(@mutex, res)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
@queue.pop
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def close
|
47
|
+
@closed = true
|
48
|
+
@received.broadcast
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module PulsarSdk
|
2
|
+
module Tweaks
|
3
|
+
class WaitMap
|
4
|
+
def initialize
|
5
|
+
@mutex = Mutex.new
|
6
|
+
@map = {}
|
7
|
+
|
8
|
+
@wait = {}
|
9
|
+
@closed = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def add(id, value)
|
13
|
+
@mutex.synchronize do
|
14
|
+
@map[id] = value
|
15
|
+
_, signal = @wait[id]
|
16
|
+
signal.signal unless signal.nil?
|
17
|
+
end
|
18
|
+
value
|
19
|
+
end
|
20
|
+
|
21
|
+
def clear
|
22
|
+
@mutex.synchronize do
|
23
|
+
@map.each {|k, v| yield k, v} if block_given?
|
24
|
+
|
25
|
+
@map = {}
|
26
|
+
end
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
def each(&block)
|
31
|
+
@mutex.synchronize do
|
32
|
+
@map.each {|k, v| yield k, v}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# 不会删除元素
|
37
|
+
def find(id)
|
38
|
+
@mutex.synchronize do
|
39
|
+
@map[id]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete(id, timeout = nil)
|
44
|
+
mutex, signal = []
|
45
|
+
|
46
|
+
@mutex.synchronize do
|
47
|
+
return @map.delete(id) if @map.has_key?(id)
|
48
|
+
|
49
|
+
@wait[id] ||= [Mutex.new, ConditionVariable.new]
|
50
|
+
mutex, signal = @wait[id]
|
51
|
+
end
|
52
|
+
|
53
|
+
mutex.synchronize do
|
54
|
+
if timeout.nil?
|
55
|
+
while !@closed && !@map.has_key?(id)
|
56
|
+
signal.wait(mutex)
|
57
|
+
end
|
58
|
+
elsif @map.empty? && timeout != 0
|
59
|
+
timeout_at = TimeX.now.to_f + timeout
|
60
|
+
while !@closed && !@map.has_key?(id) && (res = timeout_at - TimeX.now.to_f) > 0
|
61
|
+
signal.wait(mutex, res)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
@mutex.synchronize do
|
67
|
+
@wait.delete id
|
68
|
+
@map.delete id
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def close
|
73
|
+
@closed = true
|
74
|
+
@wait.each do |_, v|
|
75
|
+
_, signal = v
|
76
|
+
signal.broadcast
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/pulsar_sdk.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "pulsar_sdk/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "pulsar_sdk"
|
8
|
+
spec.version = PulsarSdk::VERSION
|
9
|
+
spec.authors = 'archfish'
|
10
|
+
spec.email = ["weihailang@gmail.com"]
|
11
|
+
spec.license = 'Apache License 2.0'
|
12
|
+
|
13
|
+
spec.summary = %q{A pure ruby client for Apache Pulsar}
|
14
|
+
spec.description = %q{A pure ruby client for Apache Pulsar}
|
15
|
+
spec.homepage = "https://github.com/archfish/pulsar_sdk"
|
16
|
+
|
17
|
+
# Specify which files should be added to the gem when it is released.
|
18
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
19
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
20
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|examples)/}) }
|
21
|
+
end
|
22
|
+
|
23
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_dependency 'google-protobuf', '~> 3.11'
|
27
|
+
spec.add_dependency 'digest-crc', '~> 0.4'
|
28
|
+
|
29
|
+
spec.add_development_dependency "bundler", "> 1.17"
|
30
|
+
spec.add_development_dependency "rake", "> 10"
|
31
|
+
end
|