smart_message 0.0.12 → 0.0.16

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.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +155 -1
  4. data/Gemfile.lock +6 -6
  5. data/README.md +71 -25
  6. data/docs/core-concepts/architecture.md +5 -10
  7. data/docs/getting-started/examples.md +0 -12
  8. data/docs/getting-started/quick-start.md +4 -9
  9. data/docs/index.md +6 -4
  10. data/docs/reference/serializers.md +160 -488
  11. data/docs/reference/transports.md +47 -146
  12. data/docs/transports/memory-transport.md +2 -1
  13. data/docs/transports/multi-transport.md +484 -0
  14. data/docs/transports/redis-transport-comparison.md +215 -350
  15. data/docs/transports/redis-transport.md +3 -22
  16. data/examples/README.md +6 -9
  17. data/examples/city_scenario/README.md +1 -1
  18. data/examples/city_scenario/messages/emergency_911_message.rb +0 -1
  19. data/examples/city_scenario/messages/emergency_resolved_message.rb +0 -1
  20. data/examples/city_scenario/messages/fire_dispatch_message.rb +0 -1
  21. data/examples/city_scenario/messages/fire_emergency_message.rb +0 -1
  22. data/examples/city_scenario/messages/health_check_message.rb +0 -1
  23. data/examples/city_scenario/messages/health_status_message.rb +0 -1
  24. data/examples/city_scenario/messages/police_dispatch_message.rb +0 -1
  25. data/examples/city_scenario/messages/silent_alarm_message.rb +0 -1
  26. data/examples/file/00_run_all_file_demos.rb +260 -0
  27. data/examples/file/01_basic_file_transport_demo.rb +237 -0
  28. data/examples/file/02_fifo_transport_demo.rb +289 -0
  29. data/examples/file/03_file_watching_demo.rb +332 -0
  30. data/examples/file/04_multi_transport_file_demo.rb +432 -0
  31. data/examples/file/README.md +257 -0
  32. data/examples/memory/00_run_all_demos.rb +317 -0
  33. data/examples/memory/01_message_deduplication_demo.rb +18 -32
  34. data/examples/memory/02_dead_letter_queue_demo.rb +9 -12
  35. data/examples/memory/03_point_to_point_orders.rb +3 -5
  36. data/examples/memory/04_publish_subscribe_events.rb +15 -16
  37. data/examples/memory/05_many_to_many_chat.rb +19 -22
  38. data/examples/memory/06_stdout_publish_only.rb +145 -0
  39. data/examples/memory/07_proc_handlers_demo.rb +13 -14
  40. data/examples/memory/08_custom_logger_demo.rb +136 -140
  41. data/examples/memory/09_error_handling_demo.rb +7 -10
  42. data/examples/memory/10_entity_addressing_basic.rb +25 -31
  43. data/examples/memory/11_entity_addressing_with_filtering.rb +32 -36
  44. data/examples/memory/12_regex_filtering_microservices.rb +10 -11
  45. data/examples/memory/13_header_block_configuration.rb +0 -5
  46. data/examples/memory/14_global_configuration_demo.rb +12 -14
  47. data/examples/memory/15_logger_demo.rb +0 -1
  48. data/examples/memory/README.md +37 -20
  49. data/examples/memory/log/demo_app.log.1 +100 -0
  50. data/examples/memory/log/demo_app.log.2 +100 -0
  51. data/examples/multi_transport_example.rb +114 -0
  52. data/examples/redis/01_smart_home_iot_demo.rb +20 -24
  53. data/examples/redis/README.md +0 -2
  54. data/examples/utilities/box_it.rb +12 -0
  55. data/examples/utilities/doing.rb +19 -0
  56. data/examples/utilities/temp.md +28 -0
  57. data/lib/smart_message/base.rb +24 -17
  58. data/lib/smart_message/configuration.rb +2 -23
  59. data/lib/smart_message/dead_letter_queue.rb +1 -1
  60. data/lib/smart_message/errors.rb +3 -0
  61. data/lib/smart_message/header.rb +1 -1
  62. data/lib/smart_message/logger/default.rb +1 -1
  63. data/lib/smart_message/messaging.rb +37 -66
  64. data/lib/smart_message/plugins.rb +42 -41
  65. data/lib/smart_message/serializer/base.rb +1 -1
  66. data/lib/smart_message/serializer.rb +3 -2
  67. data/lib/smart_message/subscription.rb +18 -20
  68. data/lib/smart_message/transport/async_publish_queue.rb +284 -0
  69. data/lib/smart_message/transport/base.rb +42 -8
  70. data/lib/smart_message/transport/fifo_operations.rb +264 -0
  71. data/lib/smart_message/transport/file_operations.rb +200 -0
  72. data/lib/smart_message/transport/file_transport.rb +149 -0
  73. data/lib/smart_message/transport/file_watching.rb +72 -0
  74. data/lib/smart_message/transport/memory_transport.rb +23 -4
  75. data/lib/smart_message/transport/partitioned_files.rb +46 -0
  76. data/lib/smart_message/transport/redis_transport.rb +11 -0
  77. data/lib/smart_message/transport/registry.rb +0 -1
  78. data/lib/smart_message/transport/stdout_transport.rb +73 -41
  79. data/lib/smart_message/transport/stdout_transport.rb.backup +88 -0
  80. data/lib/smart_message/transport.rb +0 -1
  81. data/lib/smart_message/version.rb +1 -1
  82. metadata +25 -37
  83. data/docs/guides/redis-queue-getting-started.md +0 -697
  84. data/docs/guides/redis-queue-patterns.md +0 -889
  85. data/docs/guides/redis-queue-production.md +0 -1091
  86. data/docs/transports/redis-enhanced-transport.md +0 -524
  87. data/docs/transports/redis-queue-transport.md +0 -1304
  88. data/examples/redis_enhanced/README.md +0 -319
  89. data/examples/redis_enhanced/enhanced_01_basic_patterns.rb +0 -233
  90. data/examples/redis_enhanced/enhanced_02_fluent_api.rb +0 -331
  91. data/examples/redis_enhanced/enhanced_03_dual_publishing.rb +0 -281
  92. data/examples/redis_enhanced/enhanced_04_advanced_routing.rb +0 -419
  93. data/examples/redis_queue/01_basic_messaging.rb +0 -221
  94. data/examples/redis_queue/01_comprehensive_examples.rb +0 -508
  95. data/examples/redis_queue/02_pattern_routing.rb +0 -405
  96. data/examples/redis_queue/03_fluent_api.rb +0 -422
  97. data/examples/redis_queue/04_load_balancing.rb +0 -486
  98. data/examples/redis_queue/05_microservices.rb +0 -735
  99. data/examples/redis_queue/06_emergency_alerts.rb +0 -777
  100. data/examples/redis_queue/07_queue_management.rb +0 -587
  101. data/examples/redis_queue/README.md +0 -366
  102. data/examples/redis_queue/enhanced_01_basic_patterns.rb +0 -233
  103. data/examples/redis_queue/enhanced_02_fluent_api.rb +0 -331
  104. data/examples/redis_queue/enhanced_03_dual_publishing.rb +0 -281
  105. data/examples/redis_queue/enhanced_04_advanced_routing.rb +0 -419
  106. data/examples/redis_queue/redis_queue_architecture.svg +0 -148
  107. data/ideas/README.md +0 -41
  108. data/ideas/agents.md +0 -1001
  109. data/ideas/database_transport.md +0 -980
  110. data/ideas/improvement.md +0 -359
  111. data/ideas/meshage.md +0 -1788
  112. data/ideas/message_discovery.md +0 -178
  113. data/ideas/message_schema.md +0 -1381
  114. data/lib/smart_message/transport/redis_enhanced_transport.rb +0 -399
  115. data/lib/smart_message/transport/redis_queue_transport.rb +0 -555
  116. data/lib/smart_message/wrapper.rb.bak +0 -132
  117. /data/examples/memory/{06_pretty_print_demo.rb → 16_pretty_print_demo.rb} +0 -0
