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,46 @@
1
+ # lib/smart_message/transport/partitioned_files.rb
2
+ # encoding: utf-8
3
+ # frozen_string_literal: true
4
+
5
+ module SmartMessage
6
+ module Transport
7
+ # Module for fan-out/partitioned file support.
8
+ module PartitionedFiles
9
+ def determine_file_path(payload, header)
10
+ if @options[:filename_selector]&.respond_to?(:call)
11
+ @options[:filename_selector].call(payload, header)
12
+ elsif @options[:directory]
13
+ File.join(@options[:directory], "#{header[:message_class_name].to_s.downcase}.log")
14
+ else
15
+ @options[:file_path]
16
+ end
17
+ end
18
+
19
+ def get_or_open_partition_handle(full_path)
20
+ @partition_handles ||= {}
21
+ @partition_mutexes ||= {}
22
+
23
+ unless @partition_handles[full_path]
24
+ ensure_directory_exists_for(full_path)
25
+ @partition_handles[full_path] = File.open(full_path, file_mode, encoding: @options[:encoding])
26
+ @partition_mutexes[full_path] = Mutex.new
27
+ end
28
+
29
+ @partition_handles[full_path]
30
+ end
31
+
32
+ def ensure_directory_exists_for(path)
33
+ dir = File.dirname(path)
34
+ FileUtils.mkdir_p(dir) if @options[:create_directories] && !Dir.exist?(dir)
35
+ end
36
+
37
+ def close_partition_handles
38
+ @partition_handles&.each do |_, handle|
39
+ handle.close
40
+ end
41
+ @partition_handles = {}
42
+ @partition_mutexes = {}
43
+ end
44
+ end
45
+ end
46
+ end
@@ -2,61 +2,75 @@
2
2
  # encoding: utf-8
3
3
  # frozen_string_literal: true
4
4
 
5
+ require_relative 'file_transport'
6
+
5
7
  module SmartMessage
6
8
  module Transport
7
9
  # STDOUT transport for testing and development
