smart_message 0.0.7 â 0.0.9
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/.gitignore +1 -0
- data/.irbrc +24 -0
- data/CHANGELOG.md +143 -0
- data/Gemfile.lock +6 -1
- data/README.md +289 -15
- data/docs/README.md +3 -1
- data/docs/addressing.md +119 -13
- data/docs/architecture.md +68 -0
- data/docs/dead_letter_queue.md +673 -0
- data/docs/dispatcher.md +87 -0
- data/docs/examples.md +59 -1
- data/docs/getting-started.md +8 -1
- data/docs/logging.md +382 -326
- data/docs/message_filtering.md +451 -0
- data/examples/01_point_to_point_orders.rb +54 -53
- data/examples/02_publish_subscribe_events.rb +14 -10
- data/examples/03_many_to_many_chat.rb +16 -8
- data/examples/04_redis_smart_home_iot.rb +20 -10
- data/examples/05_proc_handlers.rb +12 -11
- data/examples/06_custom_logger_example.rb +95 -100
- data/examples/07_error_handling_scenarios.rb +4 -2
- data/examples/08_entity_addressing_basic.rb +18 -6
- data/examples/08_entity_addressing_with_filtering.rb +27 -9
- data/examples/09_dead_letter_queue_demo.rb +559 -0
- data/examples/09_regex_filtering_microservices.rb +407 -0
- data/examples/10_header_block_configuration.rb +263 -0
- data/examples/11_global_configuration_example.rb +219 -0
- data/examples/README.md +102 -0
- data/examples/dead_letters.jsonl +12 -0
- data/examples/performance_metrics/benchmark_results_ractor_20250818_205603.json +135 -0
- data/examples/performance_metrics/benchmark_results_ractor_20250818_205831.json +135 -0
- data/examples/performance_metrics/benchmark_results_test_20250818_204942.json +130 -0
- data/examples/performance_metrics/benchmark_results_threadpool_20250818_204942.json +130 -0
- data/examples/performance_metrics/benchmark_results_threadpool_20250818_204959.json +130 -0
- data/examples/performance_metrics/benchmark_results_threadpool_20250818_205044.json +130 -0
- data/examples/performance_metrics/benchmark_results_threadpool_20250818_205109.json +130 -0
- data/examples/performance_metrics/benchmark_results_threadpool_20250818_205252.json +130 -0
- data/examples/performance_metrics/benchmark_results_unknown_20250819_172852.json +130 -0
- data/examples/performance_metrics/compare_benchmarks.rb +519 -0
- data/examples/performance_metrics/dead_letters.jsonl +3100 -0
- data/examples/performance_metrics/performance_benchmark.rb +344 -0
- data/examples/show_logger.rb +367 -0
- data/examples/show_me.rb +145 -0
- data/examples/temp.txt +94 -0
- data/examples/tmux_chat/bot_agent.rb +4 -2
- data/examples/tmux_chat/human_agent.rb +4 -2
- data/examples/tmux_chat/room_monitor.rb +4 -2
- data/examples/tmux_chat/shared_chat_system.rb +6 -3
- data/lib/smart_message/addressing.rb +259 -0
- data/lib/smart_message/base.rb +121 -599
- data/lib/smart_message/circuit_breaker.rb +23 -6
- data/lib/smart_message/configuration.rb +199 -0
- data/lib/smart_message/dead_letter_queue.rb +361 -0
- data/lib/smart_message/dispatcher.rb +90 -49
- data/lib/smart_message/header.rb +5 -0
- data/lib/smart_message/logger/base.rb +21 -1
- data/lib/smart_message/logger/default.rb +88 -138
- data/lib/smart_message/logger/lumberjack.rb +324 -0
- data/lib/smart_message/logger/null.rb +81 -0
- data/lib/smart_message/logger.rb +17 -9
- data/lib/smart_message/messaging.rb +100 -0
- data/lib/smart_message/plugins.rb +132 -0
- data/lib/smart_message/serializer/base.rb +25 -8
- data/lib/smart_message/serializer/json.rb +5 -4
- data/lib/smart_message/subscription.rb +193 -0
- data/lib/smart_message/transport/base.rb +84 -53
- data/lib/smart_message/transport/memory_transport.rb +7 -5
- data/lib/smart_message/transport/redis_transport.rb +15 -45
- data/lib/smart_message/transport/stdout_transport.rb +18 -8
- data/lib/smart_message/transport.rb +1 -34
- data/lib/smart_message/utilities.rb +142 -0
- data/lib/smart_message/version.rb +1 -1
- data/lib/smart_message/versioning.rb +85 -0
- data/lib/smart_message/wrapper.rb.bak +132 -0
- data/lib/smart_message.rb +74 -27
- data/smart_message.gemspec +3 -0
- metadata +77 -3
- data/lib/smart_message/serializer.rb +0 -10
- data/lib/smart_message/wrapper.rb +0 -43
@@ -36,7 +36,8 @@ class UserEventMessage < SmartMessage::Base
|
|
36
36
|
end
|
37
37
|
|
38
38
|
# Default processor - just logs the event
|
39
|
-
def self.process(
|
39
|
+
def self.process(wrapper)
|
40
|
+
message_header, message_payload = wrapper.split
|
40
41
|
event_data = JSON.parse(message_payload)
|
41
42
|
puts "đĄ Event broadcasted: #{event_data['event_type']} for user #{event_data['user_id']}"
|
42
43
|
end
|
@@ -50,12 +51,13 @@ class EmailService
|
|
50
51
|
UserEventMessage.subscribe('EmailService.handle_user_event')
|
51
52
|
end
|
52
53
|
|
53
|
-
def self.handle_user_event(
|
54
|
+
def self.handle_user_event(wrapper)
|
54
55
|
service = new
|
55
|
-
service.process_event(
|
56
|
+
service.process_event(wrapper)
|
56
57
|
end
|
57
58
|
|
58
|
-
def process_event(
|
59
|
+
def process_event(wrapper)
|
60
|
+
message_header, message_payload = wrapper.split
|
59
61
|
event_data = JSON.parse(message_payload)
|
60
62
|
|
61
63
|
case event_data['event_type']
|
@@ -105,12 +107,13 @@ class SMSService
|
|
105
107
|
UserEventMessage.subscribe('SMSService.handle_user_event')
|
106
108
|
end
|
107
109
|
|
108
|
-
def self.handle_user_event(
|
110
|
+
def self.handle_user_event(wrapper)
|
109
111
|
service = new
|
110
|
-
service.process_event(
|
112
|
+
service.process_event(wrapper)
|
111
113
|
end
|
112
114
|
|
113
|
-
def process_event(
|
115
|
+
def process_event(wrapper)
|
116
|
+
message_header, message_payload = wrapper.split
|
114
117
|
event_data = JSON.parse(message_payload)
|
115
118
|
|
116
119
|
case event_data['event_type']
|
@@ -170,17 +173,18 @@ class AuditService
|
|
170
173
|
UserEventMessage.subscribe('AuditService.handle_user_event')
|
171
174
|
end
|
172
175
|
|
173
|
-
def self.handle_user_event(
|
176
|
+
def self.handle_user_event(wrapper)
|
174
177
|
# Use a singleton pattern for persistent audit log
|
175
178
|
@@instance ||= new
|
176
|
-
@@instance.process_event(
|
179
|
+
@@instance.process_event(wrapper)
|
177
180
|
end
|
178
181
|
|
179
182
|
def self.get_summary
|
180
183
|
@@instance&.get_audit_summary || {}
|
181
184
|
end
|
182
185
|
|
183
|
-
def process_event(
|
186
|
+
def process_event(wrapper)
|
187
|
+
message_header, message_payload = wrapper.split
|
184
188
|
event_data = JSON.parse(message_payload)
|
185
189
|
|
186
190
|
audit_entry = {
|
@@ -40,7 +40,8 @@ class ChatMessage < SmartMessage::Base
|
|
40
40
|
serializer SmartMessage::Serializer::JSON.new
|
41
41
|
end
|
42
42
|
|
43
|
-
def self.process(
|
43
|
+
def self.process(wrapper)
|
44
|
+
message_header, message_payload = wrapper.split
|
44
45
|
chat_data = JSON.parse(message_payload)
|
45
46
|
puts "đŦ Chat message in #{chat_data['room_id']}: #{chat_data['content']}"
|
46
47
|
end
|
@@ -68,7 +69,8 @@ class BotCommandMessage < SmartMessage::Base
|
|
68
69
|
serializer SmartMessage::Serializer::JSON.new
|
69
70
|
end
|
70
71
|
|
71
|
-
def self.process(
|
72
|
+
def self.process(wrapper)
|
73
|
+
message_header, message_payload = wrapper.split
|
72
74
|
command_data = JSON.parse(message_payload)
|
73
75
|
puts "đ¤ Bot command: #{command_data['command']} in #{command_data['room_id']}"
|
74
76
|
end
|
@@ -96,7 +98,8 @@ class SystemNotificationMessage < SmartMessage::Base
|
|
96
98
|
serializer SmartMessage::Serializer::JSON.new
|
97
99
|
end
|
98
100
|
|
99
|
-
def self.process(
|
101
|
+
def self.process(wrapper)
|
102
|
+
message_header, message_payload = wrapper.split
|
100
103
|
notif_data = JSON.parse(message_payload)
|
101
104
|
puts "đ System: #{notif_data['content']} in #{notif_data['room_id']}"
|
102
105
|
end
|
@@ -192,7 +195,8 @@ class HumanChatAgent
|
|
192
195
|
@@agents[agent.user_id] = agent
|
193
196
|
end
|
194
197
|
|
195
|
-
def handle_chat_message(
|
198
|
+
def handle_chat_message(wrapper)
|
199
|
+
message_header, message_payload = wrapper.split
|
196
200
|
chat_data = JSON.parse(message_payload)
|
197
201
|
|
198
202
|
# Only process messages from rooms we're in and not our own messages
|
@@ -207,7 +211,8 @@ class HumanChatAgent
|
|
207
211
|
end
|
208
212
|
end
|
209
213
|
|
210
|
-
def handle_system_notification(
|
214
|
+
def handle_system_notification(wrapper)
|
215
|
+
message_header, message_payload = wrapper.split
|
211
216
|
notif_data = JSON.parse(message_payload)
|
212
217
|
|
213
218
|
# Only process notifications from rooms we're in
|
@@ -302,7 +307,8 @@ class BotAgent
|
|
302
307
|
)
|
303
308
|
end
|
304
309
|
|
305
|
-
def self.handle_bot_command(
|
310
|
+
def self.handle_bot_command(wrapper)
|
311
|
+
message_header, message_payload = wrapper.split
|
306
312
|
command_data = JSON.parse(message_payload)
|
307
313
|
@@bots ||= []
|
308
314
|
|
@@ -315,7 +321,8 @@ class BotAgent
|
|
315
321
|
capable_bot&.process_command(command_data)
|
316
322
|
end
|
317
323
|
|
318
|
-
def self.handle_chat_message(
|
324
|
+
def self.handle_chat_message(wrapper)
|
325
|
+
message_header, message_payload = wrapper.split
|
319
326
|
chat_data = JSON.parse(message_payload)
|
320
327
|
@@bots ||= []
|
321
328
|
|
@@ -491,7 +498,8 @@ class RoomManager
|
|
491
498
|
notification.publish
|
492
499
|
end
|
493
500
|
|
494
|
-
def self.handle_system_notification(
|
501
|
+
def self.handle_system_notification(wrapper)
|
502
|
+
message_header, message_payload = wrapper.split
|
495
503
|
@@instance ||= new
|
496
504
|
@@instance.process_system_notification(message_header, message_payload)
|
497
505
|
end
|
@@ -82,7 +82,8 @@ class SensorDataMessage < SmartMessage::Base
|
|
82
82
|
serializer SmartMessage::Serializer::JSON.new
|
83
83
|
end
|
84
84
|
|
85
|
-
def self.process(
|
85
|
+
def self.process(wrapper)
|
86
|
+
message_header, message_payload = wrapper.split
|
86
87
|
sensor_data = JSON.parse(message_payload)
|
87
88
|
icon = case sensor_data['device_type']
|
88
89
|
when 'thermostat' then 'đĄī¸'
|
@@ -116,7 +117,8 @@ class DeviceCommandMessage < SmartMessage::Base
|
|
116
117
|
serializer SmartMessage::Serializer::JSON.new
|
117
118
|
end
|
118
119
|
|
119
|
-
def self.process(
|
120
|
+
def self.process(wrapper)
|
121
|
+
message_header, message_payload = wrapper.split
|
120
122
|
command_data = JSON.parse(message_payload)
|
121
123
|
puts "đī¸ Command sent: #{command_data['command']} to #{command_data['device_id']} (requested by #{command_data['requested_by']})"
|
122
124
|
end
|
@@ -148,7 +150,8 @@ class AlertMessage < SmartMessage::Base
|
|
148
150
|
serializer SmartMessage::Serializer::JSON.new
|
149
151
|
end
|
150
152
|
|
151
|
-
def self.process(
|
153
|
+
def self.process(wrapper)
|
154
|
+
message_header, message_payload = wrapper.split
|
152
155
|
alert_data = JSON.parse(message_payload)
|
153
156
|
severity_icon = case alert_data['severity']
|
154
157
|
when 'low' then 'đ'
|
@@ -176,7 +179,8 @@ class DashboardStatusMessage < SmartMessage::Base
|
|
176
179
|
serializer SmartMessage::Serializer::JSON.new
|
177
180
|
end
|
178
181
|
|
179
|
-
def self.process(
|
182
|
+
def self.process(wrapper)
|
183
|
+
message_header, message_payload = wrapper.split
|
180
184
|
status_data = JSON.parse(message_payload)
|
181
185
|
status_icon = case status_data['system_status']
|
182
186
|
when 'normal' then 'â
'
|
@@ -205,7 +209,8 @@ class SmartThermostat
|
|
205
209
|
DeviceCommandMessage.subscribe("SmartThermostat.handle_command")
|
206
210
|
end
|
207
211
|
|
208
|
-
def self.handle_command(
|
212
|
+
def self.handle_command(wrapper)
|
213
|
+
message_header, message_payload = wrapper.split
|
209
214
|
command_data = JSON.parse(message_payload)
|
210
215
|
|
211
216
|
# Only process commands intended for thermostats with our device ID
|
@@ -288,7 +293,8 @@ class SecurityCamera
|
|
288
293
|
DeviceCommandMessage.subscribe("SecurityCamera.handle_command")
|
289
294
|
end
|
290
295
|
|
291
|
-
def self.handle_command(
|
296
|
+
def self.handle_command(wrapper)
|
297
|
+
message_header, message_payload = wrapper.split
|
292
298
|
command_data = JSON.parse(message_payload)
|
293
299
|
|
294
300
|
# Only process commands intended for cameras with our device ID
|
@@ -398,7 +404,8 @@ class SmartDoorLock
|
|
398
404
|
DeviceCommandMessage.subscribe("SmartDoorLock.handle_command")
|
399
405
|
end
|
400
406
|
|
401
|
-
def self.handle_command(
|
407
|
+
def self.handle_command(wrapper)
|
408
|
+
message_header, message_payload = wrapper.split
|
402
409
|
command_data = JSON.parse(message_payload)
|
403
410
|
|
404
411
|
# Only process commands intended for door locks with our device ID
|
@@ -479,17 +486,20 @@ class IoTDashboard
|
|
479
486
|
DeviceCommandMessage.subscribe("IoTDashboard.log_command")
|
480
487
|
end
|
481
488
|
|
482
|
-
def self.handle_sensor_data(
|
489
|
+
def self.handle_sensor_data(wrapper)
|
490
|
+
message_header, message_payload = wrapper.split
|
483
491
|
@@instance ||= new
|
484
492
|
@@instance.process_sensor_data(message_header, message_payload)
|
485
493
|
end
|
486
494
|
|
487
|
-
def self.handle_alert(
|
495
|
+
def self.handle_alert(wrapper)
|
496
|
+
message_header, message_payload = wrapper.split
|
488
497
|
@@instance ||= new
|
489
498
|
@@instance.process_alert(message_header, message_payload)
|
490
499
|
end
|
491
500
|
|
492
|
-
def self.log_command(
|
501
|
+
def self.log_command(wrapper)
|
502
|
+
message_header, message_payload = wrapper.split
|
493
503
|
@@instance ||= new
|
494
504
|
@@instance.log_device_command(message_header, message_payload)
|
495
505
|
end
|
@@ -33,7 +33,8 @@ class NotificationMessage < SmartMessage::Base
|
|
33
33
|
end
|
34
34
|
|
35
35
|
# Default handler
|
36
|
-
def self.process(
|
36
|
+
def self.process(wrapper)
|
37
|
+
message_header, message_payload = wrapper.split
|
37
38
|
data = JSON.parse(message_payload)
|
38
39
|
icon = case data['type']
|
39
40
|
when 'info' then 'âšī¸'
|
@@ -56,8 +57,8 @@ puts
|
|
56
57
|
|
57
58
|
# 2. Block handler
|
58
59
|
puts "2ī¸âŖ Block handler subscription:"
|
59
|
-
block_id = NotificationMessage.subscribe do |
|
60
|
-
data = JSON.parse(
|
60
|
+
block_id = NotificationMessage.subscribe do |wrapper|
|
61
|
+
data = JSON.parse(wrapper._sm_payload)
|
61
62
|
if data['type'] == 'error'
|
62
63
|
puts "đĨ [BLOCK] Critical error logged: #{data['title']}"
|
63
64
|
# Could send to error tracking service here
|
@@ -68,9 +69,9 @@ puts
|
|
68
69
|
|
69
70
|
# 3. Proc handler
|
70
71
|
puts "3ī¸âŖ Proc handler subscription:"
|
71
|
-
audit_logger = proc do |
|
72
|
-
data = JSON.parse(
|
73
|
-
timestamp =
|
72
|
+
audit_logger = proc do |wrapper|
|
73
|
+
data = JSON.parse(wrapper._sm_payload)
|
74
|
+
timestamp = wrapper._sm_header.published_at.strftime('%Y-%m-%d %H:%M:%S')
|
74
75
|
puts "đ [AUDIT] #{timestamp} - User #{data['user_id']}: #{data['type'].upcase}"
|
75
76
|
end
|
76
77
|
|
@@ -80,8 +81,8 @@ puts
|
|
80
81
|
|
81
82
|
# 4. Lambda handler
|
82
83
|
puts "4ī¸âŖ Lambda handler subscription:"
|
83
|
-
warning_filter = lambda do |
|
84
|
-
data = JSON.parse(
|
84
|
+
warning_filter = lambda do |wrapper|
|
85
|
+
data = JSON.parse(wrapper._sm_payload)
|
85
86
|
if data['type'] == 'warning'
|
86
87
|
puts "⥠[LAMBDA] Warning for user #{data['user_id']}: #{data['message']}"
|
87
88
|
end
|
@@ -94,8 +95,8 @@ puts
|
|
94
95
|
# 5. Method handler (traditional, but shown for comparison)
|
95
96
|
puts "5ī¸âŖ Method handler subscription:"
|
96
97
|
class NotificationService
|
97
|
-
def self.handle_notifications(
|
98
|
-
data = JSON.parse(
|
98
|
+
def self.handle_notifications(wrapper)
|
99
|
+
data = JSON.parse(wrapper._sm_payload)
|
99
100
|
puts "đĸ [SERVICE] Processing #{data['type']} notification for user #{data['user_id']}"
|
100
101
|
end
|
101
102
|
end
|
@@ -174,7 +175,7 @@ puts "=" * 60
|
|
174
175
|
|
175
176
|
puts "\nThis example demonstrated:"
|
176
177
|
puts "âĸ â
Default self.process method (traditional)"
|
177
|
-
puts "âĸ â
Block handlers with subscribe { |
|
178
|
+
puts "âĸ â
Block handlers with subscribe { |wrapper| ... } (NEW!)"
|
178
179
|
puts "âĸ â
Proc handlers with subscribe(proc { ... }) (NEW!)"
|
179
180
|
puts "âĸ â
Lambda handlers with subscribe(lambda { ... }) (NEW!)"
|
180
181
|
puts "âĸ â
Method handlers with subscribe('Class.method') (traditional)"
|