kafkr 0.9.1 → 0.11.0
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 +4 -4
- data/.DS_Store +0 -0
- data/exe/kafkr-consumer +2 -0
- data/lib/kafkr/consumer.rb +17 -73
- data/lib/kafkr/encryptor.rb +1 -1
- data/lib/kafkr/log.rb +10 -57
- data/lib/kafkr/producer.rb +6 -82
- data/lib/kafkr/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41bbdf52172942afa5cb0758bee83eeb452f74f3d61849841fe186e44ef323a5
|
4
|
+
data.tar.gz: fcf59de6aed2bc3644df69573091dbffeb9641f39bb5fbdece548de3cf509217
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f249925d3d2de4ca159796d88628450b78fdb5d5c00c756891202d39f7d8e34b69f282613c819c2aecc734a7fc0fe0c414ea2471955c27dda394e9f27bca1d5
|
7
|
+
data.tar.gz: 8e004710cfffe4ead0df8ed181fa5f8d044ca4cb8690d6be92028473475a9b2fddea89f0c8f77fbf96ea8b3eeaa00886a8e7ec94eff338379c9797cfa8956bf7
|
data/.DS_Store
ADDED
Binary file
|
data/exe/kafkr-consumer
CHANGED
@@ -7,6 +7,7 @@ require "digest"
|
|
7
7
|
# Accepting command line arguments for host and port
|
8
8
|
host = ARGV[0] || "localhost"
|
9
9
|
port = ARGV[1] || 4000
|
10
|
+
timeout = ARGV[2] || 120
|
10
11
|
|
11
12
|
puts "Running on host: #{host} and port: #{port}"
|
12
13
|
|
@@ -40,6 +41,7 @@ def start_consumer(port, host)
|
|
40
41
|
Kafkr::Consumer.configure do |config|
|
41
42
|
config.port = port
|
42
43
|
config.host = host
|
44
|
+
config.timeout = timeout
|
43
45
|
end
|
44
46
|
|
45
47
|
unless $handlers_loaded
|
data/lib/kafkr/consumer.rb
CHANGED
@@ -18,6 +18,9 @@ module Kafkr
|
|
18
18
|
def configuration
|
19
19
|
FileUtils.mkdir_p "./.kafkr"
|
20
20
|
@configuration ||= OpenStruct.new
|
21
|
+
@configuration.host = ENV.fetch("KAFKR_HOST", "localhost")
|
22
|
+
@configuration.port = ENV.fetch("KAFKR_PORT", 2000)
|
23
|
+
@configuration.timeout = ENV.fetch("KAFKR_CONSUMER_TIMEOUT", 120)
|
21
24
|
@configuration.suggest_handlers = false
|
22
25
|
@configuration
|
23
26
|
end
|
@@ -39,7 +42,6 @@ module Kafkr
|
|
39
42
|
end
|
40
43
|
|
41
44
|
def load_handlers(directory = "./handlers")
|
42
|
-
# Load handlers and check for new additions
|
43
45
|
Dir.glob("#{directory}/*.rb").each do |file|
|
44
46
|
handler_name = File.basename(file, ".rb")
|
45
47
|
unless $loaded_handlers[handler_name]
|
@@ -48,11 +50,6 @@ module Kafkr
|
|
48
50
|
$handlers_changed = true
|
49
51
|
end
|
50
52
|
end
|
51
|
-
|
52
|
-
# Display handlers if there are changes
|
53
|
-
if $handlers_changed
|
54
|
-
$handlers_changed = false
|
55
|
-
end
|
56
53
|
end
|
57
54
|
end
|
58
55
|
|
@@ -65,20 +62,19 @@ module Kafkr
|
|
65
62
|
raise NotImplementedError, "You must implement the handle method"
|
66
63
|
end
|
67
64
|
|
68
|
-
# ... rest of your existing Handler methods ...
|
69
65
|
def self.inherited(subclass)
|
70
66
|
Consumer.register_handler(subclass.new)
|
71
67
|
end
|
72
68
|
|
73
69
|
protected
|
74
70
|
|
75
|
-
def reply
|
71
|
+
def reply(to:, payload:)
|
76
72
|
Kafkr::Producer.configure do |config|
|
77
73
|
config.host = Consumer.configuration.host
|
78
74
|
config.port = Consumer.configuration.port
|
79
75
|
end
|
80
76
|
|
81
|
-
Kafkr::Producer.send_message({reply: {payload: payload, uuid: to["sync_uid"]}}
|
77
|
+
Kafkr::Producer.send_message({reply: {payload: payload, uuid: to["sync_uid"]}})
|
82
78
|
end
|
83
79
|
|
84
80
|
private
|
@@ -114,45 +110,34 @@ module Kafkr
|
|
114
110
|
end
|
115
111
|
|
116
112
|
def valid_class_name?(name)
|
117
|
-
# A valid class name starts with an uppercase letter and
|
118
|
-
# followed by zero or more letters, numbers, or underscores.
|
119
113
|
/^[A-Z]\w*$/.match?(name)
|
120
114
|
end
|
121
115
|
|
122
|
-
# sugests a working handler
|
123
116
|
def print_handler_class(name)
|
124
117
|
return if name.is_a?(Numeric)
|
125
|
-
|
126
|
-
# If name is a Hash, use its first key
|
127
118
|
name = name.keys.first if name.is_a?(Hash)
|
128
|
-
|
129
|
-
# Generate the handler name based on the naming convention
|
130
119
|
handler_name = "#{name.downcase}_handler"
|
131
120
|
|
132
|
-
# Check if the handler is already loaded
|
133
121
|
if $loaded_handlers.key?(handler_name)
|
134
122
|
return
|
135
123
|
end
|
136
124
|
|
137
125
|
if Kafkr::Consumer.configuration.suggest_handlers
|
138
|
-
if valid_class_name?
|
139
|
-
puts "No handler for this message, you could use this one
|
140
|
-
puts ""
|
126
|
+
if valid_class_name?(name.capitalize)
|
127
|
+
puts "No handler for this message, you could use this one.\n\n"
|
141
128
|
|
142
129
|
handler_class_string = <<~HANDLER_CLASS
|
143
|
-
|
144
130
|
class #{name.capitalize}Handler < Kafkr::Consumer::Handler
|
145
131
|
def handle?(message)
|
146
132
|
can_handle? message, '#{name}'
|
147
133
|
end
|
148
|
-
|
134
|
+
|
149
135
|
def handle(message)
|
150
136
|
puts message
|
151
137
|
end
|
152
138
|
end
|
153
139
|
|
154
|
-
|
155
|
-
|
140
|
+
# Save the file to ./handlers/#{name}_handler.rb
|
156
141
|
HANDLER_CLASS
|
157
142
|
|
158
143
|
puts handler_class_string
|
@@ -165,38 +150,28 @@ module Kafkr
|
|
165
150
|
def listen_for(message, send_message)
|
166
151
|
attempt = 0
|
167
152
|
begin
|
168
|
-
socket = TCPSocket.new(
|
153
|
+
socket = TCPSocket.new(@host, @port)
|
169
154
|
attempt = 0
|
170
155
|
|
171
|
-
Timeout.timeout(
|
172
|
-
|
173
|
-
sync_uid = send_message.call(message, acknowledge: false)
|
156
|
+
Timeout.timeout(Kafkr::Consumer.configuration.timeout) do
|
157
|
+
sync_uid = send_message.call(message)
|
174
158
|
|
175
159
|
loop do
|
176
160
|
received_message = socket.gets
|
177
161
|
raise LostConnection if received_message.nil?
|
178
|
-
# Assuming Kafkr::Encryptor is defined elsewhere
|
179
162
|
received_message = Kafkr::Encryptor.new.decrypt(received_message.chomp)
|
180
|
-
# Yield every received message to the given block
|
181
163
|
if valid_json?(received_message)
|
182
164
|
payload = yield JSON.parse(received_message), sync_uid if block_given?
|
183
165
|
return payload if payload
|
184
166
|
end
|
185
167
|
end
|
186
168
|
end
|
187
|
-
rescue Timeout::Error
|
188
|
-
puts "Listening timed out after 20 seconds."
|
189
|
-
socket&.close
|
190
|
-
rescue LostConnection
|
191
|
-
attempt += 1
|
192
|
-
wait_time = backoff_time(attempt)
|
193
|
-
puts "Connection lost. Reconnecting in #{wait_time} seconds..."
|
194
|
-
sleep(wait_time)
|
195
|
-
rescue Errno::ECONNREFUSED, Timeout::Error
|
169
|
+
rescue Timeout::Error, LostConnection, Errno::ECONNREFUSED
|
196
170
|
attempt += 1
|
197
171
|
wait_time = backoff_time(attempt)
|
198
|
-
puts "
|
172
|
+
puts "Attempt #{attempt}: Retrying in #{wait_time} seconds..."
|
199
173
|
sleep(wait_time)
|
174
|
+
retry
|
200
175
|
rescue Interrupt
|
201
176
|
puts "Received interrupt signal. Shutting down consumer gracefully..."
|
202
177
|
socket&.close
|
@@ -207,39 +182,9 @@ module Kafkr
|
|
207
182
|
def listen
|
208
183
|
attempt = 0
|
209
184
|
loop do
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
loop do
|
214
|
-
message = socket.gets
|
215
|
-
raise LostConnection if message.nil?
|
216
|
-
|
217
|
-
# Assuming Kafkr::Encryptor is defined elsewhere
|
218
|
-
message = Kafkr::Encryptor.new.decrypt(message.chomp)
|
219
|
-
if valid_json?(message)
|
220
|
-
dispatch_to_handlers(JSON.parse(message)) do |message|
|
221
|
-
yield message if block_given?
|
222
|
-
end
|
223
|
-
else
|
224
|
-
dispatch_to_handlers(message) do |message|
|
225
|
-
yield message if block_given?
|
226
|
-
end
|
227
|
-
end
|
185
|
+
listen_for("dummy", ->(msg) { puts "Listening..." }) do |message|
|
186
|
+
puts "Received message: #{message}"
|
228
187
|
end
|
229
|
-
rescue LostConnection
|
230
|
-
attempt += 1
|
231
|
-
wait_time = backoff_time(attempt)
|
232
|
-
puts "Connection lost. Reconnecting in #{wait_time} seconds..."
|
233
|
-
sleep(wait_time)
|
234
|
-
rescue Errno::ECONNREFUSED, Timeout::Error
|
235
|
-
attempt += 1
|
236
|
-
wait_time = backoff_time(attempt)
|
237
|
-
puts "Failed to connect on attempt #{attempt}. Retrying in #{wait_time} seconds..."
|
238
|
-
sleep(wait_time)
|
239
|
-
rescue Interrupt
|
240
|
-
puts "Received interrupt signal. Shutting down consumer gracefully..."
|
241
|
-
socket&.close
|
242
|
-
exit(0)
|
243
188
|
end
|
244
189
|
end
|
245
190
|
|
@@ -273,6 +218,5 @@ module Kafkr
|
|
273
218
|
end
|
274
219
|
end
|
275
220
|
|
276
|
-
# Assuming the handlers directory is the default location
|
277
221
|
Consumer.load_handlers
|
278
222
|
end
|
data/lib/kafkr/encryptor.rb
CHANGED
data/lib/kafkr/log.rb
CHANGED
@@ -8,22 +8,17 @@ module Kafkr
|
|
8
8
|
@received_file = "./.kafkr/log.txt"
|
9
9
|
@broker = MessageBroker.new
|
10
10
|
@whitelist = load_whitelist
|
11
|
-
@acknowledged_message_ids = load_acknowledged_message_ids
|
12
11
|
end
|
13
12
|
|
14
|
-
def
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
def load_whitelist
|
14
|
+
whitelist = ["localhost", "::1", "127.0.0.1"]
|
15
|
+
if File.exist?("whitelist.txt")
|
16
|
+
File.readlines("whitelist.txt").each do |line|
|
17
|
+
ip = line.strip.sub(/^::ffff:/, "")
|
18
|
+
whitelist << ip
|
19
|
+
end
|
18
20
|
end
|
19
|
-
|
20
|
-
config_path = File.expand_path("./.kafkr/acknowledged_message_ids.txt")
|
21
|
-
return [] unless File.exist?(config_path)
|
22
|
-
|
23
|
-
File.readlines(config_path).map(&:strip)
|
24
|
-
rescue Errno::ENOENT, Errno::EACCES => e
|
25
|
-
puts "Error loading acknowledged_message_ids: #{e.message}"
|
26
|
-
[]
|
21
|
+
whitelist
|
27
22
|
end
|
28
23
|
|
29
24
|
def start
|
@@ -53,14 +48,7 @@ module Kafkr
|
|
53
48
|
message = decryptor.decrypt(encrypted_message.chomp) # Decrypt the message here
|
54
49
|
uuid, message_content = extract_uuid(message)
|
55
50
|
if uuid && message_content
|
56
|
-
|
57
|
-
acknowledge_existing_message(uuid, client)
|
58
|
-
else
|
59
|
-
acknowledge_message(uuid, client)
|
60
|
-
persist_received_message(uuid)
|
61
|
-
@acknowledged_message_ids << uuid
|
62
|
-
@broker.broadcast(message_content)
|
63
|
-
end
|
51
|
+
@broker.broadcast(message_content)
|
64
52
|
else
|
65
53
|
puts "Received invalid message format: #{message}"
|
66
54
|
end
|
@@ -73,17 +61,6 @@ module Kafkr
|
|
73
61
|
end
|
74
62
|
end
|
75
63
|
|
76
|
-
def load_whitelist
|
77
|
-
whitelist = ["localhost", "::1", "127.0.0.1"]
|
78
|
-
if File.exist?("whitelist.txt")
|
79
|
-
File.readlines("whitelist.txt").each do |line|
|
80
|
-
ip = line.strip.sub(/^::ffff:/, "")
|
81
|
-
whitelist << ip
|
82
|
-
end
|
83
|
-
end
|
84
|
-
whitelist
|
85
|
-
end
|
86
|
-
|
87
64
|
def whitelisted?(ip)
|
88
65
|
@whitelist.include?(ip.gsub("::ffff:", ""))
|
89
66
|
end
|
@@ -91,39 +68,15 @@ module Kafkr
|
|
91
68
|
private
|
92
69
|
|
93
70
|
def extract_uuid(message)
|
94
|
-
|
95
|
-
#check if message if valid json
|
71
|
+
# Check if message is valid JSON
|
96
72
|
begin
|
97
73
|
message = JSON.parse(message)
|
98
|
-
|
99
74
|
return message["uuid"], message
|
100
|
-
|
101
75
|
rescue JSON::ParserError => e
|
102
76
|
puts "Received invalid message format: #{message}"
|
103
77
|
match_data = /^(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}): (.+)$/.match(message)
|
104
78
|
match_data ? [match_data[1], match_data[2]] : [nil, nil]
|
105
79
|
end
|
106
|
-
|
107
|
-
end
|
108
|
-
|
109
|
-
def acknowledge_message(uuid, client)
|
110
|
-
puts "Received message with UUID #{uuid}. Acknowledged."
|
111
|
-
acknowledgment_message = "ACK: #{uuid}"
|
112
|
-
client.puts(acknowledgment_message)
|
113
|
-
puts "Acknowledgment sent to producer: #{acknowledgment_message}"
|
114
|
-
end
|
115
|
-
|
116
|
-
def acknowledge_existing_message(uuid, client)
|
117
|
-
puts "Received duplicate message with UUID #{uuid}. Already Acknowledged."
|
118
|
-
acknowledgment_message = "ACK-DUPLICATE: #{uuid}"
|
119
|
-
client.puts(acknowledgment_message)
|
120
|
-
puts "Duplicate acknowledgment sent to producer: #{acknowledgment_message}"
|
121
|
-
end
|
122
|
-
|
123
|
-
def persist_received_message(uuid)
|
124
|
-
File.open("./.kafkr/acknowledged_message_ids.txt", "a") do |file|
|
125
|
-
file.puts(uuid)
|
126
|
-
end
|
127
80
|
end
|
128
81
|
end
|
129
82
|
end
|
data/lib/kafkr/producer.rb
CHANGED
@@ -10,16 +10,12 @@ module Kafkr
|
|
10
10
|
@@file_mutex = Mutex.new
|
11
11
|
|
12
12
|
MESSAGE_QUEUE = "./.kafkr/message_queue.txt"
|
13
|
-
ACKNOWLEDGED_MESSAGE_QUEUE = "./.kafkr/acknowledged_messages.txt"
|
14
13
|
|
15
14
|
def self.configuration
|
16
15
|
FileUtils.mkdir_p "./.kafkr"
|
17
16
|
@configuration ||= OpenStruct.new
|
18
17
|
@configuration.queue_file = MESSAGE_QUEUE
|
19
|
-
@configuration.acknowledged_file = ACKNOWLEDGED_MESSAGE_QUEUE
|
20
18
|
@configuration.message_queue = []
|
21
|
-
@configuration.acknowledged_messages = []
|
22
|
-
@configuration.acknowledged_messages = load_acknowledged_messages
|
23
19
|
load_queue_from_file
|
24
20
|
@configuration.is_json = false
|
25
21
|
@configuration
|
@@ -32,48 +28,29 @@ module Kafkr
|
|
32
28
|
end
|
33
29
|
|
34
30
|
def self.structured_data_to_hash(input:, sync_uid:)
|
35
|
-
# Check the overall structure with regex and make quotes optional
|
36
31
|
unless /\A\w+\s*(=>|<=>)\s*((\w+:\s*['"]?[^'",]*['"]?,\s*)*(\w+:\s*['"]?[^'",]*['"]?)\s*)\z/.match?(input)
|
37
32
|
return input
|
38
33
|
end
|
39
34
|
|
40
35
|
if input.include?("<=>")
|
41
|
-
# puts "sync message"
|
42
|
-
# Extract the type and key-value pairs
|
43
36
|
type, key_values_str = input.split("<=>").map(&:strip)
|
44
|
-
|
45
|
-
# puts type
|
46
|
-
# puts key_values_str
|
47
|
-
|
48
37
|
key_values = key_values_str.scan(/(\w+):\s*['"]?([^'",]*)['"]?/)
|
49
|
-
|
50
|
-
# Convert the array of pairs into a hash, stripping quotes if they exist
|
51
38
|
hash_body = key_values.to_h do |key, value|
|
52
39
|
[key.to_sym, value.strip.gsub(/\A['"]|['"]\z/, "")]
|
53
40
|
end
|
54
|
-
|
55
|
-
# Return the final hash with the type as the key
|
56
41
|
{type.to_sym => hash_body, :sync => true, :sync_uid => sync_uid}
|
57
|
-
|
58
42
|
else
|
59
|
-
# puts "async message"
|
60
|
-
# Extract the type and key-value pairs
|
61
43
|
type, key_values_str = input.split("=>").map(&:strip)
|
62
44
|
key_values = key_values_str.scan(/(\w+):\s*['"]?([^'",]*)['"]?/)
|
63
|
-
|
64
|
-
# Convert the array of pairs into a hash, stripping quotes if they exist
|
65
45
|
hash_body = key_values.to_h do |key, value|
|
66
46
|
[key.to_sym, value.strip.gsub(/\A['"]|['"]\z/, "")]
|
67
47
|
end
|
68
|
-
|
69
|
-
# Return the final hash with the type as the key
|
70
48
|
{type.to_sym => hash_body}
|
71
49
|
end
|
72
50
|
end
|
73
51
|
|
74
|
-
def self.send_message(message
|
52
|
+
def self.send_message(message)
|
75
53
|
uuid = SecureRandom.uuid
|
76
|
-
|
77
54
|
message_with_uuid = nil
|
78
55
|
|
79
56
|
if Kafkr::Producer.configuration.is_json
|
@@ -91,28 +68,14 @@ module Kafkr
|
|
91
68
|
end
|
92
69
|
end
|
93
70
|
|
94
|
-
# Encrypt the message here
|
95
71
|
encrypted_message_with_uuid = Kafkr::Encryptor.new.encrypt(message_with_uuid)
|
96
72
|
|
97
73
|
begin
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
listen_for_acknowledgments(socket) if acknowledge
|
102
|
-
send_queued_messages(socket)
|
103
|
-
# Send the encrypted message instead of the plain one
|
104
|
-
socket.puts(encrypted_message_with_uuid)
|
105
|
-
else
|
106
|
-
puts "Message with UUID #{uuid} has already been acknowledged. Skipping."
|
107
|
-
end
|
108
|
-
else
|
109
|
-
socket = TCPSocket.new(@configuration.host, @configuration.port)
|
110
|
-
send_queued_messages(socket)
|
111
|
-
socket.puts(encrypted_message_with_uuid)
|
112
|
-
end
|
74
|
+
socket = TCPSocket.new(@configuration.host, @configuration.port)
|
75
|
+
send_queued_messages(socket)
|
76
|
+
socket.puts(encrypted_message_with_uuid)
|
113
77
|
rescue Errno::ECONNREFUSED
|
114
78
|
puts "Connection refused. Queuing message: #{encrypted_message_with_uuid}"
|
115
|
-
# Queue the encrypted message
|
116
79
|
@configuration.message_queue.push(encrypted_message_with_uuid)
|
117
80
|
save_queue_to_file
|
118
81
|
rescue Errno::EPIPE
|
@@ -124,36 +87,15 @@ module Kafkr
|
|
124
87
|
end
|
125
88
|
|
126
89
|
def self.send_message_and_wait(message)
|
127
|
-
# Using method(:send_message) to pass the send_message method as a callable object
|
128
|
-
|
129
90
|
Consumer.new.listen_for(message, method(:send_message)) do |received_message, sync_uid|
|
130
|
-
if received_message.key? "reply"
|
131
|
-
|
132
|
-
received_message["reply"].dig("payload")
|
133
|
-
end
|
91
|
+
if received_message.key? "reply" and received_message["reply"].dig("uuid") == sync_uid
|
92
|
+
received_message["reply"].dig("payload")
|
134
93
|
end
|
135
94
|
end
|
136
95
|
end
|
137
96
|
|
138
97
|
private
|
139
98
|
|
140
|
-
def self.listen_for_acknowledgments(socket)
|
141
|
-
Thread.new do
|
142
|
-
while line = socket.gets
|
143
|
-
line = line.chomp
|
144
|
-
if line.start_with?("ACK:")
|
145
|
-
uuid = line.split(" ")[1]
|
146
|
-
handle_acknowledgment(uuid)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def self.handle_acknowledgment(uuid)
|
153
|
-
@configuration.acknowledged_messages << uuid
|
154
|
-
save_acknowledged_messages
|
155
|
-
end
|
156
|
-
|
157
99
|
def self.retry_connection(message_with_uuid)
|
158
100
|
sleep(5)
|
159
101
|
send_message(message_with_uuid)
|
@@ -182,24 +124,6 @@ module Kafkr
|
|
182
124
|
end
|
183
125
|
end
|
184
126
|
|
185
|
-
def self.load_acknowledged_messages
|
186
|
-
@@file_mutex.synchronize do
|
187
|
-
if File.exist?(@configuration.acknowledged_file)
|
188
|
-
File.readlines(@configuration.acknowledged_file).map(&:chomp)
|
189
|
-
else
|
190
|
-
[]
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
def self.save_acknowledged_messages
|
196
|
-
@@file_mutex.synchronize do
|
197
|
-
File.open(@configuration.acknowledged_file, "w") do |file|
|
198
|
-
file.puts(@configuration.acknowledged_messages)
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
127
|
def self.logger
|
204
128
|
@logger ||= Logger.new(STDOUT)
|
205
129
|
end
|
data/lib/kafkr/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kafkr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Delaney Kuldvee Burke
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gibberish
|
@@ -35,6 +35,7 @@ executables:
|
|
35
35
|
extensions: []
|
36
36
|
extra_rdoc_files: []
|
37
37
|
files:
|
38
|
+
- ".DS_Store"
|
38
39
|
- ".rspec"
|
39
40
|
- ".standard.yml"
|
40
41
|
- README.md
|
@@ -71,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
72
|
- !ruby/object:Gem::Version
|
72
73
|
version: '0'
|
73
74
|
requirements: []
|
74
|
-
rubygems_version: 3.5.
|
75
|
+
rubygems_version: 3.5.5
|
75
76
|
signing_key:
|
76
77
|
specification_version: 4
|
77
78
|
summary: A homage to kafkr implmented in ruby
|