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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +155 -1
- data/Gemfile.lock +6 -6
- data/README.md +71 -25
- data/docs/core-concepts/architecture.md +5 -10
- data/docs/getting-started/examples.md +0 -12
- data/docs/getting-started/quick-start.md +4 -9
- data/docs/index.md +6 -4
- data/docs/reference/serializers.md +160 -488
- data/docs/reference/transports.md +47 -146
- data/docs/transports/memory-transport.md +2 -1
- data/docs/transports/multi-transport.md +484 -0
- data/docs/transports/redis-transport-comparison.md +215 -350
- data/docs/transports/redis-transport.md +3 -22
- data/examples/README.md +6 -9
- data/examples/city_scenario/README.md +1 -1
- data/examples/city_scenario/messages/emergency_911_message.rb +0 -1
- data/examples/city_scenario/messages/emergency_resolved_message.rb +0 -1
- data/examples/city_scenario/messages/fire_dispatch_message.rb +0 -1
- data/examples/city_scenario/messages/fire_emergency_message.rb +0 -1
- data/examples/city_scenario/messages/health_check_message.rb +0 -1
- data/examples/city_scenario/messages/health_status_message.rb +0 -1
- data/examples/city_scenario/messages/police_dispatch_message.rb +0 -1
- data/examples/city_scenario/messages/silent_alarm_message.rb +0 -1
- data/examples/file/00_run_all_file_demos.rb +260 -0
- data/examples/file/01_basic_file_transport_demo.rb +237 -0
- data/examples/file/02_fifo_transport_demo.rb +289 -0
- data/examples/file/03_file_watching_demo.rb +332 -0
- data/examples/file/04_multi_transport_file_demo.rb +432 -0
- data/examples/file/README.md +257 -0
- data/examples/memory/00_run_all_demos.rb +317 -0
- data/examples/memory/01_message_deduplication_demo.rb +18 -32
- data/examples/memory/02_dead_letter_queue_demo.rb +9 -12
- data/examples/memory/03_point_to_point_orders.rb +3 -5
- data/examples/memory/04_publish_subscribe_events.rb +15 -16
- data/examples/memory/05_many_to_many_chat.rb +19 -22
- data/examples/memory/06_stdout_publish_only.rb +145 -0
- data/examples/memory/07_proc_handlers_demo.rb +13 -14
- data/examples/memory/08_custom_logger_demo.rb +136 -140
- data/examples/memory/09_error_handling_demo.rb +7 -10
- data/examples/memory/10_entity_addressing_basic.rb +25 -31
- data/examples/memory/11_entity_addressing_with_filtering.rb +32 -36
- data/examples/memory/12_regex_filtering_microservices.rb +10 -11
- data/examples/memory/13_header_block_configuration.rb +0 -5
- data/examples/memory/14_global_configuration_demo.rb +12 -14
- data/examples/memory/15_logger_demo.rb +0 -1
- data/examples/memory/README.md +37 -20
- data/examples/memory/log/demo_app.log.1 +100 -0
- data/examples/memory/log/demo_app.log.2 +100 -0
- data/examples/multi_transport_example.rb +114 -0
- data/examples/redis/01_smart_home_iot_demo.rb +20 -24
- data/examples/redis/README.md +0 -2
- data/examples/utilities/box_it.rb +12 -0
- data/examples/utilities/doing.rb +19 -0
- data/examples/utilities/temp.md +28 -0
- data/lib/smart_message/base.rb +24 -17
- data/lib/smart_message/configuration.rb +2 -23
- data/lib/smart_message/dead_letter_queue.rb +1 -1
- data/lib/smart_message/errors.rb +3 -0
- data/lib/smart_message/header.rb +1 -1
- data/lib/smart_message/logger/default.rb +1 -1
- data/lib/smart_message/messaging.rb +37 -66
- data/lib/smart_message/plugins.rb +42 -41
- data/lib/smart_message/serializer/base.rb +1 -1
- data/lib/smart_message/serializer.rb +3 -2
- data/lib/smart_message/subscription.rb +18 -20
- data/lib/smart_message/transport/async_publish_queue.rb +284 -0
- data/lib/smart_message/transport/base.rb +42 -8
- data/lib/smart_message/transport/fifo_operations.rb +264 -0
- data/lib/smart_message/transport/file_operations.rb +200 -0
- data/lib/smart_message/transport/file_transport.rb +149 -0
- data/lib/smart_message/transport/file_watching.rb +72 -0
- data/lib/smart_message/transport/memory_transport.rb +23 -4
- data/lib/smart_message/transport/partitioned_files.rb +46 -0
- data/lib/smart_message/transport/redis_transport.rb +11 -0
- data/lib/smart_message/transport/registry.rb +0 -1
- data/lib/smart_message/transport/stdout_transport.rb +73 -41
- data/lib/smart_message/transport/stdout_transport.rb.backup +88 -0
- data/lib/smart_message/transport.rb +0 -1
- data/lib/smart_message/version.rb +1 -1
- metadata +25 -37
- data/docs/guides/redis-queue-getting-started.md +0 -697
- data/docs/guides/redis-queue-patterns.md +0 -889
- data/docs/guides/redis-queue-production.md +0 -1091
- data/docs/transports/redis-enhanced-transport.md +0 -524
- data/docs/transports/redis-queue-transport.md +0 -1304
- data/examples/redis_enhanced/README.md +0 -319
- data/examples/redis_enhanced/enhanced_01_basic_patterns.rb +0 -233
- data/examples/redis_enhanced/enhanced_02_fluent_api.rb +0 -331
- data/examples/redis_enhanced/enhanced_03_dual_publishing.rb +0 -281
- data/examples/redis_enhanced/enhanced_04_advanced_routing.rb +0 -419
- data/examples/redis_queue/01_basic_messaging.rb +0 -221
- data/examples/redis_queue/01_comprehensive_examples.rb +0 -508
- data/examples/redis_queue/02_pattern_routing.rb +0 -405
- data/examples/redis_queue/03_fluent_api.rb +0 -422
- data/examples/redis_queue/04_load_balancing.rb +0 -486
- data/examples/redis_queue/05_microservices.rb +0 -735
- data/examples/redis_queue/06_emergency_alerts.rb +0 -777
- data/examples/redis_queue/07_queue_management.rb +0 -587
- data/examples/redis_queue/README.md +0 -366
- data/examples/redis_queue/enhanced_01_basic_patterns.rb +0 -233
- data/examples/redis_queue/enhanced_02_fluent_api.rb +0 -331
- data/examples/redis_queue/enhanced_03_dual_publishing.rb +0 -281
- data/examples/redis_queue/enhanced_04_advanced_routing.rb +0 -419
- data/examples/redis_queue/redis_queue_architecture.svg +0 -148
- data/ideas/README.md +0 -41
- data/ideas/agents.md +0 -1001
- data/ideas/database_transport.md +0 -980
- data/ideas/improvement.md +0 -359
- data/ideas/meshage.md +0 -1788
- data/ideas/message_discovery.md +0 -178
- data/ideas/message_schema.md +0 -1381
- data/lib/smart_message/transport/redis_enhanced_transport.rb +0 -399
- data/lib/smart_message/transport/redis_queue_transport.rb +0 -555
- data/lib/smart_message/wrapper.rb.bak +0 -132
- /data/examples/memory/{06_pretty_print_demo.rb → 16_pretty_print_demo.rb} +0 -0
@@ -430,24 +430,6 @@ All subscribers receive all messages:
|
|
430
430
|
# No load balancing between subscribers
|
431
431
|
```
|
432
432
|
|
433
|
-
## Migration to Enhanced Transport
|
434
|
-
|
435
|
-
When you need advanced routing, consider upgrading to Enhanced Transport:
|
436
|
-
|
437
|
-
```ruby
|
438
|
-
# From Redis Transport
|
439
|
-
SmartMessage.configure do |config|
|
440
|
-
config.default_transport = SmartMessage::Transport::RedisTransport.new
|
441
|
-
end
|
442
|
-
|
443
|
-
# To Enhanced Transport (with backward compatibility)
|
444
|
-
SmartMessage.configure do |config|
|
445
|
-
config.default_transport = SmartMessage::Transport::RedisEnhancedTransport.new
|
446
|
-
end
|
447
|
-
|
448
|
-
# All existing messages continue to work
|
449
|
-
# New messages gain pattern-matching capabilities
|
450
|
-
```
|
451
433
|
|
452
434
|
## Examples
|
453
435
|
|
@@ -503,7 +485,6 @@ For more Redis Transport examples and patterns, also see:
|
|
503
485
|
|
504
486
|
## Related Documentation
|
505
487
|
|
506
|
-
- [
|
507
|
-
- [
|
508
|
-
- [
|
509
|
-
- [Transport Overview](../reference/transports.md) - All available transports
|
488
|
+
- [Transport Overview](../reference/transports.md) - All available transports
|
489
|
+
- [Examples & Use Cases](../getting-started/examples.md) - Practical usage patterns
|
490
|
+
- [Architecture Overview](../core-concepts/architecture.md) - How SmartMessage works
|
data/examples/README.md
CHANGED
@@ -40,7 +40,7 @@ cd city_scenario
|
|
40
40
|
**Key Features:**
|
41
41
|
- Request-response messaging pattern
|
42
42
|
- Error handling and payment validation
|
43
|
-
-
|
43
|
+
- Automatic serialization of complex business objects by transport
|
44
44
|
- Service-to-service communication
|
45
45
|
|
46
46
|
**Messages Used:**
|
@@ -393,7 +393,6 @@ Most examples use `StdoutTransport` with loopback enabled for demonstration purp
|
|
393
393
|
```ruby
|
394
394
|
config do
|
395
395
|
transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
|
396
|
-
serializer SmartMessage::Serializer::JSON.new
|
397
396
|
end
|
398
397
|
```
|
399
398
|
|
@@ -406,13 +405,12 @@ config do
|
|
406
405
|
db: 1,
|
407
406
|
auto_subscribe: true
|
408
407
|
)
|
409
|
-
serializer SmartMessage::Serializer::JSON.new
|
410
408
|
end
|
411
409
|
```
|
412
410
|
|
413
411
|
**For Production Use:**
|
414
412
|
- Use production transports like Redis (see example #4), RabbitMQ, or Kafka
|
415
|
-
-
|
413
|
+
- Transports handle serialization automatically
|
416
414
|
- Add proper error handling and logging
|
417
415
|
- Implement monitoring and metrics
|
418
416
|
|
@@ -547,7 +545,6 @@ class MyCustomMessage < SmartMessage::Base
|
|
547
545
|
|
548
546
|
config do
|
549
547
|
transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
|
550
|
-
serializer SmartMessage::Serializer::JSON.new
|
551
548
|
end
|
552
549
|
end
|
553
550
|
```
|
@@ -676,9 +673,9 @@ When adapting these examples for production:
|
|
676
673
|
- Implement proper error handling
|
677
674
|
|
678
675
|
2. **Serialization:**
|
679
|
-
-
|
680
|
-
-
|
681
|
-
- Handle schema evolution
|
676
|
+
- Transports handle serialization automatically
|
677
|
+
- Choose transports based on serialization requirements
|
678
|
+
- Handle schema evolution at the message level
|
682
679
|
|
683
680
|
3. **Monitoring:**
|
684
681
|
- Add logging and metrics
|
@@ -699,7 +696,7 @@ When adapting these examples for production:
|
|
699
696
|
|
700
697
|
- [SmartMessage Documentation](../docs/README.md)
|
701
698
|
- [Transport Layer Guide](../docs/transports.md)
|
702
|
-
- [Serialization Guide](../docs/serializers.md)
|
699
|
+
- [Serialization Guide](../docs/serializers.md) (Note: Serialization is now handled by transports)
|
703
700
|
- [Architecture Overview](../docs/architecture.md)
|
704
701
|
|
705
702
|
## Questions and Contributions
|
@@ -372,7 +372,7 @@ All messages include comprehensive headers:
|
|
372
372
|
"publisher_pid": 12345,
|
373
373
|
"version": 1,
|
374
374
|
"from": "house-sensor-01",
|
375
|
-
"
|
375
|
+
"transport": "SmartMessage::Transport::RedisTransport"
|
376
376
|
},
|
377
377
|
"_sm_payload": {
|
378
378
|
"location": "123 Oak Street",
|
@@ -10,7 +10,6 @@ module Messages
|
|
10
10
|
description 'Emergency 911 call for reporting fires, crimes, accidents, medical emergencies, or other urgent situations requiring police, fire, or medical response'
|
11
11
|
|
12
12
|
transport SmartMessage::Transport::RedisTransport.new
|
13
|
-
serializer SmartMessage::Serializer::Json.new
|
14
13
|
|
15
14
|
VALID_EMERGENCY_TYPES = %w[fire medical crime accident hazmat rescue other]
|
16
15
|
VALID_SEVERITY = %w[critical high medium low]
|
@@ -14,7 +14,6 @@ module Messages
|
|
14
14
|
description 'Emergency incident closure notification message broadcast by emergency services when incidents are successfully resolved, providing completion status, response duration, outcome details, and unit deployment information to all city services for operational awareness and incident tracking'
|
15
15
|
|
16
16
|
transport SmartMessage::Transport::RedisTransport.new
|
17
|
-
serializer SmartMessage::Serializer::Json.new
|
18
17
|
|
19
18
|
property :incident_id, required: true,
|
20
19
|
description: 'Unique identifier of the emergency incident that was resolved'
|
@@ -13,7 +13,6 @@ module Messages
|
|
13
13
|
description 'Emergency fire suppression dispatch coordination message sent by the Fire Department in response to fire emergencies, containing fire engine assignments, specialized equipment deployment, and tactical response information for various fire types, rescue operations, and hazardous material incidents'
|
14
14
|
|
15
15
|
transport SmartMessage::Transport::RedisTransport.new
|
16
|
-
serializer SmartMessage::Serializer::Json.new
|
17
16
|
|
18
17
|
property :dispatch_id, required: true,
|
19
18
|
description: 'Unique hexadecimal identifier for this fire department dispatch operation'
|
@@ -13,7 +13,6 @@ module Messages
|
|
13
13
|
description "Critical fire emergency alert message sent by residential monitoring systems to the Fire Department when smoke, heat, or fire is detected, triggering immediate emergency response with fire engine dispatch, specialized equipment deployment, and rescue operations based on fire type, severity, and occupant safety status"
|
14
14
|
|
15
15
|
transport SmartMessage::Transport::RedisTransport.new
|
16
|
-
serializer SmartMessage::Serializer::Json.new
|
17
16
|
|
18
17
|
VALID_FIRE_TYPES = %w[fire kitchen electrical basement garage wildfire]
|
19
18
|
VALID_SEVERITY = %w[small medium large out_of_control]
|
@@ -14,7 +14,6 @@ module Messages
|
|
14
14
|
description "Health monitoring message broadcast by the Health Department every 5 seconds to verify operational status of all city services including police, fire, banks, and residential monitoring systems"
|
15
15
|
|
16
16
|
transport SmartMessage::Transport::RedisTransport.new
|
17
|
-
serializer SmartMessage::Serializer::Json.new
|
18
17
|
|
19
18
|
property :check_id, required: true,
|
20
19
|
description: "Unique identifier for this health check request (UUID format)"
|
@@ -16,7 +16,6 @@ module Messages
|
|
16
16
|
VALID_STATUS = %w[healthy warning critical failed]
|
17
17
|
|
18
18
|
transport SmartMessage::Transport::RedisTransport.new
|
19
|
-
serializer SmartMessage::Serializer::Json.new
|
20
19
|
|
21
20
|
property :service_name, required: true,
|
22
21
|
description: "Name of the city service reporting its status (e.g., 'police-department', 'fire-department')"
|
@@ -0,0 +1,260 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
# Run All File Transport Demos
|
6
|
+
#
|
7
|
+
# This script runs all the FileTransport demonstration programs
|
8
|
+
# and provides a summary of each demo's capabilities.
|
9
|
+
|
10
|
+
require 'fileutils'
|
11
|
+
|
12
|
+
puts "🚀 SmartMessage FileTransport Demo Suite"
|
13
|
+
puts "=" * 50
|
14
|
+
puts
|
15
|
+
|
16
|
+
demos = [
|
17
|
+
{
|
18
|
+
file: '01_basic_file_transport_demo.rb',
|
19
|
+
title: 'Basic File Transport Demo',
|
20
|
+
description: 'Core FileTransport functionality including writing, formats, and modes'
|
21
|
+
},
|
22
|
+
{
|
23
|
+
file: '02_fifo_transport_demo.rb',
|
24
|
+
title: 'FIFO Transport Demo',
|
25
|
+
description: 'Named pipes (FIFO) for real-time inter-process communication'
|
26
|
+
},
|
27
|
+
{
|
28
|
+
file: '03_file_watching_demo.rb',
|
29
|
+
title: 'File Watching Demo',
|
30
|
+
description: 'Monitoring files for changes and processing new content'
|
31
|
+
},
|
32
|
+
{
|
33
|
+
file: '04_multi_transport_file_demo.rb',
|
34
|
+
title: 'Multi-Transport File Demo',
|
35
|
+
description: 'Advanced patterns with multiple transports and routing'
|
36
|
+
}
|
37
|
+
]
|
38
|
+
|
39
|
+
def run_demo(demo_file, title)
|
40
|
+
puts "🔧 Running: #{title}"
|
41
|
+
puts "-" * 60
|
42
|
+
|
43
|
+
start_time = Time.now
|
44
|
+
|
45
|
+
begin
|
46
|
+
# Run the demo in a separate process to isolate any issues
|
47
|
+
output = `ruby #{demo_file} 2>&1`
|
48
|
+
exit_status = $?.exitstatus
|
49
|
+
|
50
|
+
end_time = Time.now
|
51
|
+
duration = (end_time - start_time).round(2)
|
52
|
+
|
53
|
+
if exit_status == 0
|
54
|
+
puts output
|
55
|
+
puts "✅ SUCCESS - Completed in #{duration}s"
|
56
|
+
else
|
57
|
+
puts "❌ FAILED - Exit status: #{exit_status}"
|
58
|
+
puts "Output:"
|
59
|
+
puts output
|
60
|
+
end
|
61
|
+
|
62
|
+
return exit_status == 0
|
63
|
+
|
64
|
+
rescue => e
|
65
|
+
puts "❌ ERROR - #{e.message}"
|
66
|
+
return false
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def check_system_requirements
|
71
|
+
puts "🔍 Checking System Requirements"
|
72
|
+
puts "-" * 40
|
73
|
+
|
74
|
+
requirements = {
|
75
|
+
'Ruby version' => RUBY_VERSION,
|
76
|
+
'Platform' => RUBY_PLATFORM,
|
77
|
+
'SmartMessage available' => File.exist?('../../lib/smart_message.rb')
|
78
|
+
}
|
79
|
+
|
80
|
+
requirements.each do |req, status|
|
81
|
+
puts " #{req}: #{status}"
|
82
|
+
end
|
83
|
+
|
84
|
+
# Check for FIFO support
|
85
|
+
fifo_supported = false
|
86
|
+
begin
|
87
|
+
test_dir = Dir.mktmpdir('fifo_check')
|
88
|
+
test_fifo = File.join(test_dir, 'test.fifo')
|
89
|
+
fifo_supported = system("mkfifo #{test_fifo} 2>/dev/null") && File.exist?(test_fifo)
|
90
|
+
FileUtils.rm_rf(test_dir)
|
91
|
+
rescue
|
92
|
+
fifo_supported = false
|
93
|
+
end
|
94
|
+
|
95
|
+
puts " FIFO support: #{fifo_supported ? '✅ Available' : '❌ Not available'}"
|
96
|
+
|
97
|
+
unless fifo_supported
|
98
|
+
puts " ⚠️ Note: FIFO demos will be skipped on this system"
|
99
|
+
end
|
100
|
+
|
101
|
+
puts
|
102
|
+
return fifo_supported
|
103
|
+
end
|
104
|
+
|
105
|
+
def show_demo_menu(demos)
|
106
|
+
puts "📋 Available Demos:"
|
107
|
+
puts "-" * 20
|
108
|
+
|
109
|
+
demos.each_with_index do |demo, index|
|
110
|
+
puts " #{index + 1}. #{demo[:title]}"
|
111
|
+
puts " #{demo[:description]}"
|
112
|
+
puts
|
113
|
+
end
|
114
|
+
|
115
|
+
puts " 0. Run all demos"
|
116
|
+
puts " q. Quit"
|
117
|
+
puts
|
118
|
+
end
|
119
|
+
|
120
|
+
def get_user_choice(max_choice)
|
121
|
+
loop do
|
122
|
+
print "Enter your choice (0-#{max_choice}, q): "
|
123
|
+
input = gets.chomp.downcase
|
124
|
+
|
125
|
+
return :quit if input == 'q'
|
126
|
+
return 0 if input == '0'
|
127
|
+
|
128
|
+
choice = input.to_i
|
129
|
+
if choice >= 1 && choice <= max_choice
|
130
|
+
return choice
|
131
|
+
end
|
132
|
+
|
133
|
+
puts "Invalid choice. Please try again."
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Change to the examples/file directory
|
138
|
+
script_dir = File.dirname(__FILE__)
|
139
|
+
Dir.chdir(script_dir)
|
140
|
+
|
141
|
+
# Check system requirements
|
142
|
+
fifo_supported = check_system_requirements
|
143
|
+
|
144
|
+
# Interactive mode
|
145
|
+
if ARGV.empty?
|
146
|
+
loop do
|
147
|
+
show_demo_menu(demos)
|
148
|
+
choice = get_user_choice(demos.length)
|
149
|
+
|
150
|
+
break if choice == :quit
|
151
|
+
|
152
|
+
puts
|
153
|
+
|
154
|
+
if choice == 0
|
155
|
+
# Run all demos
|
156
|
+
puts "🚀 Running All Demos"
|
157
|
+
puts "=" * 30
|
158
|
+
puts
|
159
|
+
|
160
|
+
success_count = 0
|
161
|
+
total_start = Time.now
|
162
|
+
|
163
|
+
demos.each_with_index do |demo, index|
|
164
|
+
# Skip FIFO demo if not supported
|
165
|
+
if demo[:file].include?('fifo') && !fifo_supported
|
166
|
+
puts "⏭️ Skipping #{demo[:title]} (FIFO not supported)"
|
167
|
+
puts
|
168
|
+
next
|
169
|
+
end
|
170
|
+
|
171
|
+
if run_demo(demo[:file], demo[:title])
|
172
|
+
success_count += 1
|
173
|
+
end
|
174
|
+
puts
|
175
|
+
end
|
176
|
+
|
177
|
+
total_time = (Time.now - total_start).round(2)
|
178
|
+
|
179
|
+
puts "📊 Summary"
|
180
|
+
puts "=" * 20
|
181
|
+
puts "Successful demos: #{success_count}/#{demos.length}"
|
182
|
+
puts "Total time: #{total_time}s"
|
183
|
+
puts
|
184
|
+
|
185
|
+
else
|
186
|
+
# Run specific demo
|
187
|
+
demo = demos[choice - 1]
|
188
|
+
|
189
|
+
# Check if FIFO demo on unsupported system
|
190
|
+
if demo[:file].include?('fifo') && !fifo_supported
|
191
|
+
puts "❌ Cannot run #{demo[:title]} - FIFO not supported on this system"
|
192
|
+
puts
|
193
|
+
next
|
194
|
+
end
|
195
|
+
|
196
|
+
run_demo(demo[:file], demo[:title])
|
197
|
+
puts
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
puts "👋 Thanks for exploring SmartMessage FileTransport!"
|
202
|
+
|
203
|
+
else
|
204
|
+
# Command line mode
|
205
|
+
case ARGV[0]
|
206
|
+
when 'all'
|
207
|
+
puts "🚀 Running All Demos (Non-Interactive Mode)"
|
208
|
+
puts "=" * 45
|
209
|
+
puts
|
210
|
+
|
211
|
+
success_count = 0
|
212
|
+
|
213
|
+
demos.each do |demo|
|
214
|
+
# Skip FIFO demo if not supported
|
215
|
+
if demo[:file].include?('fifo') && !fifo_supported
|
216
|
+
puts "⏭️ Skipping #{demo[:title]} (FIFO not supported)"
|
217
|
+
puts
|
218
|
+
next
|
219
|
+
end
|
220
|
+
|
221
|
+
if run_demo(demo[:file], demo[:title])
|
222
|
+
success_count += 1
|
223
|
+
end
|
224
|
+
puts
|
225
|
+
end
|
226
|
+
|
227
|
+
puts "📊 Final Summary: #{success_count}/#{demos.length} demos successful"
|
228
|
+
|
229
|
+
when 'list'
|
230
|
+
puts "📋 Available FileTransport Demos:"
|
231
|
+
demos.each_with_index do |demo, index|
|
232
|
+
puts " #{index + 1}. #{demo[:file]} - #{demo[:title]}"
|
233
|
+
end
|
234
|
+
|
235
|
+
when /^\d+$/
|
236
|
+
choice = ARGV[0].to_i
|
237
|
+
if choice >= 1 && choice <= demos.length
|
238
|
+
demo = demos[choice - 1]
|
239
|
+
|
240
|
+
if demo[:file].include?('fifo') && !fifo_supported
|
241
|
+
puts "❌ Cannot run #{demo[:title]} - FIFO not supported on this system"
|
242
|
+
exit 1
|
243
|
+
end
|
244
|
+
|
245
|
+
success = run_demo(demo[:file], demo[:title])
|
246
|
+
exit(success ? 0 : 1)
|
247
|
+
else
|
248
|
+
puts "❌ Invalid demo number. Use 'list' to see available demos."
|
249
|
+
exit 1
|
250
|
+
end
|
251
|
+
|
252
|
+
else
|
253
|
+
puts "Usage:"
|
254
|
+
puts " #{$0} # Interactive mode"
|
255
|
+
puts " #{$0} all # Run all demos"
|
256
|
+
puts " #{$0} list # List available demos"
|
257
|
+
puts " #{$0} N # Run demo number N"
|
258
|
+
exit 1
|
259
|
+
end
|
260
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
# Basic File Transport Demo
|
6
|
+
#
|
7
|
+
# This example demonstrates the core functionality of SmartMessage's FileTransport.
|
8
|
+
# It shows how to publish messages to files and read them back.
|
9
|
+
|
10
|
+
require_relative '../../lib/smart_message'
|
11
|
+
require 'tempfile'
|
12
|
+
require 'fileutils'
|
13
|
+
|
14
|
+
# Define message classes that will be saved in the messages directory
|
15
|
+
Dir.mkdir('messages') unless Dir.exist?('messages')
|
16
|
+
|
17
|
+
class LogMessage < SmartMessage::Base
|
18
|
+
property :level, required: true, valid: %w[DEBUG INFO WARN ERROR FATAL]
|
19
|
+
property :message, required: true
|
20
|
+
property :timestamp, default: -> { Time.now.iso8601 }
|
21
|
+
property :component, default: 'system'
|
22
|
+
|
23
|
+
from 'file_transport_demo'
|
24
|
+
|
25
|
+
# Transport will be set dynamically in examples
|
26
|
+
end
|
27
|
+
|
28
|
+
class UserAction < SmartMessage::Base
|
29
|
+
property :user_id, required: true
|
30
|
+
property :action, required: true
|
31
|
+
property :details, default: {}
|
32
|
+
property :timestamp, default: -> { Time.now.iso8601 }
|
33
|
+
|
34
|
+
from 'file_transport_demo'
|
35
|
+
|
36
|
+
# Transport will be set dynamically in examples
|
37
|
+
end
|
38
|
+
|
39
|
+
puts "=== SmartMessage FileTransport Basic Demo ==="
|
40
|
+
puts
|
41
|
+
|
42
|
+
# Create a temporary directory for our demo
|
43
|
+
demo_dir = Dir.mktmpdir('file_transport_demo')
|
44
|
+
puts "Demo directory: #{demo_dir}"
|
45
|
+
|
46
|
+
begin
|
47
|
+
# Example 1: Basic file writing
|
48
|
+
puts "\n1. Basic File Writing"
|
49
|
+
puts "=" * 30
|
50
|
+
|
51
|
+
log_file = File.join(demo_dir, 'application.log')
|
52
|
+
|
53
|
+
# Configure a simple file transport
|
54
|
+
file_transport = SmartMessage::Transport::FileTransport.new(
|
55
|
+
file_path: log_file,
|
56
|
+
format: :json
|
57
|
+
)
|
58
|
+
|
59
|
+
# Configure LogMessage to use the file transport
|
60
|
+
LogMessage.class_eval do
|
61
|
+
transport file_transport
|
62
|
+
end
|
63
|
+
|
64
|
+
# Publish some log messages
|
65
|
+
LogMessage.new(level: 'INFO', message: 'Application started', component: 'main').publish
|
66
|
+
LogMessage.new(level: 'DEBUG', message: 'Loading configuration', component: 'config').publish
|
67
|
+
LogMessage.new(level: 'WARN', message: 'Deprecated feature used', component: 'legacy').publish
|
68
|
+
LogMessage.new(level: 'ERROR', message: 'Database connection failed', component: 'db').publish
|
69
|
+
|
70
|
+
puts "✓ Messages written to: #{log_file}"
|
71
|
+
puts "File contents:"
|
72
|
+
puts File.read(log_file)
|
73
|
+
|
74
|
+
# Example 2: Different output formats
|
75
|
+
puts "\n2. Different Output Formats"
|
76
|
+
puts "=" * 30
|
77
|
+
|
78
|
+
formats = [:json, :yaml, :raw]
|
79
|
+
|
80
|
+
formats.each do |format|
|
81
|
+
format_file = File.join(demo_dir, "messages_#{format}.log")
|
82
|
+
|
83
|
+
format_transport = SmartMessage::Transport::FileTransport.new(
|
84
|
+
file_path: format_file,
|
85
|
+
format: format
|
86
|
+
)
|
87
|
+
|
88
|
+
# Create a temporary message class for this format
|
89
|
+
temp_message = Class.new(SmartMessage::Base) do
|
90
|
+
property :content, required: true
|
91
|
+
property :format_type, required: true
|
92
|
+
from 'file_transport_demo'
|
93
|
+
end
|
94
|
+
|
95
|
+
temp_message.class_eval do
|
96
|
+
transport format_transport
|
97
|
+
end
|
98
|
+
|
99
|
+
temp_message.new(
|
100
|
+
content: "This message is in #{format} format",
|
101
|
+
format_type: format.to_s
|
102
|
+
).publish
|
103
|
+
|
104
|
+
puts "\n#{format.upcase} format (#{format_file}):"
|
105
|
+
puts File.read(format_file)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Example 3: Append vs Overwrite modes
|
109
|
+
puts "\n3. Append vs Overwrite Modes"
|
110
|
+
puts "=" * 30
|
111
|
+
|
112
|
+
append_file = File.join(demo_dir, 'append_demo.log')
|
113
|
+
overwrite_file = File.join(demo_dir, 'overwrite_demo.log')
|
114
|
+
|
115
|
+
# Append mode (default)
|
116
|
+
append_transport = SmartMessage::Transport::FileTransport.new(
|
117
|
+
file_path: append_file,
|
118
|
+
write_mode: :append,
|
119
|
+
format: :raw
|
120
|
+
)
|
121
|
+
|
122
|
+
# Overwrite mode
|
123
|
+
overwrite_transport = SmartMessage::Transport::FileTransport.new(
|
124
|
+
file_path: overwrite_file,
|
125
|
+
write_mode: :overwrite,
|
126
|
+
format: :raw
|
127
|
+
)
|
128
|
+
|
129
|
+
# Create messages for demonstration
|
130
|
+
3.times do |i|
|
131
|
+
# Append mode - messages accumulate
|
132
|
+
temp_append = Class.new(SmartMessage::Base) do
|
133
|
+
property :content, required: true
|
134
|
+
from 'file_transport_demo'
|
135
|
+
end
|
136
|
+
temp_append.class_eval do
|
137
|
+
transport append_transport
|
138
|
+
end
|
139
|
+
temp_append.new(content: "Append message #{i + 1}").publish
|
140
|
+
|
141
|
+
# Overwrite mode - only the last message remains
|
142
|
+
temp_overwrite = Class.new(SmartMessage::Base) do
|
143
|
+
property :content, required: true
|
144
|
+
from 'file_transport_demo'
|
145
|
+
end
|
146
|
+
temp_overwrite.class_eval do
|
147
|
+
transport overwrite_transport
|
148
|
+
end
|
149
|
+
temp_overwrite.new(content: "Overwrite message #{i + 1}").publish
|
150
|
+
end
|
151
|
+
|
152
|
+
puts "\nAppend mode result (#{append_file}):"
|
153
|
+
puts File.read(append_file)
|
154
|
+
|
155
|
+
puts "\nOverwrite mode result (#{overwrite_file}):"
|
156
|
+
puts File.read(overwrite_file)
|
157
|
+
|
158
|
+
# Example 4: Custom serialization
|
159
|
+
puts "\n4. Custom Serialization"
|
160
|
+
puts "=" * 30
|
161
|
+
|
162
|
+
csv_file = File.join(demo_dir, 'user_actions.csv')
|
163
|
+
|
164
|
+
# Create a CSV-style transport with custom serializer
|
165
|
+
csv_transport = SmartMessage::Transport::FileTransport.new(
|
166
|
+
file_path: csv_file,
|
167
|
+
format: :custom,
|
168
|
+
serializer: ->(message) {
|
169
|
+
# Custom CSV serialization
|
170
|
+
"#{message.timestamp},#{message.user_id},#{message.action},\"#{message.details}\"\n"
|
171
|
+
}
|
172
|
+
)
|
173
|
+
|
174
|
+
UserAction.class_eval do
|
175
|
+
transport csv_transport
|
176
|
+
end
|
177
|
+
|
178
|
+
# Write CSV header manually
|
179
|
+
File.write(csv_file, "timestamp,user_id,action,details\n")
|
180
|
+
|
181
|
+
# Publish user action messages
|
182
|
+
UserAction.new(user_id: '12345', action: 'login', details: {ip: '192.168.1.1'}).publish
|
183
|
+
UserAction.new(user_id: '12345', action: 'view_profile', details: {page: 'settings'}).publish
|
184
|
+
UserAction.new(user_id: '67890', action: 'purchase', details: {item_id: 'ABC123', amount: 29.99}).publish
|
185
|
+
UserAction.new(user_id: '12345', action: 'logout', details: {}).publish
|
186
|
+
|
187
|
+
puts "CSV file contents (#{csv_file}):"
|
188
|
+
puts File.read(csv_file)
|
189
|
+
|
190
|
+
# Example 5: File rotation
|
191
|
+
puts "\n5. File Rotation"
|
192
|
+
puts "=" * 30
|
193
|
+
|
194
|
+
# Note: This demonstrates the concept - actual rotation would require external tools
|
195
|
+
base_file = File.join(demo_dir, 'rotated.log')
|
196
|
+
|
197
|
+
rotation_transport = SmartMessage::Transport::FileTransport.new(
|
198
|
+
file_path: base_file,
|
199
|
+
format: :json
|
200
|
+
)
|
201
|
+
|
202
|
+
temp_rotated = Class.new(SmartMessage::Base) do
|
203
|
+
property :sequence, required: true
|
204
|
+
property :data, required: true
|
205
|
+
from 'file_transport_demo'
|
206
|
+
end
|
207
|
+
temp_rotated.class_eval do
|
208
|
+
transport rotation_transport
|
209
|
+
end
|
210
|
+
|
211
|
+
# Simulate rotation by publishing messages and manually rotating
|
212
|
+
5.times do |i|
|
213
|
+
temp_rotated.new(sequence: i + 1, data: "Message #{i + 1}").publish
|
214
|
+
|
215
|
+
# Simulate rotation after every 2 messages
|
216
|
+
if (i + 1) % 2 == 0
|
217
|
+
rotated_file = "#{base_file}.#{(i + 1) / 2}"
|
218
|
+
FileUtils.mv(base_file, rotated_file) if File.exist?(base_file)
|
219
|
+
puts "✓ Rotated to: #{rotated_file}"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Show rotated files
|
224
|
+
Dir.glob("#{base_file}*").sort.each do |file|
|
225
|
+
puts "\n#{file}:"
|
226
|
+
puts File.read(file) if File.exist?(file) && File.size(file) > 0
|
227
|
+
end
|
228
|
+
|
229
|
+
rescue => e
|
230
|
+
puts "Error: #{e.message}"
|
231
|
+
puts e.backtrace.first(3)
|
232
|
+
ensure
|
233
|
+
# Cleanup
|
234
|
+
FileUtils.rm_rf(demo_dir) if Dir.exist?(demo_dir)
|
235
|
+
FileUtils.rm_rf('messages') if Dir.exist?('messages')
|
236
|
+
puts "\n✓ Demo completed and cleaned up"
|
237
|
+
end
|