8
- # This transport outputs messages to STDOUT and optionally loops them back
9
- class StdoutTransport < Base
10
- def default_options
11
- {
12
- loopback: false,
13
- output: $stdout,
14
- format: :pretty # :pretty or :json
10
+ # This is a publish-only transport that outputs messages to STDOUT
11
+ # Now inherits from FileTransport but maintains specialized formatting
12
+ class StdoutTransport < FileTransport
13
+ def initialize(options = {})
14
+ # Merge STDOUT-specific defaults with FileTransport defaults
15
+ stdout_options = {
16
+ file_path: $stdout,
17
+ file_mode: 'w',
18
+ file_type: :regular,
19
+ format: :pretty, # :pretty or :json
20
+ enable_subscriptions: false, # STDOUT is publish-only
21
+ auto_flush: true
15
22
  }
23
+ super(stdout_options.merge(options))
16
24
  end
17
25
 
18
26
  # Default to JSON for readability in STDOUT
19
27
  def default_serializer
20
28
  SmartMessage::Serializer::Json.new
21
29
  end
22
-
30
+
31
+ # Override configuration to handle STDOUT-specific setup
23
32
  def configure
24
- @output = @options[:output].is_a?(String) ? File.open(@options[:output], 'w') : @options[:output]
33
+ # If file_path is a string, delegate to parent FileTransport
34
+ if @options[:file_path].is_a?(String)
35
+ super
36
+ else
37
+ # Use the IO object directly (like $stdout)
38
+ @file_handle = @options[:file_path]
39
+ @write_buffer = []
40
+ @last_flush = Time.now
41
+ @file_mutex = Mutex.new
42
+ end
25
43
  end
26
-
27
- # Enable/disable loopback mode
28
- def loopback=(enabled)
29
- @options[:loopback] = enabled
44
+
45
+ # Override write_to_file to handle STDOUT directly
46
+ def write_to_file(serialized_message)
47
+ # If using a string file path, delegate to parent
48
+ if @options[:file_path].is_a?(String)
49
+ super
50
+ else
51
+ # Use IO object directly
52
+ content = prepare_file_content(serialized_message)
53
+ @file_handle.write(content)
54
+ @file_handle.flush if @options[:auto_flush]
55
+ end
30
56
  end
31
57
 
32
- def loopback?
33
- @options[:loopback]
58
+ # Override the file content preparation to use custom formatting
59
+ def prepare_file_content(serialized_message)
60
+ format_message(@current_message_class, serialized_message)
34
61
  end
35
62
 
36
- # Publish message to STDOUT
37
- def do_publish(message_class, serialized_message)
38
- logger.debug { "[SmartMessage::StdoutTransport] do_publish called" }
39
- logger.debug { "[SmartMessage::StdoutTransport] message_class: #{message_class}" }
40
-
41
- @output.puts format_message(message_class, serialized_message)
42
- @output.flush
43
-
44
- # If loopback is enabled, route the message back through the dispatcher
45
- if loopback?
46
- logger.debug { "[SmartMessage::StdoutTransport] Loopback enabled, calling receive" }
47
- receive(message_class, serialized_message)
48
- end
49
- rescue => e
50
- logger.error { "[SmartMessage] Error in stdout transport do_publish: #{e.class.name} - #{e.message}" }
51
- raise
63
+ # Override subscribe methods to log warnings since this is a publish-only transport
64
+ def subscribe(message_class, process_method, filter_options = {})
65
+ logger.warn { "[SmartMessage::StdoutTransport] Subscription attempt ignored - STDOUT transport is publish-only (message_class: #{message_class}, process_method: #{process_method})" }
52
66
  end
53
67
 
54
- def connected?
55
- !@output.closed?
68
+ def unsubscribe(message_class, process_method)
69
+ logger.warn { "[SmartMessage::StdoutTransport] Unsubscribe attempt ignored - STDOUT transport is publish-only (message_class: #{message_class}, process_method: #{process_method})" }
56
70
  end
57
71
 
58
- def disconnect
59
- @output.close if @output.respond_to?(:close) && @output != $stdout && @output != $stderr
72
+ def unsubscribe!(message_class)
73
+ logger.warn { "[SmartMessage::StdoutTransport] Unsubscribe all attempt ignored - STDOUT transport is publish-only (message_class: #{message_class})" }
60
74
  end
61
75
 
62
76
  private
@@ -69,7 +83,7 @@ module SmartMessage
69
83
  message_class: message_class,
70
84
  serialized_message: serialized_message,
71
85
  timestamp: Time.now.iso8601
72
- }.to_json
86
+ }.to_json + "\n"
73
87
  else
74
88
  # Pretty format for human reading
75
89
  <<~MESSAGE
