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
@@ -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
- - [Redis Enhanced Transport](redis-enhanced-transport.md) - Advanced routing with patterns
507
- - [Redis Queue Transport](redis-queue-transport.md) - Persistent queues with load balancing
508
- - [Transport Comparison](redis-transport-comparison.md) - Compare all Redis transports
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
- - JSON serialization of complex business objects
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
- - Configure appropriate serializers for your data needs
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
- - Choose appropriate serializers for your data
680
- - Consider performance and compatibility requirements
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
- "serializer": "SmartMessage::Serializer::Json"
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')"
@@ -16,7 +16,6 @@ module Messages
16
16
  DESC
17
17
 
18
18
  transport SmartMessage::Transport::RedisTransport.new
19
- serializer SmartMessage::Serializer::Json.new
20
19
 
21
20
  VALID_PRIORITY = %w[low medium high emergency]
22
21
 
@@ -17,7 +17,6 @@ module Messages
17
17
  DESC
18
18
 
19
19
  transport SmartMessage::Transport::RedisTransport.new
20
- serializer SmartMessage::Serializer::Json.new
21
20
 
22
21
  VALID_ALARM_TYPES = %w[robbery vault_breach suspicious_activity]
23
22
  VALID_SEVERITY = %w[low medium high critical]
@@ -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