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
@@ -0,0 +1,407 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# examples/09_regex_filtering_microservices.rb
|
3
|
+
|
4
|
+
require_relative '../lib/smart_message'
|
5
|
+
|
6
|
+
# Example: Advanced Regex Filtering for Microservices Architecture
|
7
|
+
#
|
8
|
+
# This example demonstrates how to use SmartMessage's regex filtering capabilities
|
9
|
+
# to build a sophisticated microservices routing system that supports:
|
10
|
+
# - Environment-based routing (dev, staging, prod)
|
11
|
+
# - Service pattern routing (payment-*, api-*, admin-*)
|
12
|
+
# - Mixed exact and pattern matching
|
13
|
+
# - Complex multi-criteria filtering
|
14
|
+
|
15
|
+
puts "š SmartMessage Regex Filtering Demo"
|
16
|
+
puts "=" * 50
|
17
|
+
|
18
|
+
# Base message class for the microservices ecosystem
|
19
|
+
class MicroserviceMessage < SmartMessage::Base
|
20
|
+
version 1
|
21
|
+
|
22
|
+
# Set default 'from' to avoid header requirement issues
|
23
|
+
from 'microservice-demo'
|
24
|
+
|
25
|
+
property :service_id, required: true, description: "Originating service identifier"
|
26
|
+
property :message_type, required: true, description: "Type of message being sent"
|
27
|
+
property :data, description: "Message payload data"
|
28
|
+
property :environment, default: 'dev', description: "Target environment"
|
29
|
+
property :timestamp, default: -> { Time.now.iso8601 }, description: "Message timestamp"
|
30
|
+
|
31
|
+
# Configure with STDOUT transport for demo visibility
|
32
|
+
config do
|
33
|
+
transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
|
34
|
+
serializer SmartMessage::Serializer::JSON.new
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Service-specific message types
|
39
|
+
class PaymentMessage < MicroserviceMessage
|
40
|
+
description "Payment processing and transaction messages"
|
41
|
+
|
42
|
+
property :transaction_id, required: true
|
43
|
+
property :amount, required: true
|
44
|
+
property :currency, default: 'USD'
|
45
|
+
|
46
|
+
def self.process(wrapper)
|
47
|
+
header = wrapper._sm_header
|
48
|
+
payload = wrapper._sm_payload
|
49
|
+
msg_data = JSON.parse(payload)
|
50
|
+
puts "š³ PaymentMessage processed by #{self.name}"
|
51
|
+
puts " From: #{header.from} ā To: #{header.to}"
|
52
|
+
puts " Transaction: #{msg_data['transaction_id']} (#{msg_data['currency']} #{msg_data['amount']})"
|
53
|
+
puts " Environment: #{msg_data['environment']}"
|
54
|
+
puts
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class OrderMessage < MicroserviceMessage
|
59
|
+
description "Order management and fulfillment messages"
|
60
|
+
|
61
|
+
property :order_id, required: true
|
62
|
+
property :customer_id, required: true
|
63
|
+
property :status, default: 'pending'
|
64
|
+
|
65
|
+
def self.process(wrapper)
|
66
|
+
header = wrapper._sm_header
|
67
|
+
payload = wrapper._sm_payload
|
68
|
+
msg_data = JSON.parse(payload)
|
69
|
+
puts "š¦ OrderMessage processed by #{self.name}"
|
70
|
+
puts " From: #{header.from} ā To: #{header.to}"
|
71
|
+
puts " Order: #{msg_data['order_id']} for customer #{msg_data['customer_id']}"
|
72
|
+
puts " Status: #{msg_data['status']}, Environment: #{msg_data['environment']}"
|
73
|
+
puts
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class AlertMessage < MicroserviceMessage
|
78
|
+
description "System monitoring and alerting messages"
|
79
|
+
|
80
|
+
property :alert_level, required: true
|
81
|
+
property :component, required: true
|
82
|
+
property :description, required: true
|
83
|
+
|
84
|
+
def self.process(wrapper)
|
85
|
+
header = wrapper._sm_header
|
86
|
+
payload = wrapper._sm_payload
|
87
|
+
msg_data = JSON.parse(payload)
|
88
|
+
puts "šØ AlertMessage processed by #{self.name}"
|
89
|
+
puts " From: #{header.from} ā To: #{header.to}"
|
90
|
+
puts " Level: #{msg_data['alert_level']} - Component: #{msg_data['component']}"
|
91
|
+
puts " Description: #{msg_data['description']}"
|
92
|
+
puts " Environment: #{msg_data['environment']}"
|
93
|
+
puts
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Demonstration of different regex filtering patterns
|
98
|
+
def demonstrate_filtering_patterns
|
99
|
+
puts "\nšÆ Setting up subscription filters..."
|
100
|
+
|
101
|
+
# Clear any existing subscriptions
|
102
|
+
[PaymentMessage, OrderMessage, AlertMessage].each(&:unsubscribe!)
|
103
|
+
|
104
|
+
# 1. Environment-based filtering
|
105
|
+
puts "\n1ļøā£ Environment-based filtering:"
|
106
|
+
puts " - Development services receive dev/staging messages"
|
107
|
+
puts " - Production services receive only prod messages"
|
108
|
+
|
109
|
+
PaymentMessage.subscribe("PaymentMessage.process_dev", to: /^(dev|staging)-.*/)
|
110
|
+
PaymentMessage.subscribe("PaymentMessage.process_prod", to: /^prod-.*/)
|
111
|
+
|
112
|
+
# 2. Service pattern filtering
|
113
|
+
puts "\n2ļøā£ Service pattern filtering:"
|
114
|
+
puts " - Order services receive messages from payment services"
|
115
|
+
puts " - Alert services receive messages from any monitoring system"
|
116
|
+
|
117
|
+
OrderMessage.subscribe("OrderMessage.process", from: /^payment-.*/)
|
118
|
+
AlertMessage.subscribe("AlertMessage.process", from: /^(monitoring|health|system)-.*/)
|
119
|
+
|
120
|
+
# 3. Mixed exact and pattern matching
|
121
|
+
puts "\n3ļøā£ Mixed filtering (exact + patterns):"
|
122
|
+
puts " - Specific services + pattern matching"
|
123
|
+
|
124
|
+
# Alert service receives from admin, plus any system-* services
|
125
|
+
AlertMessage.subscribe("AlertMessage.process_admin", from: ['admin', /^system-.*/, 'security'])
|
126
|
+
|
127
|
+
# 4. Complex multi-criteria filtering
|
128
|
+
puts "\n4ļøā£ Complex multi-criteria filtering:"
|
129
|
+
puts " - Admin services to production environments only"
|
130
|
+
|
131
|
+
OrderMessage.subscribe("OrderMessage.process_admin_prod",
|
132
|
+
from: /^admin-.*/,
|
133
|
+
to: /^prod-.*/)
|
134
|
+
|
135
|
+
# 5. Broadcast + directed message filtering
|
136
|
+
puts "\n5ļøā£ Broadcast + directed filtering:"
|
137
|
+
puts " - Receive broadcast messages OR messages directed to api services"
|
138
|
+
|
139
|
+
PaymentMessage.subscribe("PaymentMessage.process_api",
|
140
|
+
broadcast: true,
|
141
|
+
to: /^api-.*/)
|
142
|
+
|
143
|
+
puts "\nā
All subscription filters configured!"
|
144
|
+
end
|
145
|
+
|
146
|
+
# Simulate microservices sending messages
|
147
|
+
def simulate_microservice_traffic
|
148
|
+
puts "\nš” Simulating microservice message traffic..."
|
149
|
+
puts "=" * 50
|
150
|
+
|
151
|
+
# Sleep between messages for readability
|
152
|
+
delay = 0.5
|
153
|
+
|
154
|
+
# 1. Environment-based routing examples
|
155
|
+
puts "\nš Environment-based routing examples:"
|
156
|
+
|
157
|
+
payment_msg = PaymentMessage.new(
|
158
|
+
service_id: "payment-core",
|
159
|
+
message_type: "transaction_complete",
|
160
|
+
transaction_id: "TXN-001",
|
161
|
+
amount: 99.99,
|
162
|
+
data: { merchant: "Online Store" },
|
163
|
+
environment: "dev"
|
164
|
+
)
|
165
|
+
payment_msg.from('payment-service')
|
166
|
+
payment_msg.to('dev-payment-processor')
|
167
|
+
payment_msg.publish
|
168
|
+
sleep(delay)
|
169
|
+
|
170
|
+
payment_msg = PaymentMessage.new(
|
171
|
+
service_id: "payment-core",
|
172
|
+
message_type: "transaction_complete",
|
173
|
+
transaction_id: "TXN-002",
|
174
|
+
amount: 299.99,
|
175
|
+
data: { merchant: "Enterprise Store" },
|
176
|
+
environment: "prod"
|
177
|
+
)
|
178
|
+
payment_msg.from('payment-service')
|
179
|
+
payment_msg.to('prod-payment-processor')
|
180
|
+
payment_msg.publish
|
181
|
+
sleep(delay)
|
182
|
+
|
183
|
+
# 2. Service pattern routing examples
|
184
|
+
puts "\nš Service pattern routing examples:"
|
185
|
+
|
186
|
+
order_msg = OrderMessage.new(
|
187
|
+
service_id: "order-manager",
|
188
|
+
message_type: "order_created",
|
189
|
+
order_id: "ORD-123",
|
190
|
+
customer_id: "CUST-456",
|
191
|
+
status: "pending",
|
192
|
+
data: { items: ["Widget A", "Widget B"] },
|
193
|
+
environment: "prod"
|
194
|
+
)
|
195
|
+
order_msg.from('payment-gateway') # Matches /^payment-.*/ pattern
|
196
|
+
order_msg.to('order-service')
|
197
|
+
order_msg.publish
|
198
|
+
sleep(delay)
|
199
|
+
|
200
|
+
# 3. Monitoring and alerting examples
|
201
|
+
puts "\nš Monitoring and alerting examples:"
|
202
|
+
|
203
|
+
alert_msg = AlertMessage.new(
|
204
|
+
service_id: "health-checker",
|
205
|
+
message_type: "system_alert",
|
206
|
+
alert_level: "warning",
|
207
|
+
component: "database",
|
208
|
+
description: "High connection count detected",
|
209
|
+
data: { current_connections: 95, max_connections: 100 },
|
210
|
+
environment: "prod"
|
211
|
+
)
|
212
|
+
alert_msg.from('monitoring-system') # Matches /^monitoring-.*/ pattern
|
213
|
+
alert_msg.to('ops-dashboard')
|
214
|
+
alert_msg.publish
|
215
|
+
sleep(delay)
|
216
|
+
|
217
|
+
# 4. Mixed filtering examples
|
218
|
+
puts "\nš Mixed filtering examples:"
|
219
|
+
|
220
|
+
alert_msg = AlertMessage.new(
|
221
|
+
service_id: "security-scanner",
|
222
|
+
message_type: "security_alert",
|
223
|
+
alert_level: "critical",
|
224
|
+
component: "authentication",
|
225
|
+
description: "Multiple failed login attempts detected",
|
226
|
+
data: { attempts: 50, ip: "192.168.1.100" },
|
227
|
+
environment: "prod"
|
228
|
+
)
|
229
|
+
alert_msg.from('admin') # Exact match in mixed array ['admin', /^system-.*/, 'security']
|
230
|
+
alert_msg.to('security-dashboard')
|
231
|
+
alert_msg.publish
|
232
|
+
sleep(delay)
|
233
|
+
|
234
|
+
alert_msg = AlertMessage.new(
|
235
|
+
service_id: "system-monitor",
|
236
|
+
message_type: "resource_alert",
|
237
|
+
alert_level: "warning",
|
238
|
+
component: "memory",
|
239
|
+
description: "Memory usage above threshold",
|
240
|
+
data: { usage_percent: 85, threshold: 80 },
|
241
|
+
environment: "staging"
|
242
|
+
)
|
243
|
+
alert_msg.from('system-metrics') # Matches /^system-.*/ pattern
|
244
|
+
alert_msg.to('ops-dashboard')
|
245
|
+
alert_msg.publish
|
246
|
+
sleep(delay)
|
247
|
+
|
248
|
+
# 5. Complex multi-criteria examples
|
249
|
+
puts "\nšÆ Complex multi-criteria examples:"
|
250
|
+
|
251
|
+
order_msg = OrderMessage.new(
|
252
|
+
service_id: "admin-portal",
|
253
|
+
message_type: "admin_order_override",
|
254
|
+
order_id: "ORD-999",
|
255
|
+
customer_id: "ADMIN",
|
256
|
+
status: "expedited",
|
257
|
+
data: { priority: "high", reason: "VIP customer" },
|
258
|
+
environment: "prod"
|
259
|
+
)
|
260
|
+
order_msg.from('admin-dashboard') # Matches /^admin-.*/ pattern
|
261
|
+
order_msg.to('prod-fulfillment') # Matches /^prod-.*/ pattern
|
262
|
+
order_msg.publish
|
263
|
+
sleep(delay)
|
264
|
+
|
265
|
+
# 6. Broadcast message examples
|
266
|
+
puts "\nš¢ Broadcast message examples:"
|
267
|
+
|
268
|
+
payment_msg = PaymentMessage.new(
|
269
|
+
service_id: "payment-system",
|
270
|
+
message_type: "system_maintenance",
|
271
|
+
transaction_id: "MAINT-001",
|
272
|
+
amount: 0,
|
273
|
+
data: {
|
274
|
+
message: "Scheduled maintenance in 30 minutes",
|
275
|
+
duration: "2 hours",
|
276
|
+
affected_services: ["payment", "billing"]
|
277
|
+
},
|
278
|
+
environment: "prod"
|
279
|
+
)
|
280
|
+
payment_msg.from('admin')
|
281
|
+
payment_msg.to(nil) # Broadcast message
|
282
|
+
payment_msg.publish
|
283
|
+
sleep(delay)
|
284
|
+
|
285
|
+
# 7. Messages that won't match filters
|
286
|
+
puts "\nā Examples of messages that won't match filters:"
|
287
|
+
|
288
|
+
# This won't match any filters (wrong from pattern)
|
289
|
+
order_msg = OrderMessage.new(
|
290
|
+
service_id: "user-service",
|
291
|
+
message_type: "user_action",
|
292
|
+
order_id: "ORD-NOFILT",
|
293
|
+
customer_id: "USER-123",
|
294
|
+
status: "ignored",
|
295
|
+
environment: "dev"
|
296
|
+
)
|
297
|
+
order_msg.from('user-portal') # Doesn't match /^payment-.*/ pattern
|
298
|
+
order_msg.to('order-service')
|
299
|
+
order_msg.publish
|
300
|
+
puts " ā ļø This message won't be processed (wrong sender pattern)"
|
301
|
+
sleep(delay)
|
302
|
+
|
303
|
+
# This won't match the admin-prod filter (wrong environment)
|
304
|
+
order_msg = OrderMessage.new(
|
305
|
+
service_id: "admin-dev",
|
306
|
+
message_type: "test_order",
|
307
|
+
order_id: "ORD-TEST",
|
308
|
+
customer_id: "TEST-123",
|
309
|
+
status: "test",
|
310
|
+
environment: "dev"
|
311
|
+
)
|
312
|
+
order_msg.from('admin-panel') # Matches /^admin-.*/ pattern
|
313
|
+
order_msg.to('dev-fulfillment') # Doesn't match /^prod-.*/ pattern
|
314
|
+
order_msg.publish
|
315
|
+
puts " ā ļø This message won't match admin-prod filter (wrong environment)"
|
316
|
+
sleep(delay)
|
317
|
+
|
318
|
+
puts "\n⨠Message simulation complete!"
|
319
|
+
end
|
320
|
+
|
321
|
+
# Display filter configuration summary
|
322
|
+
def display_filter_summary
|
323
|
+
puts "\nš Current Filter Configuration Summary:"
|
324
|
+
puts "=" * 50
|
325
|
+
|
326
|
+
# Get dispatcher to examine subscriptions
|
327
|
+
dispatcher = PaymentMessage.transport.instance_variable_get(:@dispatcher)
|
328
|
+
|
329
|
+
dispatcher.subscribers.each do |message_class, subscriptions|
|
330
|
+
puts "\n#{message_class}:"
|
331
|
+
subscriptions.each_with_index do |sub, index|
|
332
|
+
filters = sub[:filters]
|
333
|
+
method = sub[:process_method]
|
334
|
+
|
335
|
+
puts " #{index + 1}. #{method}"
|
336
|
+
|
337
|
+
if filters[:from]
|
338
|
+
from_desc = filters[:from].map do |f|
|
339
|
+
f.is_a?(Regexp) ? f.inspect : "'#{f}'"
|
340
|
+
end.join(', ')
|
341
|
+
puts " from: [#{from_desc}]"
|
342
|
+
end
|
343
|
+
|
344
|
+
if filters[:to]
|
345
|
+
to_desc = filters[:to].map do |f|
|
346
|
+
f.is_a?(Regexp) ? f.inspect : "'#{f}'"
|
347
|
+
end.join(', ')
|
348
|
+
puts " to: [#{to_desc}]"
|
349
|
+
end
|
350
|
+
|
351
|
+
if filters[:broadcast]
|
352
|
+
puts " broadcast: #{filters[:broadcast]}"
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
puts "\nš Message Processing Statistics:"
|
358
|
+
puts SS.stat.select { |k, v| k.include?('process') }
|
359
|
+
end
|
360
|
+
|
361
|
+
# Main demonstration
|
362
|
+
def main
|
363
|
+
puts "\nThis example demonstrates SmartMessage's powerful regex filtering capabilities"
|
364
|
+
puts "for building sophisticated microservices routing systems.\n"
|
365
|
+
|
366
|
+
# Setup
|
367
|
+
demonstrate_filtering_patterns
|
368
|
+
|
369
|
+
# Wait a moment for subscriptions to be established
|
370
|
+
sleep(1)
|
371
|
+
|
372
|
+
# Simulate traffic
|
373
|
+
simulate_microservice_traffic
|
374
|
+
|
375
|
+
# Wait for message processing
|
376
|
+
sleep(2)
|
377
|
+
|
378
|
+
# Show results
|
379
|
+
display_filter_summary
|
380
|
+
|
381
|
+
puts "\n" + "=" * 60
|
382
|
+
puts "š Regex Filtering Demo Complete!"
|
383
|
+
puts "=" * 60
|
384
|
+
|
385
|
+
puts "\nš” Key Takeaways:"
|
386
|
+
puts " ⢠Use regex patterns for flexible service routing"
|
387
|
+
puts " ⢠Combine exact matches with patterns in arrays"
|
388
|
+
puts " ⢠Environment-based routing with regex patterns"
|
389
|
+
puts " ⢠Multi-criteria filtering for complex scenarios"
|
390
|
+
puts " ⢠Broadcast + directed message handling"
|
391
|
+
puts " ⢠Validation prevents invalid filter types"
|
392
|
+
puts "\nš See CLAUDE.md and README.md for more filtering examples!"
|
393
|
+
end
|
394
|
+
|
395
|
+
# Handle script execution
|
396
|
+
if __FILE__ == $0
|
397
|
+
begin
|
398
|
+
main
|
399
|
+
rescue Interrupt
|
400
|
+
puts "\n\nš Demo interrupted by user"
|
401
|
+
exit(0)
|
402
|
+
rescue => e
|
403
|
+
puts "\nā Error: #{e.message}"
|
404
|
+
puts e.backtrace.first(5).map { |line| " #{line}" }
|
405
|
+
exit(1)
|
406
|
+
end
|
407
|
+
end
|
@@ -0,0 +1,263 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# examples/10_header_block_configuration.rb
|
3
|
+
#
|
4
|
+
# Demonstrates the different ways to configure message addressing:
|
5
|
+
# - Method 1: Direct class methods (from, to, reply_to)
|
6
|
+
# - Method 2: Header block DSL
|
7
|
+
# - Method 3: Instance-level overrides
|
8
|
+
# - Shortcut accessor methods for addressing
|
9
|
+
|
10
|
+
require_relative '../lib/smart_message'
|
11
|
+
|
12
|
+
puts "šÆ SmartMessage Header Block Configuration Demo"
|
13
|
+
puts "=" * 50
|
14
|
+
|
15
|
+
# =============================================================================
|
16
|
+
# Method 1: Direct Class Methods
|
17
|
+
# =============================================================================
|
18
|
+
|
19
|
+
puts "\nš” Method 1: Direct Class Methods"
|
20
|
+
puts "-" * 40
|
21
|
+
|
22
|
+
class DirectMethodMessage < SmartMessage::Base
|
23
|
+
version 1
|
24
|
+
description "Configured using direct class methods"
|
25
|
+
|
26
|
+
# Configure addressing using individual methods
|
27
|
+
from 'service-a'
|
28
|
+
to 'service-b'
|
29
|
+
reply_to 'service-a-callback'
|
30
|
+
|
31
|
+
property :data, required: true
|
32
|
+
|
33
|
+
config do
|
34
|
+
transport SmartMessage::Transport.create(:stdout)
|
35
|
+
serializer SmartMessage::Serializer::JSON.new
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
msg1 = DirectMethodMessage.new(data: "Method 1 test")
|
40
|
+
puts "From: #{msg1.from}"
|
41
|
+
puts "To: #{msg1.to}"
|
42
|
+
puts "Reply-to: #{msg1.reply_to}"
|
43
|
+
|
44
|
+
# =============================================================================
|
45
|
+
# Method 2: Header Block DSL
|
46
|
+
# =============================================================================
|
47
|
+
|
48
|
+
puts "\nš” Method 2: Header Block DSL"
|
49
|
+
puts "-" * 40
|
50
|
+
|
51
|
+
class HeaderBlockMessage < SmartMessage::Base
|
52
|
+
version 1
|
53
|
+
description "Configured using header block DSL"
|
54
|
+
|
55
|
+
# Configure all addressing in a single block
|
56
|
+
header do
|
57
|
+
from 'service-x'
|
58
|
+
to 'service-y'
|
59
|
+
reply_to 'service-x-callback'
|
60
|
+
end
|
61
|
+
|
62
|
+
property :data, required: true
|
63
|
+
|
64
|
+
config do
|
65
|
+
transport SmartMessage::Transport.create(:stdout)
|
66
|
+
serializer SmartMessage::Serializer::JSON.new
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
msg2 = HeaderBlockMessage.new(data: "Method 2 test")
|
71
|
+
puts "From: #{msg2.from}"
|
72
|
+
puts "To: #{msg2.to}"
|
73
|
+
puts "Reply-to: #{msg2.reply_to}"
|
74
|
+
|
75
|
+
# =============================================================================
|
76
|
+
# Method 3: Mixed Approach
|
77
|
+
# =============================================================================
|
78
|
+
|
79
|
+
puts "\nš” Method 3: Mixed Approach"
|
80
|
+
puts "-" * 40
|
81
|
+
|
82
|
+
class MixedConfigMessage < SmartMessage::Base
|
83
|
+
version 1
|
84
|
+
description "Configured using mixed approaches"
|
85
|
+
|
86
|
+
# Some configuration in header block
|
87
|
+
header do
|
88
|
+
from 'mixed-service'
|
89
|
+
to 'target-service'
|
90
|
+
end
|
91
|
+
|
92
|
+
# Additional configuration outside block
|
93
|
+
reply_to 'mixed-callback'
|
94
|
+
|
95
|
+
property :data, required: true
|
96
|
+
|
97
|
+
config do
|
98
|
+
transport SmartMessage::Transport.create(:stdout)
|
99
|
+
serializer SmartMessage::Serializer::JSON.new
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
msg3 = MixedConfigMessage.new(data: "Method 3 test")
|
104
|
+
puts "From: #{msg3.from}"
|
105
|
+
puts "To: #{msg3.to}"
|
106
|
+
puts "Reply-to: #{msg3.reply_to}"
|
107
|
+
|
108
|
+
# =============================================================================
|
109
|
+
# Instance-Level Overrides
|
110
|
+
# =============================================================================
|
111
|
+
|
112
|
+
puts "\nš” Instance-Level Overrides"
|
113
|
+
puts "-" * 40
|
114
|
+
|
115
|
+
class FlexibleMessage < SmartMessage::Base
|
116
|
+
version 1
|
117
|
+
description "Demonstrates instance-level addressing overrides"
|
118
|
+
|
119
|
+
# Default configuration using header block
|
120
|
+
header do
|
121
|
+
from 'default-sender'
|
122
|
+
to 'default-recipient'
|
123
|
+
reply_to 'default-callback'
|
124
|
+
end
|
125
|
+
|
126
|
+
property :data, required: true
|
127
|
+
|
128
|
+
config do
|
129
|
+
transport SmartMessage::Transport.create(:stdout)
|
130
|
+
serializer SmartMessage::Serializer::JSON.new
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Create with defaults
|
135
|
+
msg4 = FlexibleMessage.new(data: "Default config")
|
136
|
+
puts "\nDefault configuration:"
|
137
|
+
puts "From: #{msg4.from}"
|
138
|
+
puts "To: #{msg4.to}"
|
139
|
+
puts "Reply-to: #{msg4.reply_to}"
|
140
|
+
|
141
|
+
# Override using method chaining
|
142
|
+
msg5 = FlexibleMessage.new(data: "Chained overrides")
|
143
|
+
msg5.from('override-sender')
|
144
|
+
.to('override-recipient')
|
145
|
+
.reply_to('override-callback')
|
146
|
+
|
147
|
+
puts "\nMethod chaining overrides:"
|
148
|
+
puts "From: #{msg5.from}"
|
149
|
+
puts "To: #{msg5.to}"
|
150
|
+
puts "Reply-to: #{msg5.reply_to}"
|
151
|
+
|
152
|
+
# Override using setter syntax
|
153
|
+
msg6 = FlexibleMessage.new(data: "Setter overrides")
|
154
|
+
msg6.from = 'setter-sender'
|
155
|
+
msg6.to = 'setter-recipient'
|
156
|
+
msg6.reply_to = 'setter-callback'
|
157
|
+
|
158
|
+
puts "\nSetter syntax overrides:"
|
159
|
+
puts "From: #{msg6.from}"
|
160
|
+
puts "To: #{msg6.to}"
|
161
|
+
puts "Reply-to: #{msg6.reply_to}"
|
162
|
+
|
163
|
+
# =============================================================================
|
164
|
+
# Accessing Addressing Values
|
165
|
+
# =============================================================================
|
166
|
+
|
167
|
+
puts "\nš” Accessing Addressing Values"
|
168
|
+
puts "-" * 40
|
169
|
+
|
170
|
+
msg7 = FlexibleMessage.new(data: "Access demo")
|
171
|
+
msg7.from = 'demo-service'
|
172
|
+
msg7.to = 'demo-target'
|
173
|
+
|
174
|
+
puts "\nThree ways to access addressing:"
|
175
|
+
|
176
|
+
# Method 1: Shortcut methods (recommended)
|
177
|
+
puts "\n1. Shortcut methods:"
|
178
|
+
puts " msg.from => #{msg7.from}"
|
179
|
+
puts " msg.to => #{msg7.to}"
|
180
|
+
puts " msg.reply_to => #{msg7.reply_to}"
|
181
|
+
|
182
|
+
# Method 2: Via header object
|
183
|
+
puts "\n2. Via header object:"
|
184
|
+
puts " msg._sm_header.from => #{msg7._sm_header.from}"
|
185
|
+
puts " msg._sm_header.to => #{msg7._sm_header.to}"
|
186
|
+
puts " msg._sm_header.reply_to => #{msg7._sm_header.reply_to}"
|
187
|
+
|
188
|
+
# Method 3: Class defaults
|
189
|
+
puts "\n3. Class defaults (unchanged by instances):"
|
190
|
+
puts " FlexibleMessage.from => #{FlexibleMessage.from}"
|
191
|
+
puts " FlexibleMessage.to => #{FlexibleMessage.to}"
|
192
|
+
puts " FlexibleMessage.reply_to => #{FlexibleMessage.reply_to}"
|
193
|
+
|
194
|
+
# =============================================================================
|
195
|
+
# Header Synchronization
|
196
|
+
# =============================================================================
|
197
|
+
|
198
|
+
puts "\nš” Header Synchronization"
|
199
|
+
puts "-" * 40
|
200
|
+
|
201
|
+
msg8 = FlexibleMessage.new(data: "Sync demo")
|
202
|
+
puts "\nInitial values:"
|
203
|
+
puts "Instance from: #{msg8.from}"
|
204
|
+
puts "Header from: #{msg8._sm_header.from}"
|
205
|
+
|
206
|
+
# Change instance value
|
207
|
+
msg8.from = 'new-sender'
|
208
|
+
puts "\nAfter changing instance value:"
|
209
|
+
puts "Instance from: #{msg8.from}"
|
210
|
+
puts "Header from: #{msg8._sm_header.from} (automatically synced)"
|
211
|
+
|
212
|
+
# Headers stay in sync
|
213
|
+
msg8.to = 'new-target'
|
214
|
+
puts "\nHeaders stay synchronized:"
|
215
|
+
puts "Instance to: #{msg8.to}"
|
216
|
+
puts "Header to: #{msg8._sm_header.to}"
|
217
|
+
|
218
|
+
# =============================================================================
|
219
|
+
# Configuration Checks
|
220
|
+
# =============================================================================
|
221
|
+
|
222
|
+
puts "\nš” Configuration Checks"
|
223
|
+
puts "-" * 40
|
224
|
+
|
225
|
+
class CheckableMessage < SmartMessage::Base
|
226
|
+
version 1
|
227
|
+
|
228
|
+
header do
|
229
|
+
from 'check-service'
|
230
|
+
# Note: to is not set
|
231
|
+
end
|
232
|
+
|
233
|
+
property :data
|
234
|
+
|
235
|
+
config do
|
236
|
+
transport SmartMessage::Transport.create(:stdout)
|
237
|
+
serializer SmartMessage::Serializer::JSON.new
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# Class-level checks
|
242
|
+
puts "\nClass-level configuration checks:"
|
243
|
+
puts "from_configured? => #{CheckableMessage.from_configured?}"
|
244
|
+
puts "to_configured? => #{CheckableMessage.to_configured?}"
|
245
|
+
puts "reply_to_configured? => #{CheckableMessage.reply_to_configured?}"
|
246
|
+
puts "to_missing? => #{CheckableMessage.to_missing?}"
|
247
|
+
|
248
|
+
# Instance-level checks
|
249
|
+
msg9 = CheckableMessage.new(data: "Check test")
|
250
|
+
msg9.to = 'instance-target'
|
251
|
+
|
252
|
+
puts "\nInstance-level configuration checks:"
|
253
|
+
puts "from_configured? => #{msg9.from_configured?}"
|
254
|
+
puts "to_configured? => #{msg9.to_configured?}"
|
255
|
+
puts "reply_to_configured? => #{msg9.reply_to_configured?}"
|
256
|
+
|
257
|
+
# Reset functionality
|
258
|
+
msg9.reset_to
|
259
|
+
puts "\nAfter reset_to:"
|
260
|
+
puts "to_configured? => #{msg9.to_configured?}"
|
261
|
+
puts "to value: => #{msg9.to.inspect}"
|
262
|
+
|
263
|
+
puts "\nā
Header Block Configuration Demo Complete!"
|