@@ -0,0 +1,88 @@
1
+ # lib/smart_message/transport/stdout_transport.rb
2
+ # encoding: utf-8
3
+ # frozen_string_literal: true
4
+
5
+ module SmartMessage
6
+ module Transport
7
+ # STDOUT transport for testing and development
8
+ # This is a publish-only transport that outputs messages to STDOUT
9
+ class StdoutTransport < Base
10
+ def default_options
11
+ {
12
+ output: $stdout,
13
+ format: :pretty # :pretty or :json
14
+ }
15
+ end
16
+
17
+ # Default to JSON for readability in STDOUT
18
+ def default_serializer
19
+ SmartMessage::Serializer::Json.new
20
+ end
21
+
22
+ def configure
23
+ @output = @options[:output].is_a?(String) ? File.open(@options[:output], 'w') : @options[:output]
24
+ end
25
+
26
+
27
+ # Publish message to STDOUT
28
+ def do_publish(message_class, serialized_message)
29
+ logger.debug { "[SmartMessage::StdoutTransport] do_publish called" }
30
+ logger.debug { "[SmartMessage::StdoutTransport] message_class: #{message_class}" }
31
+
32
+ @output.puts format_message(message_class, serialized_message)
33
+ @output.flush
34
+ rescue => e
35
+ logger.error { "[SmartMessage] Error in stdout transport do_publish: #{e.class.name} - #{e.message}" }
36
+ raise
37
+ end
38
+
39
+ def connected?
40
+ !@output.closed?
41
+ end
42
+
43
+ def disconnect
44
+ @output.close if @output.respond_to?(:close) && @output != $stdout && @output != $stderr
45
+ end
46
+
47
+ # Override subscribe methods to log warnings since this is a publish-only transport
48
+ def subscribe(message_class, process_method, filter_options = {})
49
+ logger.warn { "[SmartMessage::StdoutTransport] Subscription attempt ignored - STDOUT transport is publish-only (message_class: #{message_class}, process_method: #{process_method})" }
50
+ end
51
+
52
+ def unsubscribe(message_class, process_method)
53
+ logger.warn { "[SmartMessage::StdoutTransport] Unsubscribe attempt ignored - STDOUT transport is publish-only (message_class: #{message_class}, process_method: #{process_method})" }
54
+ end
55
+
56
+ def unsubscribe!(message_class)
57
+ logger.warn { "[SmartMessage::StdoutTransport] Unsubscribe all attempt ignored - STDOUT transport is publish-only (message_class: #{message_class})" }
58
+ end
59
+
60
+ private
61
+
62
+ def format_message(message_class, serialized_message)
63
+ if @options[:format] == :json
64
+ # Output as JSON for machine parsing
65
+ {
66
+ transport: 'stdout',
67
+ message_class: message_class,
68
+ serialized_message: serialized_message,
69
+ timestamp: Time.now.iso8601
70
+ }.to_json
71
+ else
72
+ # Pretty format for human reading
73
+ <<~MESSAGE
74
+
75
+ ===================================================
76
+ == SmartMessage Published via STDOUT Transport
77
+ == Message Class: #{message_class}
78
+ == Serializer: #{@serializer.class.name}
79
+ == Serialized Message:
80
+ #{serialized_message}
81
+ ===================================================
82
+
83
+ MESSAGE
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -3,5 +3,5 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  module SmartMessage
6
- VERSION = '0.0.13'
6
+ VERSION = '0.0.16'
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_message
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.13
4
+ version: 0.0.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dewayne VanHoozer
@@ -319,6 +319,7 @@ files:
319
319
  - docs/reference/serializers.md
320
320
  - docs/reference/transports.md
321
321
  - docs/transports/memory-transport.md
322
+ - docs/transports/multi-transport.md
322
323
  - docs/transports/redis-transport-comparison.md
323
324
  - docs/transports/redis-transport.md
324
325
  - examples/.gitignore
@@ -355,12 +356,19 @@ files:
355
356
  - examples/city_scenario/start_demo.sh
356
357
  - examples/city_scenario/stop_demo.sh
357
358
  - examples/city_scenario/visitor.rb
359
+ - examples/file/00_run_all_file_demos.rb
360
+ - examples/file/01_basic_file_transport_demo.rb
361
+ - examples/file/02_fifo_transport_demo.rb
362
+ - examples/file/03_file_watching_demo.rb
363
+ - examples/file/04_multi_transport_file_demo.rb
364
+ - examples/file/README.md
365
+ - examples/memory/00_run_all_demos.rb
358
366
  - examples/memory/01_message_deduplication_demo.rb
359
367
  - examples/memory/02_dead_letter_queue_demo.rb
360
368
  - examples/memory/03_point_to_point_orders.rb
361
369
  - examples/memory/04_publish_subscribe_events.rb
362
370
  - examples/memory/05_many_to_many_chat.rb
363
- - examples/memory/06_pretty_print_demo.rb
371
+ - examples/memory/06_stdout_publish_only.rb
364
372
  - examples/memory/07_proc_handlers_demo.rb
365
373
  - examples/memory/08_custom_logger_demo.rb
366
374
  - examples/memory/09_error_handling_demo.rb
@@ -370,10 +378,14 @@ files:
370
378
  - examples/memory/13_header_block_configuration.rb
371
379
  - examples/memory/14_global_configuration_demo.rb
372
380
  - examples/memory/15_logger_demo.rb
381
+ - examples/memory/16_pretty_print_demo.rb
373
382
  - examples/memory/README.md
