smart_message 0.0.13 → 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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +120 -0
  4. data/Gemfile.lock +3 -3
  5. data/README.md +71 -25
  6. data/docs/index.md +2 -0
  7. data/docs/reference/transports.md +46 -21
  8. data/docs/transports/memory-transport.md +2 -1
  9. data/docs/transports/multi-transport.md +484 -0
  10. data/examples/file/00_run_all_file_demos.rb +260 -0
  11. data/examples/file/01_basic_file_transport_demo.rb +237 -0
  12. data/examples/file/02_fifo_transport_demo.rb +289 -0
  13. data/examples/file/03_file_watching_demo.rb +332 -0
  14. data/examples/file/04_multi_transport_file_demo.rb +432 -0
  15. data/examples/file/README.md +257 -0
  16. data/examples/memory/00_run_all_demos.rb +317 -0
  17. data/examples/memory/01_message_deduplication_demo.rb +18 -30
  18. data/examples/memory/02_dead_letter_queue_demo.rb +9 -9
  19. data/examples/memory/03_point_to_point_orders.rb +3 -3
  20. data/examples/memory/04_publish_subscribe_events.rb +15 -15
  21. data/examples/memory/05_many_to_many_chat.rb +19 -19
  22. data/examples/memory/06_stdout_publish_only.rb +145 -0
  23. data/examples/memory/07_proc_handlers_demo.rb +13 -13
  24. data/examples/memory/08_custom_logger_demo.rb +136 -136
  25. data/examples/memory/09_error_handling_demo.rb +7 -7
  26. data/examples/memory/10_entity_addressing_basic.rb +25 -25
  27. data/examples/memory/11_entity_addressing_with_filtering.rb +32 -32
  28. data/examples/memory/12_regex_filtering_microservices.rb +10 -10
  29. data/examples/memory/14_global_configuration_demo.rb +12 -12
  30. data/examples/memory/README.md +34 -17
  31. data/examples/memory/log/demo_app.log.1 +100 -0
  32. data/examples/memory/log/demo_app.log.2 +100 -0
  33. data/examples/multi_transport_example.rb +114 -0
  34. data/examples/redis/01_smart_home_iot_demo.rb +20 -20
  35. data/examples/utilities/box_it.rb +12 -0
  36. data/examples/utilities/doing.rb +19 -0
  37. data/examples/utilities/temp.md +28 -0
  38. data/lib/smart_message/base.rb +5 -7
  39. data/lib/smart_message/errors.rb +3 -0
  40. data/lib/smart_message/header.rb +1 -1
  41. data/lib/smart_message/logger/default.rb +1 -1
  42. data/lib/smart_message/messaging.rb +36 -6
  43. data/lib/smart_message/plugins.rb +46 -4
  44. data/lib/smart_message/serializer/base.rb +1 -1
  45. data/lib/smart_message/serializer.rb +3 -2
  46. data/lib/smart_message/subscription.rb +18 -20
  47. data/lib/smart_message/transport/async_publish_queue.rb +284 -0
  48. data/lib/smart_message/transport/fifo_operations.rb +264 -0
  49. data/lib/smart_message/transport/file_operations.rb +200 -0
  50. data/lib/smart_message/transport/file_transport.rb +149 -0
  51. data/lib/smart_message/transport/file_watching.rb +72 -0
  52. data/lib/smart_message/transport/partitioned_files.rb +46 -0
  53. data/lib/smart_message/transport/stdout_transport.rb +50 -36
  54. data/lib/smart_message/transport/stdout_transport.rb.backup +88 -0
  55. data/lib/smart_message/version.rb +1 -1
  56. metadata +24 -10
  57. data/ideas/README.md +0 -41
  58. data/ideas/agents.md +0 -1001
  59. data/ideas/database_transport.md +0 -980
  60. data/ideas/improvement.md +0 -359
  61. data/ideas/meshage.md +0 -1788
  62. data/ideas/message_discovery.md +0 -178
  63. data/ideas/message_schema.md +0 -1381
  64. data/lib/smart_message/wrapper.rb.bak +0 -132
  65. /data/examples/memory/{06_pretty_print_demo.rb → 16_pretty_print_demo.rb} +0 -0
@@ -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