@@ -0,0 +1,317 @@
1
+ #!/usr/bin/env ruby
2
+ # examples/memory/00_run_all_demos.rb
3
+ #
4
+ # Master Demo Runner - Executes All SmartMessage Memory Transport Examples
5
+ #
6
+ # This script runs all the demo programs in the examples/memory directory
7
+ # in sequence, with clear banners to show which demo is currently running.
8
+
9
+ require 'fileutils'
10
+ require 'pathname'
11
+
12
+ class SmartMessageDemoRunner
13
+ DEMO_PROGRAMS = [
14
+ {
15
+ file: "01_message_deduplication_demo.rb",
16
+ title: "Message Deduplication with DDQ",
17
+ description: "Demonstrates message deduplication patterns and duplicate message prevention",
18
+ duration: "~10 seconds"
19
+ },
20
+ {
21
+ file: "02_dead_letter_queue_demo.rb",
22
+ title: "Dead Letter Queue & Error Handling",
23
+ description: "Shows DLQ pattern implementation with circuit breakers and error recovery",
24
+ duration: "~15 seconds"
25
+ },
26
+ {
27
+ file: "03_point_to_point_orders.rb",
28
+ title: "Point-to-Point Order Processing",
29
+ description: "Order processing system with 1:1 messaging between OrderService and PaymentService",
30
+ duration: "~8 seconds"
31
+ },
32
+ {
33
+ file: "04_publish_subscribe_events.rb",
34
+ title: "Publish-Subscribe Event Broadcasting",
35
+ description: "Event-driven architecture with multiple subscribers (Email, SMS, Audit)",
36
+ duration: "~10 seconds"
37
+ },
38
+ {
39
+ file: "05_many_to_many_chat.rb",
40
+ title: "Many-to-Many Chat System",
41
+ description: "Interactive chat system with rooms, bots, and human agents",
42
+ duration: "~12 seconds"
43
+ },
44
+ {
45
+ file: "06_stdout_publish_only.rb",
46
+ title: "STDOUT Transport (Publish-Only)",
47
+ description: "Demonstrates STDOUT transport for logging and external tool integration",
48
+ duration: "~5 seconds"
49
+ },
50
+ {
51
+ file: "07_proc_handlers_demo.rb",
52
+ title: "Proc-Based Message Handlers",
53
+ description: "Flexible message handlers using blocks, procs, lambdas, and methods",
54
+ duration: "~8 seconds"
55
+ },
56
+ {
57
+ file: "08_custom_logger_demo.rb",
58
+ title: "Custom Logging Implementations",
59
+ description: "Advanced logging with multiple loggers and custom formatting",
60
+ duration: "~12 seconds"
61
+ },
62
+ {
63
+ file: "09_error_handling_demo.rb",
64
+ title: "Comprehensive Error Handling",
65
+ description: "Error handling strategies, validation failures, and graceful degradation",
66
+ duration: "~10 seconds"
67
+ },
68
+ {
69
+ file: "10_entity_addressing_basic.rb",
70
+ title: "Entity Addressing Basics",
71
+ description: "Message routing by entity addresses with FROM/TO/REPLY_TO patterns",
72
+ duration: "~8 seconds"
73
+ },
74
+ {
75
+ file: "11_entity_addressing_with_filtering.rb",
76
+ title: "Advanced Entity Addressing & Filtering",
77
+ description: "Complex filtering patterns with regex-based address matching",
78
+ duration: "~10 seconds"
79
+ },
80
+ {
81
+ file: "12_regex_filtering_microservices.rb",
82
+ title: "Microservices with Regex Filtering",
83
+ description: "Service-to-service communication with environment-based filtering",
84
+ duration: "~8 seconds"
85
+ },
86
+ {
87
+ file: "13_header_block_configuration.rb",
88
+ title: "Header Block Configuration",
89
+ description: "Dynamic header configuration with block-based modification",
90
+ duration: "~6 seconds"
91
+ },
92
+ {
93
+ file: "14_global_configuration_demo.rb",
94
+ title: "Global Configuration Management",
95
+ description: "Global transport settings and configuration inheritance",
96
+ duration: "~8 seconds"
97
+ },
98
+ {
99
+ file: "15_logger_demo.rb",
100
+ title: "Advanced Logger Configuration",
101
+ description: "Logger configuration, log levels, and SmartMessage lifecycle integration",
102
+ duration: "~10 seconds"
103
+ },
104
+ {
105
+ file: "16_pretty_print_demo.rb",
106
+ title: "Message Pretty-Printing",
107
+ description: "Message inspection and debugging with pretty-print formatting",
108
+ duration: "~5 seconds"
109
+ }
110
+ ].freeze
111
+
112
+ def initialize
113
+ @base_dir = File.dirname(__FILE__)
114
+ @total_demos = DEMO_PROGRAMS.length
115
+ @start_time = Time.now
116
+ end
117
+
118
+ def run_all
119
+ print_main_banner
120
+ print_overview
121
+
122
+ DEMO_PROGRAMS.each_with_index do |demo, index|
123
+ run_demo(demo, index + 1)
124
+ end
125
+
126
+ print_completion_summary
127
+ end
128
+
129
+ private
130
+
131
+ # Helper method to calculate visual width of string accounting for emoji
132
+ def visual_width(str)
133
+ # Remove ANSI escape sequences if any
134
+ clean_str = str.gsub(/\e\[[0-9;]*m/, '')
135
+
136
+ # Count emoji and other wide characters
137
+ emoji_count = clean_str.scan(/[\u{1F600}-\u{1F64F}]|[\u{1F300}-\u{1F5FF}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]/).length
138
+
139
+ # Each emoji takes up 2 visual columns but counts as 1 character
140
+ # So we add the emoji_count to get the actual visual width
141
+ clean_str.length + emoji_count
142
+ end
143
+
144
+ # Helper method to pad string to exact visual width
145
+ def pad_to_width(str, target_width)
146
+ current_width = visual_width(str)
147
+ if current_width <= target_width
148
+ str + (" " * (target_width - current_width))
149
+ else
150
+ # Truncate if too long, being careful about emoji
151
+ str[0...(target_width - current_width)]
152
+ end
153
+ end
154
+
155
+ def print_main_banner
156
+ puts "\n"
157
+ puts "█" * 100
158
+ puts "█" + " " * 98 + "█"
159
+ puts "█" + pad_to_width(" 🚀 SMARTMESSAGE COMPREHENSIVE DEMO SUITE 🚀 ", 98) + "█"
160
+ puts "█" + " " * 98 + "█"
161
+ puts "█" + pad_to_width(" Running all #{@total_demos} demo programs to showcase SmartMessage capabilities ", 98) + "█"
162
+ puts "█" + " " * 98 + "█"
163
+ puts "█" * 100
164
+ puts "\n"
165
+ end
166
+
167
+ def print_overview
168
+ puts "📋 DEMO OVERVIEW:"
169
+ puts "=" * 80
170
+
171
+ DEMO_PROGRAMS.each_with_index do |demo, index|
172
+ printf " %2d. %-35s %s\n",
173
+ index + 1,
174
+ demo[:title],
175
+ "(#{demo[:duration]})"
176
+ end
177
+
178
+ total_time = DEMO_PROGRAMS.sum { |demo|
179
+ demo[:duration].scan(/\d+/).first.to_i
180
+ }
181
+
182
+ puts "=" * 80
183
+ puts "📊 Total estimated time: ~#{total_time} seconds (~#{(total_time/60.0).round(1)} minutes)"
184
+ puts "🎯 Each demo runs independently with clear separation"
185
+ puts "⏸️ Press Ctrl+C at any time to stop the demo suite"
186
+ puts "\n"
187
+ end
188
+
189
+ def run_demo(demo, demo_number)
190
+ file_path = File.join(@base_dir, demo[:file])
191
+
192
+ unless File.exist?(file_path)
193
+ print_error_banner(demo_number, demo[:title], "File not found: #{demo[:file]}")
194
+ return
195
+ end
196
+
197
+ print_demo_banner(demo_number, demo)
198
+
199
+ start_time = Time.now
200
+ begin
201
+ # Execute the demo program
202
+ success = system("cd #{@base_dir} && ruby #{demo[:file]}")
203
+ end_time = Time.now
204
+
205
+ if success
206
+ print_demo_completion(demo_number, demo[:title], end_time - start_time)
207
+ else
208
+ print_demo_error(demo_number, demo[:title], "Demo exited with error code")
209
+ end
210
+
211
+ rescue Interrupt
212
+ puts "\n"
213
+ puts "🛑 DEMO SUITE INTERRUPTED BY USER"
214
+ puts " Completed #{demo_number - 1} of #{@total_demos} demos"
215
+ exit(0)
216
+ rescue => e
217
+ print_demo_error(demo_number, demo[:title], e.message)
218
+ end
219
+
220
+ print_demo_separator
221
+ end
222
+
223
+ def print_demo_banner(demo_number, demo)
224
+ puts "┌" + "─" * 98 + "┐"
225
+ puts "│" + " " * 98 + "│"
226
+ puts "│" + pad_to_width("🔥 DEMO #{demo_number.to_s.rjust(2, '0')}/#{@total_demos.to_s.rjust(2, '0')}: #{demo[:title]}", 98) + "│"
227
+ puts "│" + " " * 98 + "│"
228
+ puts "│" + pad_to_width("📝 #{demo[:description]}", 98) + "│"
229
+ puts "│" + pad_to_width("⏱️ Expected duration: #{demo[:duration]}", 98) + "│"
230
+ puts "│" + pad_to_width("📁 File: #{demo[:file]}", 98) + "│"
231
+ puts "│" + " " * 98 + "│"
232
+ puts "└" + "─" * 98 + "┘"
233
+ puts "\n"
234
+ end
235
+
236
+ def print_demo_completion(demo_number, title, actual_time)
237
+ puts "\n"
238
+ puts "✅ DEMO #{demo_number.to_s.rjust(2, '0')} COMPLETED: #{title}"
239
+ puts " ⏱️ Actual execution time: #{actual_time.round(2)} seconds"
240
+ puts "\n"
241
+ end
242
+
243
+ def print_demo_error(demo_number, title, error_message)
244
+ puts "\n"
245
+ puts "❌ DEMO #{demo_number.to_s.rjust(2, '0')} FAILED: #{title}"
246
+ puts " 🚨 Error: #{error_message}"
247
+ puts " ⏭️ Continuing with next demo..."
248
+ puts "\n"
249
+ end
250
+
251
+ def print_error_banner(demo_number, title, error_message)
252
+ puts "┌" + "─" * 98 + "┐"
253
+ puts "│" + pad_to_width("❌ DEMO #{demo_number.to_s.rjust(2, '0')}/#{@total_demos.to_s.rjust(2, '0')} ERROR: #{title}", 98) + "│"
254
+ puts "│" + " " * 98 + "│"
255
+ puts "│" + pad_to_width("🚨 #{error_message}", 98) + "│"
256
+ puts "│" + " " * 98 + "│"
257
+ puts "└" + "─" * 98 + "┘"
258
+ puts "\n"
259
+ end
260
+
261
+ def print_demo_separator
262
+ puts "═" * 100
263
+ puts "\n"
264
+ sleep(1) # Brief pause between demos for readability
265
+ end
266
+
267
+ def print_completion_summary
268
+ total_time = Time.now - @start_time
269
+
270
+ puts "\n"
271
+ puts "🏁" * 50
272
+ puts "🏁" + " " * 96 + "🏁"
273
+ puts "🏁" + pad_to_width(" 🎉 ALL DEMOS COMPLETED SUCCESSFULLY! 🎉 ", 96) + "🏁"
274
+ puts "🏁" + " " * 96 + "🏁"
275
+ puts "🏁" + pad_to_width(" Total execution time: #{total_time.round(2)} seconds (#{(total_time/60.0).round(2)} minutes) ", 96) + "🏁"
276
+ puts "🏁" + pad_to_width(" Demos completed: #{@total_demos} ", 96) + "🏁"
277
+ puts "🏁" + " " * 96 + "🏁"
278
+ puts "🏁" * 50
279
+ puts "\n"
280
+
281
+ puts "📋 WHAT YOU'VE SEEN:"
282
+ puts "=" * 80
283
+ puts "✅ Message deduplication and Dead Letter Queue patterns"
284
+ puts "✅ Point-to-point, publish-subscribe, and many-to-many messaging"
285
+ puts "✅ STDOUT transport for debugging and external integration"
286
+ puts "✅ Advanced message handlers (procs, blocks, lambdas)"
287
+ puts "✅ Comprehensive logging and error handling strategies"
288
+ puts "✅ Entity addressing and advanced message filtering"
289
+ puts "✅ Microservices communication patterns"
290
+ puts "✅ Configuration management and message inspection"
291
+ puts "\n"
292
+
293
+ puts "🚀 NEXT STEPS:"
294
+ puts "=" * 80
295
+ puts "• Explore individual demos: ruby examples/memory/<demo_file>"
296
+ puts "• Check out Redis Queue examples: examples/redis_queue/"
297
+ puts "• View comprehensive documentation: docs/"
298
+ puts "• Start building with SmartMessage in your projects!"
299
+ puts "\n"
300
+
301
+ puts "💡 For more information:"
302
+ puts " 📖 README.md - Getting started guide"
303
+ puts " 🔧 examples/memory/README.md - Detailed example descriptions"
304
+ puts " 📚 https://github.com/MadBomber/smart_message - Full documentation"
305
+ puts "\n"
306
+ end
307
+ end
308
+
309
+ # Allow running directly or requiring as a library
310
+ if __FILE__ == $0
311
+ puts "Starting SmartMessage Demo Suite..."
312
+ puts "Press Ctrl+C to interrupt at any time."
313
+ puts "\n"
314
+
315
+ runner = SmartMessageDemoRunner.new
316
+ runner.run_all
317
+ end
@@ -64,11 +64,9 @@ def demonstrate_deduplication
64
64
  transport = SmartMessage::Transport::MemoryTransport.new
65
65
 
66
66
  OrderMessage.transport(transport)
67
- OrderMessage.serializer(SmartMessage::Serializer::Json.new)
68
67
  OrderMessage.subscribe('OrderMessage.process')
69
68
 
70
69
  NotificationMessage.transport(transport)
71
- NotificationMessage.serializer(SmartMessage::Serializer::Json.new)
72
70
  NotificationMessage.subscribe('NotificationMessage.process')
73
71
 
74
72
  # Clear any previous state
@@ -91,21 +89,13 @@ def demonstrate_deduplication
91
89
  # Test 1: OrderMessage with deduplication
92
90
  puts "--- Test 1: OrderMessage (with deduplication) ---"
93
91
 
94
- # Create header with specific UUID
95
- header = SmartMessage::Header.new(
96
- uuid: uuid,
97
- message_class: "OrderMessage",
98
- published_at: Time.now,
99
- publisher_pid: Process.pid,
100
- version: 1,
101
- from: "order-service"
102
- )
103
-
104
- # First message
92
+ # First message (create normally, then set UUID for testing)
105
93
  order1 = OrderMessage.new(
106
- _sm_header: header,
107
- _sm_payload: { order_id: "ORD-001", amount: 99.99 }
94
+ order_id: "ORD-001",
95
+ amount: 99.99
108
96
  )
97
+ # Override UUID for deduplication testing
98
+ order1._sm_header.uuid = uuid
109
99
 
110
100
  puts "Publishing first order message..."
111
101
  order1.publish
@@ -113,9 +103,11 @@ def demonstrate_deduplication
113
103
 
114
104
  # Second message with SAME UUID (should be deduplicated)
115
105
  order2 = OrderMessage.new(
116
- _sm_header: header,
117
- _sm_payload: { order_id: "ORD-002", amount: 149.99 }
106
+ order_id: "ORD-002",
107
+ amount: 149.99
118
108
  )
109
+ # Use same UUID to test deduplication
110
+ order2._sm_header.uuid = uuid
119
111
 
120
112
  puts "Publishing duplicate order message (same UUID)..."
121
113
  order2.publish
@@ -129,21 +121,13 @@ def demonstrate_deduplication
129
121
  # Test 2: NotificationMessage without deduplication
130
122
  puts "--- Test 2: NotificationMessage (no deduplication) ---"
131
123
 
132
- # Create header with same UUID
133
- notification_header = SmartMessage::Header.new(
134
- uuid: uuid, # Same UUID as orders!
135
- message_class: "NotificationMessage",
136
- published_at: Time.now,
137
- publisher_pid: Process.pid,
138
- version: 1,
139
- from: "notification-service"
140
- )
141
-
142
- # First notification
124
+ # First notification (create normally, then set UUID)
143
125
  notif1 = NotificationMessage.new(
144
- _sm_header: notification_header,
145
- _sm_payload: { message: "Order confirmed", recipient: "customer@example.com" }
126
+ message: "Order confirmed",
127
+ recipient: "customer@example.com"
146
128
  )
129
+ # Use same UUID as orders to show deduplication is per-message-class
130
+ notif1._sm_header.uuid = uuid
147
131
 
148
132
  puts "Publishing first notification..."
149
133
  notif1.publish
@@ -151,9 +135,11 @@ def demonstrate_deduplication
151
135
 
152
136
  # Second notification with same UUID (should NOT be deduplicated)
153
137
  notif2 = NotificationMessage.new(
154
- _sm_header: notification_header,
155
- _sm_payload: { message: "Order shipped", recipient: "customer@example.com" }
138
+ message: "Order shipped",
139
+ recipient: "customer@example.com"
156
140
  )
141
+ # Use same UUID - NotificationMessage doesn't have deduplication enabled
142
+ notif2._sm_header.uuid = uuid
157
143
 
158
144
  puts "Publishing duplicate notification (same UUID)..."
159
145
  notif2.publish
@@ -45,12 +45,11 @@ class PaymentMessage < SmartMessage::Base
45
45
 
46
46
  config do
47
47
  transport SmartMessage::Transport.create(:memory)
48
- serializer SmartMessage::Serializer::Json.new
49
48
  end
50
49
 
51
- def self.process(wrapper)
52
- header = wrapper._sm_header
53
- payload = wrapper._sm_payload
50
+ def process(message)
51
+ header = message._sm_header
52
+ payload = message
54
53
  data = JSON.parse(payload, symbolize_names: true)
55
54
  puts " 💳 Processing payment #{data[:payment_id]} for $#{data[:amount]}"
56
55
  end
@@ -68,12 +67,11 @@ class OrderMessage < SmartMessage::Base
68
67
 
69
68
  config do
70
69
  transport SmartMessage::Transport.create(:memory)
71
- serializer SmartMessage::Serializer::Json.new
72
70
  end
73
71
 
74
- def self.process(wrapper)
75
- header = wrapper._sm_header
76
- payload = wrapper._sm_payload
72
+ def process(message)
73
+ header = message._sm_header
74
+ payload = message
77
75
  data = JSON.parse(payload, symbolize_names: true)
78
76
  puts " 📦 Processing order #{data[:order_id]} with #{data[:items].size} items"
79
77
  end
@@ -90,12 +88,11 @@ class NotificationMessage < SmartMessage::Base
90
88
 
91
89
  config do
92
90
  transport SmartMessage::Transport.create(:memory)
93
- serializer SmartMessage::Serializer::Json.new
94
91
  end
95
92
 
96
- def self.process(wrapper)
97
- header = wrapper._sm_header
98
- payload = wrapper._sm_payload
93
+ def process(message)
94
+ header = message._sm_header
95
+ payload = message
99
96
  data = JSON.parse(payload, symbolize_names: true)
100
97
  puts " 📧 Sending #{data[:channel]} to user #{data[:user_id]}: #{data[:message]}"
101
98
  end
@@ -35,8 +35,7 @@ class OrderMessage < SmartMessage::Base
35
35
 
36
36
  # Configure to use memory transport for this example
37
37
  config do
38
- transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
39
- serializer SmartMessage::Serializer::Json.new
38
+ transport SmartMessage::Transport::MemoryTransport.new
40
39
  end
41
40
 
42
41
  # Default processing - just logs the order
@@ -61,8 +60,7 @@ class PaymentResponseMessage < SmartMessage::Base
61
60
  description: "ISO8601 timestamp when the payment was processed"
62
61
 
63
62
  config do
64
- transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
65
- serializer SmartMessage::Serializer::Json.new
63
+ transport SmartMessage::Transport::MemoryTransport.new
66
64
  end
67
65
 
68
66
  def self.process(message)
@@ -208,7 +206,7 @@ class OrderProcessingDemo
208
206
  puts "• Point-to-point messaging between OrderService and PaymentService"
209
207
  puts "• Bidirectional communication with request/response pattern"
210
208
  puts "• JSON serialization of complex message data"
211
- puts "• STDOUT transport with loopback for local demonstration"
209
+ puts "• Memory transport for local demonstration"
212
210
  end
213
211
  end
214
212
 
@@ -31,13 +31,12 @@ class UserEventMessage < SmartMessage::Base
31
31
  description: "Additional event-specific data (source, location, IP, etc.)"
32
32
 
33
33
  config do
34
- transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
35
- serializer SmartMessage::Serializer::Json.new
34
+ transport SmartMessage::Transport::MemoryTransport.new
36
35
  end
37
36
 
38
37
  # Default processor - just logs the event
39
- def self.process(wrapper)
40
- message_header, message_payload = wrapper.split
38
+ def process(message)
39
+ message_header, message_payload = message
41
40
  event_data = JSON.parse(message_payload)
42
41
  puts "📡 Event broadcasted: #{event_data['event_type']} for user #{event_data['user_id']}"
43
42
  end
@@ -51,13 +50,13 @@ class EmailService
51
50
  UserEventMessage.subscribe('EmailService.handle_user_event')
52
51
  end
53
52
 
54
- def self.handle_user_event(wrapper)
53
+ def handle_event(message)
55
54
  service = new
56
- service.process_event(wrapper)
55
+ service.process_event(message)
57
56
  end
58
57
 
59
- def process_event(wrapper)
60
- message_header, message_payload = wrapper.split
58
+ def process_event(message)
59
+ message_header, message_payload = message
61
60
  event_data = JSON.parse(message_payload)
62
61
 
63
62
  case event_data['event_type']
@@ -107,13 +106,13 @@ class SMSService
107
106
  UserEventMessage.subscribe('SMSService.handle_user_event')
108
107
  end
109
108
 
110
- def self.handle_user_event(wrapper)
109
+ def handle_event(message)
111
110
  service = new
112
- service.process_event(wrapper)
111
+ service.process_event(message)
113
112
  end
114
113
 
115
- def process_event(wrapper)
116
- message_header, message_payload = wrapper.split
114
+ def process_event(message)
115
+ message_header, message_payload = message
117
116
  event_data = JSON.parse(message_payload)
118
117
 
119
118
  case event_data['event_type']
@@ -173,18 +172,18 @@ class AuditService
173
172
  UserEventMessage.subscribe('AuditService.handle_user_event')
174
173
  end
175
174
 
176
- def self.handle_user_event(wrapper)
175
+ def handle_event(message)
177
176
  # Use a singleton pattern for persistent audit log
178
177
  @@instance ||= new
179
- @@instance.process_event(wrapper)
178
+ @@instance.process_event(message)
180
179
  end
181
180
 
182
181
  def self.get_summary
183
182
  @@instance&.get_audit_summary || {}
184
183
  end
185
184
 
186
- def process_event(wrapper)
187
- message_header, message_payload = wrapper.split
185
+ def process_event(message)
186
+ message_header, message_payload = message
188
187
  event_data = JSON.parse(message_payload)
189
188
 
190
189
  audit_entry = {
@@ -36,12 +36,11 @@ class ChatMessage < SmartMessage::Base
36
36
  description: "Additional message data (reactions, edit history, etc.)"
37
37
 
38
38
  config do
39
- transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
40
- serializer SmartMessage::Serializer::Json.new
39
+ transport SmartMessage::Transport::MemoryTransport.new
41
40
  end
42
41
 
43
- def self.process(wrapper)
44
- message_header, message_payload = wrapper.split
42
+ def process(message)
43
+ message_header, message_payload = message
45
44
  chat_data = JSON.parse(message_payload)
46
45
  puts "💬 Chat message in #{chat_data['room_id']}: #{chat_data['content']}"
47
46
  end
@@ -65,12 +64,11 @@ class BotCommandMessage < SmartMessage::Base
65
64
  description: "ISO8601 timestamp when command was issued"
66
65
 
67
66
  config do
68
- transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
69
- serializer SmartMessage::Serializer::Json.new
67
+ transport SmartMessage::Transport::MemoryTransport.new
70
68
  end
71
69
 
72
- def self.process(wrapper)
73
- message_header, message_payload = wrapper.split
70
+ def process(message)
71
+ message_header, message_payload = message
74
72
  command_data = JSON.parse(message_payload)
75
73
  puts "🤖 Bot command: #{command_data['command']} in #{command_data['room_id']}"
76
74
  end
@@ -94,12 +92,11 @@ class SystemNotificationMessage < SmartMessage::Base
94
92
  description: "Additional system event data and context"
95
93
 
96
94
  config do
97
- transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
98
- serializer SmartMessage::Serializer::Json.new
95
+ transport SmartMessage::Transport::MemoryTransport.new
99
96
  end
100
97
 
101
- def self.process(wrapper)
102
- message_header, message_payload = wrapper.split
98
+ def process(message)
99
+ message_header, message_payload = message
103
100
  notif_data = JSON.parse(message_payload)
104
101
  puts "🔔 System: #{notif_data['content']} in #{notif_data['room_id']}"
105
102
  end
@@ -195,8 +192,8 @@ class HumanChatAgent
195
192
  @@agents[agent.user_id] = agent
196
193
  end
197
194
 
198
- def handle_chat_message(wrapper)
199
- message_header, message_payload = wrapper.split
195
+ def handle_message(message)
196
+ message_header, message_payload = message
200
197
  chat_data = JSON.parse(message_payload)
201
198
 
202
199
  # Only process messages from rooms we're in and not our own messages
@@ -211,8 +208,8 @@ class HumanChatAgent
211
208
  end
212
209
  end
213
210
 
214
- def handle_system_notification(wrapper)
215
- message_header, message_payload = wrapper.split
211
+ def handle_system_notification(message)
212
+ message_header, message_payload = message
216
213
  notif_data = JSON.parse(message_payload)
217
214
 
218
215
  # Only process notifications from rooms we're in
@@ -307,8 +304,8 @@ class BotAgent
307
304
  )
308
305
  end
309
306
 
310
- def self.handle_bot_command(wrapper)
311
- message_header, message_payload = wrapper.split
307
+ def handle_command(message)
308
+ message_header, message_payload = message
312
309
  command_data = JSON.parse(message_payload)
313
310
  @@bots ||= []
314
311
 
@@ -321,8 +318,8 @@ class BotAgent
321
318
  capable_bot&.process_command(command_data)
322
319
  end
323
320
 
324
- def self.handle_chat_message(wrapper)
325
- message_header, message_payload = wrapper.split
321
+ def handle_message(message)
322
+ message_header, message_payload = message
326
323
  chat_data = JSON.parse(message_payload)
327
324
  @@bots ||= []
328
325
 
@@ -498,8 +495,8 @@ class RoomManager
498
495
  notification.publish
499
496
  end
500
497
 
501
- def self.handle_system_notification(wrapper)
502
- message_header, message_payload = wrapper.split
498
+ def handle_system_notification(message)
499
+ message_header, message_payload = message
503
500
  @@instance ||= new
504
501
  @@instance.process_system_notification(message_header, message_payload)
505
502
  end