383
+ - examples/memory/log/demo_app.log.1
384
+ - examples/memory/log/demo_app.log.2
374
385
  - examples/memory/memory_transport_architecture.svg
375
386
  - examples/memory/point_to_point_pattern.svg
376
387
  - examples/memory/publish_subscribe_pattern.svg
388
+ - examples/multi_transport_example.rb
377
389
  - examples/performance_metrics/benchmark_results_ractor_20250818_205603.json
378
390
  - examples/performance_metrics/benchmark_results_ractor_20250818_205831.json
379
391
  - examples/performance_metrics/benchmark_results_test_20250818_204942.json
@@ -394,13 +406,9 @@ files:
394
406
  - examples/redis/redis_transport_architecture.svg
395
407
  - examples/redis/smart_home_iot_dataflow.md
396
408
  - examples/redis/smart_home_system_architecture.svg
397
- - ideas/README.md
398
- - ideas/agents.md
399
- - ideas/database_transport.md
400
- - ideas/improvement.md
401
- - ideas/meshage.md
402
- - ideas/message_discovery.md
403
- - ideas/message_schema.md
409
+ - examples/utilities/box_it.rb
410
+ - examples/utilities/doing.rb
411
+ - examples/utilities/temp.md
404
412
  - lib/simple_stats.rb
405
413
  - lib/smart_message.rb
406
414
  - lib/smart_message/.idea/.gitignore
@@ -437,15 +445,21 @@ files:
437
445
  - lib/smart_message/serializer/json.rb
438
446
  - lib/smart_message/subscription.rb
439
447
  - lib/smart_message/transport.rb
448
+ - lib/smart_message/transport/async_publish_queue.rb
440
449
  - lib/smart_message/transport/base.rb
450
+ - lib/smart_message/transport/fifo_operations.rb
451
+ - lib/smart_message/transport/file_operations.rb
452
+ - lib/smart_message/transport/file_transport.rb
453
+ - lib/smart_message/transport/file_watching.rb
441
454
  - lib/smart_message/transport/memory_transport.rb
455
+ - lib/smart_message/transport/partitioned_files.rb
442
456
  - lib/smart_message/transport/redis_transport.rb
443
457
  - lib/smart_message/transport/registry.rb
444
458
  - lib/smart_message/transport/stdout_transport.rb
459
+ - lib/smart_message/transport/stdout_transport.rb.backup
445
460
  - lib/smart_message/utilities.rb
446
461
  - lib/smart_message/version.rb
447
462
  - lib/smart_message/versioning.rb
448
- - lib/smart_message/wrapper.rb.bak
449
463
  - mkdocs.yml
450
464
  - p2p_plan.md
451
465
  - p2p_roadmap.md
data/ideas/README.md DELETED
@@ -1,41 +0,0 @@
1
- # SmartMessage Ideas and Design Discussions
2
-
3
- This directory contains design discussions and architectural ideas for extending the SmartMessage framework. Each document explores a different aspect of potential enhancements to the system.
4
-
5
- ## database_transport.md
6
-
7
- Explores implementing a database-backed transport layer for SmartMessage, enabling persistent message queuing and reliable delivery without requiring external message brokers like RabbitMQ or Kafka. This approach would store messages directly in a PostgreSQL or MySQL database, providing built-in persistence, transactional guarantees, and the ability to query message history.
8
-
9
- The design includes database schema definitions, message lifecycle management (pending, processing, completed, failed states), retry mechanisms with exponential backoff, and dead letter queue functionality. This transport would be particularly useful for applications that already have a database but don't want the operational complexity of managing a separate message broker, or for scenarios requiring long-term message retention and complex querying capabilities.
10
-
11
- ## improvement.md
12
-
13
- Contains a comprehensive list of potential improvements and enhancements to the SmartMessage framework, covering areas from core functionality to developer experience. The ideas range from technical enhancements like performance optimizations and new transport implementations to architectural improvements such as better plugin systems and schema management.
14
-
15
- Key improvement areas include adding support for additional transports (Redis, AWS SQS, Google Pub/Sub), implementing message compression and encryption, enhancing the validation framework, improving error handling and retry logic, and adding comprehensive metrics and monitoring capabilities. The document also explores developer experience improvements like better debugging tools, enhanced documentation, and a potential web UI for message inspection.
16
-
17
- ## message_discovery.md
18
-
19
- Focuses on the service discovery and dynamic class creation capabilities that would allow SmartMessage-based services to automatically discover and use message types from other services without manual integration. This system would enable services to query a central registry to find available message schemas and dynamically create the corresponding Ruby classes at runtime.
20
-
21
- The discovery mechanism includes APIs for browsing available message types by service, environment, or tags, dynamic class generation from stored schemas without requiring Ruby source files, and automatic synchronization when schemas are updated. This enables true microservice architectures where services can integrate with new message types without code changes or deployments, supporting patterns like partner integrations, multi-tenant systems, and runtime service composition.
22
-
23
- ## message_schema.md
24
-
25
- Describes a comprehensive schema registry system that transforms SmartMessage from a messaging framework into a schema management platform. The core innovation is bidirectional conversion between SmartMessage Ruby classes and JSON Schema, enabling message definitions to be stored as data rather than code.
26
-
27
- The system includes automatic schema registration when classes are defined, version tracking and evolution management, and most importantly, the ability to serialize a Ruby class definition to JSON Schema and reconstruct it later using `to_json_schema` and `from_json_schema` methods. This enables powerful capabilities like storing schemas in databases, sharing schemas across different programming languages (with examples for Rust, Python, TypeScript, Go, and Java), runtime schema updates without deployment, and schema governance with approval workflows. The JSON Schema approach provides cross-language interoperability while maintaining safety (no code execution) and human readability, fundamentally changing how distributed systems manage message contracts.
28
-
29
- ## meshage.md
30
-
31
- Explores implementing a true mesh network transport for SmartMessage that enables completely decentralized messaging with location-agnostic publishing. Unlike direct peer-to-peer systems, mesh networks allow publishers to send messages to service names without knowing which physical nodes host those services - the mesh automatically routes messages through intermediate nodes until they reach their destination or expire.
32
-
33
- The design emphasizes the key mesh network principles of complete decentralization, multi-hop message routing, and self-terminating messages with TTL. Services register themselves with the mesh, and the network maintains a distributed service directory that enables automatic route discovery. Messages can travel through multiple intermediate nodes (A → C → F → K) to reach their destination, with the mesh providing fault tolerance through alternate routing paths. The document incorporates insights from existing P2P libraries (journeta, p2p2) for proven patterns in NAT traversal, connection management, and network coordination. Multi-layer deduplication ensures message storms are prevented at subscriber, node, and network levels, while network control messages handle presence, health monitoring, and graceful shutdown protocols.
34
-
35
- ## agents.md
36
-
37
- Comprehensive exploration of AI agents using SmartMessage for intelligent communication patterns. The document examines how AI agents represent the next evolution in distributed systems - intelligent entities that can make contextual decisions, adapt to scenarios, and communicate using natural language understanding combined with structured messaging.
38
-
39
- The analysis covers three complementary architecture patterns: Agent99 for request/response service coordination, SmartMessage AI for context-aware dynamic messaging, and hybrid approaches that combine both. Key innovations include contextual message selection where AI chooses appropriate message types based on scenarios, intelligent property generation using LLM understanding of validation constraints, and self-healing validation with automatic retry logic.
40
-
41
- The document includes a crucial analysis of Model Context Protocol (MCP) integration, demonstrating how MCP's resource sharing capabilities complement rather than compete with SmartMessage+Agent99. The integration creates a three-layer intelligence stack: Context Layer (MCP) for rich data access, Intelligence Layer (AI + SmartMessage) for smart decision making, and Coordination Layer (Agent99) for multi-agent orchestration. Real-world applications span smart city management, autonomous supply chains, and healthcare coordination systems, showing how these technologies enable truly intelligent distributed systems that understand context, communicate naturally, and coordinate seamlessly.