smart_message 0.0.10 → 0.0.12

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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/deploy-github-pages.yml +38 -0
  3. data/.gitignore +5 -0
  4. data/CHANGELOG.md +30 -0
  5. data/Gemfile.lock +35 -4
  6. data/README.md +169 -71
  7. data/Rakefile +29 -4
  8. data/docs/assets/images/ddq_architecture.svg +130 -0
  9. data/docs/assets/images/dlq_architecture.svg +115 -0
  10. data/docs/assets/images/enhanced-dual-publishing.svg +136 -0
  11. data/docs/assets/images/enhanced-fluent-api.svg +149 -0
  12. data/docs/assets/images/enhanced-microservices-routing.svg +115 -0
  13. data/docs/assets/images/enhanced-pattern-matching.svg +107 -0
  14. data/docs/assets/images/fluent-api-demo.svg +59 -0
  15. data/docs/assets/images/performance-comparison.svg +161 -0
  16. data/docs/assets/images/redis-basic-architecture.svg +53 -0
  17. data/docs/assets/images/redis-enhanced-architecture.svg +88 -0
  18. data/docs/assets/images/redis-queue-architecture.svg +101 -0
  19. data/docs/assets/images/smart_message.jpg +0 -0
  20. data/docs/assets/images/smart_message_walking.jpg +0 -0
  21. data/docs/assets/images/smartmessage_architecture_overview.svg +173 -0
  22. data/docs/assets/images/transport-comparison-matrix.svg +171 -0
  23. data/docs/assets/javascripts/mathjax.js +17 -0
  24. data/docs/assets/stylesheets/extra.css +51 -0
  25. data/docs/{addressing.md → core-concepts/addressing.md} +5 -7
  26. data/docs/{architecture.md → core-concepts/architecture.md} +78 -138
  27. data/docs/{dispatcher.md → core-concepts/dispatcher.md} +21 -21
  28. data/docs/{message_filtering.md → core-concepts/message-filtering.md} +2 -3
  29. data/docs/{message_processing.md → core-concepts/message-processing.md} +17 -17
  30. data/docs/{troubleshooting.md → development/troubleshooting.md} +7 -7
  31. data/docs/{examples.md → getting-started/examples.md} +115 -89
  32. data/docs/{getting-started.md → getting-started/quick-start.md} +47 -18
  33. data/docs/guides/redis-queue-getting-started.md +697 -0
  34. data/docs/guides/redis-queue-patterns.md +889 -0
  35. data/docs/guides/redis-queue-production.md +1091 -0
  36. data/docs/index.md +64 -0
  37. data/docs/{dead_letter_queue.md → reference/dead-letter-queue.md} +2 -3
  38. data/docs/{logging.md → reference/logging.md} +1 -1
  39. data/docs/{message_deduplication.md → reference/message-deduplication.md} +1 -0
  40. data/docs/{proc_handlers_summary.md → reference/proc-handlers.md} +7 -6
  41. data/docs/{serializers.md → reference/serializers.md} +3 -5
  42. data/docs/{transports.md → reference/transports.md} +133 -11
  43. data/docs/transports/memory-transport.md +374 -0
  44. data/docs/transports/redis-enhanced-transport.md +524 -0
  45. data/docs/transports/redis-queue-transport.md +1304 -0
  46. data/docs/transports/redis-transport-comparison.md +496 -0
  47. data/docs/transports/redis-transport.md +509 -0
  48. data/examples/README.md +98 -5
  49. data/examples/city_scenario/911_emergency_call_flow.svg +99 -0
  50. data/examples/city_scenario/README.md +515 -0
  51. data/examples/city_scenario/ai_visitor_intelligence_flow.svg +108 -0
  52. data/examples/city_scenario/citizen.rb +195 -0
  53. data/examples/city_scenario/city_diagram.svg +125 -0
  54. data/examples/city_scenario/common/health_monitor.rb +80 -0
  55. data/examples/city_scenario/common/logger.rb +30 -0
  56. data/examples/city_scenario/emergency_dispatch_center.rb +270 -0
  57. data/examples/city_scenario/fire_department.rb +446 -0
  58. data/examples/city_scenario/fire_emergency_flow.svg +95 -0
  59. data/examples/city_scenario/health_department.rb +100 -0
  60. data/examples/city_scenario/health_monitoring_system.svg +130 -0
  61. data/examples/city_scenario/house.rb +244 -0
  62. data/examples/city_scenario/local_bank.rb +217 -0
  63. data/examples/city_scenario/messages/emergency_911_message.rb +81 -0
  64. data/examples/city_scenario/messages/emergency_resolved_message.rb +43 -0
  65. data/examples/city_scenario/messages/fire_dispatch_message.rb +43 -0
  66. data/examples/city_scenario/messages/fire_emergency_message.rb +45 -0
  67. data/examples/city_scenario/messages/health_check_message.rb +22 -0
  68. data/examples/city_scenario/messages/health_status_message.rb +35 -0
  69. data/examples/city_scenario/messages/police_dispatch_message.rb +46 -0
  70. data/examples/city_scenario/messages/silent_alarm_message.rb +38 -0
  71. data/examples/city_scenario/police_department.rb +316 -0
  72. data/examples/city_scenario/redis_monitor.rb +129 -0
  73. data/examples/city_scenario/redis_stats.rb +743 -0
  74. data/examples/city_scenario/room_for_improvement.md +240 -0
  75. data/examples/city_scenario/security_emergency_flow.svg +95 -0
  76. data/examples/city_scenario/service_internal_architecture.svg +154 -0
  77. data/examples/city_scenario/smart_message_ai_agent.rb +364 -0
  78. data/examples/city_scenario/start_demo.sh +236 -0
  79. data/examples/city_scenario/stop_demo.sh +106 -0
  80. data/examples/city_scenario/visitor.rb +631 -0
  81. data/examples/{10_message_deduplication.rb → memory/01_message_deduplication_demo.rb} +1 -1
  82. data/examples/{09_dead_letter_queue_demo.rb → memory/02_dead_letter_queue_demo.rb} +13 -40
  83. data/examples/{01_point_to_point_orders.rb → memory/03_point_to_point_orders.rb} +1 -1
  84. data/examples/{02_publish_subscribe_events.rb → memory/04_publish_subscribe_events.rb} +2 -2
  85. data/examples/{03_many_to_many_chat.rb → memory/05_many_to_many_chat.rb} +4 -4
  86. data/examples/{show_me.rb → memory/06_pretty_print_demo.rb} +1 -1
  87. data/examples/{05_proc_handlers.rb → memory/07_proc_handlers_demo.rb} +2 -2
  88. data/examples/{06_custom_logger_example.rb → memory/08_custom_logger_demo.rb} +17 -14
  89. data/examples/{07_error_handling_scenarios.rb → memory/09_error_handling_demo.rb} +4 -4
  90. data/examples/{08_entity_addressing_basic.rb → memory/10_entity_addressing_basic.rb} +8 -8
  91. data/examples/{08_entity_addressing_with_filtering.rb → memory/11_entity_addressing_with_filtering.rb} +6 -6
  92. data/examples/{09_regex_filtering_microservices.rb → memory/12_regex_filtering_microservices.rb} +2 -2
  93. data/examples/{10_header_block_configuration.rb → memory/13_header_block_configuration.rb} +6 -6
  94. data/examples/{11_global_configuration_example.rb → memory/14_global_configuration_demo.rb} +19 -8
  95. data/examples/{show_logger.rb → memory/15_logger_demo.rb} +1 -1
  96. data/examples/memory/README.md +163 -0
  97. data/examples/memory/memory_transport_architecture.svg +90 -0
  98. data/examples/memory/point_to_point_pattern.svg +94 -0
  99. data/examples/memory/publish_subscribe_pattern.svg +125 -0
  100. data/examples/{04_redis_smart_home_iot.rb → redis/01_smart_home_iot_demo.rb} +5 -5
  101. data/examples/redis/README.md +230 -0
  102. data/examples/redis/alert_system_flow.svg +127 -0
  103. data/examples/redis/dashboard_status_flow.svg +107 -0
  104. data/examples/redis/device_command_flow.svg +113 -0
  105. data/examples/redis/redis_transport_architecture.svg +115 -0
  106. data/examples/{smart_home_iot_dataflow.md → redis/smart_home_iot_dataflow.md} +4 -116
  107. data/examples/redis/smart_home_system_architecture.svg +133 -0
  108. data/examples/redis_enhanced/README.md +319 -0
  109. data/examples/redis_enhanced/enhanced_01_basic_patterns.rb +233 -0
  110. data/examples/redis_enhanced/enhanced_02_fluent_api.rb +331 -0
  111. data/examples/redis_enhanced/enhanced_03_dual_publishing.rb +281 -0
  112. data/examples/redis_enhanced/enhanced_04_advanced_routing.rb +419 -0
  113. data/examples/redis_queue/01_basic_messaging.rb +221 -0
  114. data/examples/redis_queue/01_comprehensive_examples.rb +508 -0
  115. data/examples/redis_queue/02_pattern_routing.rb +405 -0
  116. data/examples/redis_queue/03_fluent_api.rb +422 -0
  117. data/examples/redis_queue/04_load_balancing.rb +486 -0
  118. data/examples/redis_queue/05_microservices.rb +735 -0
  119. data/examples/redis_queue/06_emergency_alerts.rb +777 -0
  120. data/examples/redis_queue/07_queue_management.rb +587 -0
  121. data/examples/redis_queue/README.md +366 -0
  122. data/examples/redis_queue/enhanced_01_basic_patterns.rb +233 -0
  123. data/examples/redis_queue/enhanced_02_fluent_api.rb +331 -0
  124. data/examples/redis_queue/enhanced_03_dual_publishing.rb +281 -0
  125. data/examples/redis_queue/enhanced_04_advanced_routing.rb +419 -0
  126. data/examples/redis_queue/redis_queue_architecture.svg +148 -0
  127. data/ideas/README.md +41 -0
  128. data/ideas/agents.md +1001 -0
  129. data/ideas/database_transport.md +980 -0
  130. data/ideas/improvement.md +359 -0
  131. data/ideas/meshage.md +1788 -0
  132. data/ideas/message_discovery.md +178 -0
  133. data/ideas/message_schema.md +1381 -0
  134. data/lib/smart_message/.idea/.gitignore +8 -0
  135. data/lib/smart_message/.idea/markdown.xml +6 -0
  136. data/lib/smart_message/.idea/misc.xml +4 -0
  137. data/lib/smart_message/.idea/modules.xml +8 -0
  138. data/lib/smart_message/.idea/smart_message.iml +16 -0
  139. data/lib/smart_message/.idea/vcs.xml +6 -0
  140. data/lib/smart_message/addressing.rb +15 -0
  141. data/lib/smart_message/base.rb +0 -2
  142. data/lib/smart_message/configuration.rb +1 -1
  143. data/lib/smart_message/logger.rb +15 -4
  144. data/lib/smart_message/plugins.rb +5 -2
  145. data/lib/smart_message/serializer.rb +14 -0
  146. data/lib/smart_message/transport/redis_enhanced_transport.rb +399 -0
  147. data/lib/smart_message/transport/redis_queue_transport.rb +555 -0
  148. data/lib/smart_message/transport/registry.rb +1 -0
  149. data/lib/smart_message/transport.rb +34 -1
  150. data/lib/smart_message/version.rb +1 -1
  151. data/lib/smart_message.rb +5 -52
  152. data/mkdocs.yml +184 -0
  153. data/p2p_plan.md +326 -0
  154. data/p2p_roadmap.md +287 -0
  155. data/smart_message.gemspec +2 -0
  156. data/smart_message.svg +51 -0
  157. metadata +170 -44
  158. data/docs/README.md +0 -57
  159. data/examples/dead_letters.jsonl +0 -12
  160. data/examples/temp.txt +0 -94
  161. data/examples/tmux_chat/README.md +0 -283
  162. data/examples/tmux_chat/bot_agent.rb +0 -278
  163. data/examples/tmux_chat/human_agent.rb +0 -199
  164. data/examples/tmux_chat/room_monitor.rb +0 -160
  165. data/examples/tmux_chat/shared_chat_system.rb +0 -328
  166. data/examples/tmux_chat/start_chat_demo.sh +0 -190
  167. data/examples/tmux_chat/stop_chat_demo.sh +0 -22
  168. /data/docs/{properties.md → core-concepts/properties.md} +0 -0
  169. /data/docs/{ideas_to_think_about.md → development/ideas.md} +0 -0
@@ -0,0 +1,108 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="700" height="500" viewBox="0 0 700 500" xmlns="http://www.w3.org/2000/svg">
3
+ <defs>
4
+ <style>
5
+ .bg { fill: transparent; }
6
+ .visitor { fill: #2a1a3a; stroke: #aa4aff; stroke-width: 2; rx: 8; }
7
+ .ai { fill: #1a3a3a; stroke: #4affaa; stroke-width: 2; rx: 8; }
8
+ .emergency { fill: #3a1a1a; stroke: #ff4a4a; stroke-width: 2; rx: 8; }
9
+ .message { stroke: #aa4aff; stroke-width: 2; fill: none; marker-end: url(#arrowhead); }
10
+ .analysis { stroke: #4affaa; stroke-width: 2; fill: none; marker-end: url(#arrowhead-green); stroke-dasharray: 5,3; }
11
+ .publish { stroke: #ff4a4a; stroke-width: 3; fill: none; marker-end: url(#arrowhead-red); }
12
+ .text { fill: #ffffff; font-family: 'Arial', sans-serif; font-size: 12px; }
13
+ .title { fill: #4a9eff; font-family: 'Arial', sans-serif; font-size: 18px; font-weight: bold; }
14
+ .subtitle { fill: #ffaa4a; font-family: 'Arial', sans-serif; font-size: 11px; }
15
+ .note { fill: #aaaaaa; font-family: 'Arial', sans-serif; font-size: 10px; }
16
+ .self-message { fill: #2a1a3a; stroke: #aa4aff; stroke-width: 1; rx: 4; }
17
+ </style>
18
+ <marker id="arrowhead" markerWidth="8" markerHeight="6"
19
+ refX="8" refY="3" orient="auto">
20
+ <polygon points="0 0, 8 3, 0 6" fill="#aa4aff" />
21
+ </marker>
22
+ <marker id="arrowhead-green" markerWidth="8" markerHeight="6"
23
+ refX="8" refY="3" orient="auto">
24
+ <polygon points="0 0, 8 3, 0 6" fill="#4affaa" />
25
+ </marker>
26
+ <marker id="arrowhead-red" markerWidth="8" markerHeight="6"
27
+ refX="8" refY="3" orient="auto">
28
+ <polygon points="0 0, 8 3, 0 6" fill="#ff4a4a" />
29
+ </marker>
30
+ </defs>
31
+
32
+ <!-- Background -->
33
+ <rect class="bg" width="700" height="500"/>
34
+
35
+ <!-- Title -->
36
+ <text x="350" y="25" text-anchor="middle" class="title">AI Visitor Intelligence Flow</text>
37
+ <text x="350" y="45" text-anchor="middle" class="subtitle">AI-Powered Emergency Incident Reporting System</text>
38
+
39
+ <!-- Participants -->
40
+ <rect x="50" y="80" width="140" height="80" class="visitor"/>
41
+ <text x="120" y="105" text-anchor="middle" class="text">🧑‍💼 Visitor (AI)</text>
42
+ <text x="120" y="125" text-anchor="middle" class="subtitle">Incident Observer</text>
43
+ <text x="120" y="145" text-anchor="middle" class="subtitle">Smart Reporter</text>
44
+
45
+ <rect x="280" y="80" width="140" height="80" class="ai"/>
46
+ <text x="350" y="105" text-anchor="middle" class="text">🤖 RubyLLM</text>
47
+ <text x="350" y="125" text-anchor="middle" class="subtitle">AI Analysis Engine</text>
48
+ <text x="350" y="145" text-anchor="middle" class="subtitle">Message Intelligence</text>
49
+
50
+ <rect x="510" y="80" width="140" height="80" class="emergency"/>
51
+ <text x="580" y="105" text-anchor="middle" class="text">🚨 Emergency</text>
52
+ <text x="580" y="125" text-anchor="middle" class="text">Services</text>
53
+ <text x="580" y="145" text-anchor="middle" class="subtitle">Response Network</text>
54
+
55
+ <!-- Vertical lifelines -->
56
+ <line x1="120" y1="160" x2="120" y2="450" stroke="#666" stroke-width="2" stroke-dasharray="3,3"/>
57
+ <line x1="350" y1="160" x2="350" y2="450" stroke="#666" stroke-width="2" stroke-dasharray="3,3"/>
58
+ <line x1="580" y1="160" x2="580" y2="450" stroke="#666" stroke-width="2" stroke-dasharray="3,3"/>
59
+
60
+ <!-- Message Flow -->
61
+ <!-- 1. Witness incident (self message) -->
62
+ <rect x="80" y="180" width="80" height="25" class="self-message"/>
63
+ <text x="120" y="197" text-anchor="middle" class="note">Witness incident</text>
64
+
65
+ <!-- 2. Analyze message types -->
66
+ <path d="M 120 220 L 350 220" class="message"/>
67
+ <text x="235" y="215" text-anchor="middle" class="text">Analyze available message types</text>
68
+ <rect x="160" y="230" width="160" height="40" fill="#1a1a1a" stroke="#aa4aff" rx="4"/>
69
+ <text x="240" y="245" text-anchor="middle" class="note">Dynamic message discovery</text>
70
+ <text x="240" y="260" text-anchor="middle" class="note">Property analysis</text>
71
+
72
+ <!-- 3. AI selection response -->
73
+ <path d="M 350 290 L 120 290" class="analysis"/>
74
+ <text x="235" y="285" text-anchor="middle" class="text">Select appropriate message type</text>
75
+ <rect x="180" y="300" width="140" height="40" fill="#2a3a2a" stroke="#4affaa" rx="4"/>
76
+ <text x="250" y="315" text-anchor="middle" class="note">SilentAlarmMessage for robbery</text>
77
+ <text x="250" y="330" text-anchor="middle" class="note">FireEmergencyMessage for fire</text>
78
+
79
+ <!-- 4. Generate properties -->
80
+ <path d="M 120 360 L 350 360" class="message"/>
81
+ <text x="235" y="355" text-anchor="middle" class="text">Generate realistic properties</text>
82
+ <rect x="160" y="370" width="160" height="40" fill="#1a1a1a" stroke="#aa4aff" rx="4"/>
83
+ <text x="240" y="385" text-anchor="middle" class="note">Bank names, locations</text>
84
+ <text x="240" y="400" text-anchor="middle" class="note">Fire types, severities</text>
85
+
86
+ <!-- 5. Publish emergency message -->
87
+ <path d="M 120 430 L 580 430" class="publish"/>
88
+ <text x="350" y="425" text-anchor="middle" class="text">Publish selected message</text>
89
+ <text x="350" y="445" text-anchor="middle" class="note">Emergency services respond based on message type</text>
90
+
91
+ <!-- AI Intelligence Box -->
92
+ <rect x="50" y="350" width="200" height="80" fill="#1a2a1a" stroke="#4affaa" rx="6"/>
93
+ <text x="60" y="370" class="text">AI Intelligence Features:</text>
94
+ <text x="60" y="385" class="note">• Dynamic message type discovery</text>
95
+ <text x="60" y="400" class="note">• Context-aware message selection</text>
96
+ <text x="60" y="415" class="note">• Realistic property generation</text>
97
+ <text x="60" y="430" class="note">• Comprehensive interaction logging</text>
98
+
99
+ <!-- Response Examples Box -->
100
+ <rect x="420" y="220" width="230" height="120" fill="#1a1a1a" stroke="#ff4a4a" rx="6"/>
101
+ <text x="430" y="240" class="text">Emergency Response Examples:</text>
102
+ <text x="430" y="260" class="note">🏦 Bank Robbery → SilentAlarmMessage</text>
103
+ <text x="430" y="275" class="note"> • Location: "First National Bank"</text>
104
+ <text x="430" y="290" class="note"> • Threat level: "high"</text>
105
+ <text x="430" y="310" class="note">🔥 Building Fire → FireEmergencyMessage</text>
106
+ <text x="430" y="325" class="note"> • Fire type: "electrical"</text>
107
+ <text x="430" y="340" class="note"> • Severity: "critical"</text>
108
+ </svg>
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env ruby
2
+ # examples/multi_program_demo/citizen.rb
3
+
4
+ require_relative '../../lib/smart_message'
5
+ require_relative 'messages/emergency_911_message'
6
+
7
+ require_relative 'common/logger'
8
+
9
+ class Citizen
10
+ include Common::Logger
11
+
12
+ def initialize
13
+ @service_name = 'citizen'
14
+ @names = ['John Smith', 'Mary Johnson', 'Robert Williams', 'Patricia Brown', 'Michael Davis']
15
+ @locations = [
16
+ '123 Main Street',
17
+ '456 Oak Avenue',
18
+ '789 Pine Lane',
19
+ '321 Elm Drive',
20
+ '654 Maple Road',
21
+ '987 Cedar Court',
22
+ '147 Birch Way',
23
+ '258 Spruce Boulevard'
24
+ ]
25
+
26
+ @emergency_scenarios = [
27
+ # Fires
28
+ { type: 'fire', severity: 'high',
29
+ description: 'House is on fire! Smoke everywhere!',
30
+ fire: true, injuries: true, victims: 2 },
31
+ { type: 'fire', severity: 'critical',
32
+ description: 'Kitchen grease fire spreading to cabinets!',
33
+ fire: true, injuries: false },
34
+
35
+ # Medical
36
+ { type: 'medical', severity: 'critical',
37
+ description: 'Heart attack! Person unconscious!',
38
+ injuries: true, victims: 1 },
39
+ { type: 'medical', severity: 'high',
40
+ description: 'Elderly person fell down stairs, bleeding heavily',
41
+ injuries: true, victims: 1 },
42
+
43
+ # Crimes
44
+ { type: 'crime', severity: 'high',
45
+ description: 'Break-in in progress! I can see them in my neighbor\'s house!',
46
+ weapons: false, suspects: true },
47
+ { type: 'crime', severity: 'critical',
48
+ description: 'Armed robbery at the corner store!',
49
+ weapons: true, suspects: true },
50
+ { type: 'crime', severity: 'medium',
51
+ description: 'My car was stolen from my driveway',
52
+ weapons: false, suspects: false },
53
+
54
+ # Accidents
55
+ { type: 'accident', severity: 'medium',
56
+ description: 'Two car collision at the intersection',
57
+ vehicles: 2, injuries: true, victims: 2 },
58
+ { type: 'accident', severity: 'critical',
59
+ description: 'Multi-car pileup on the highway! At least 5 cars!',
60
+ vehicles: 5, injuries: true, victims: 8, fire: true },
61
+ { type: 'accident', severity: 'low',
62
+ description: 'Fender bender in parking lot',
63
+ vehicles: 2, injuries: false },
64
+
65
+ # Rescue
66
+ { type: 'rescue', severity: 'high',
67
+ description: 'Child stuck in storm drain!',
68
+ injuries: false, victims: 1 },
69
+ { type: 'rescue', severity: 'critical',
70
+ description: 'Person trapped in collapsed building!',
71
+ injuries: true, victims: 2 },
72
+
73
+ # Hazmat
74
+ { type: 'hazmat', severity: 'critical',
75
+ description: 'Chemical spill from overturned truck! Strong fumes!',
76
+ hazmat: true, injuries: true, victims: 3 },
77
+
78
+ # Other
79
+ { type: 'other', severity: 'low',
80
+ description: 'Suspicious person looking into car windows',
81
+ suspects: true },
82
+ { type: 'other', severity: 'medium',
83
+ description: 'Power lines down across the road',
84
+ hazmat: false }
85
+ ]
86
+
87
+ Messages::Emergency911Message.from = @service_name
88
+ end
89
+
90
+ # def setup_logging
91
+ # log_file = File.join(__dir__, 'citizen.log')
92
+ # logger = Logger.new(log_file)
93
+ # logger.level = Logger::INFO
94
+ # logger.formatter = proc do |severity, datetime, progname, msg|
95
+ # "#{datetime.strftime('%Y-%m-%d %H:%M:%S')} [#{severity}] #{msg}\n"
96
+ # end
97
+ # logger.info("Citizen 911 caller started")
98
+ # end
99
+
100
+ def make_emergency_call
101
+ scenario = @emergency_scenarios.sample
102
+ caller_name = @names.sample
103
+ location = @locations.sample
104
+ phone = "555-#{rand(1000..9999)}"
105
+
106
+ puts "\n📱 Citizen making 911 call..."
107
+ puts " Caller: #{caller_name}"
108
+ puts " Location: #{location}"
109
+ puts " Emergency: #{scenario[:type]} - #{scenario[:description]}"
110
+
111
+ call = Messages::Emergency911Message.new(
112
+ caller_name: caller_name,
113
+ caller_phone: phone,
114
+ caller_location: location,
115
+ emergency_type: scenario[:type],
116
+ description: scenario[:description],
117
+ severity: scenario[:severity],
118
+ injuries_reported: scenario[:injuries],
119
+ number_of_victims: scenario[:victims],
120
+ fire_involved: scenario[:fire],
121
+ weapons_involved: scenario[:weapons],
122
+ hazardous_materials: scenario[:hazmat],
123
+ vehicles_involved: scenario[:vehicles],
124
+ suspects_on_scene: scenario[:suspects],
125
+ timestamp: Time.now.iso8601,
126
+ from: "citizen-#{caller_name.downcase.gsub(' ', '_')}",
127
+ to: '911'
128
+ )
129
+
130
+ call.publish
131
+
132
+ puts " ✅ 911 call placed successfully"
133
+ logger.info("911 call placed: #{scenario[:type]} at #{location} - #{scenario[:description]}")
134
+
135
+ call
136
+ rescue => e
137
+ puts " ❌ Error making 911 call: #{e.message}"
138
+ logger.error("Error making 911 call: #{e.message}")
139
+ nil
140
+ end
141
+
142
+ def run_interactive
143
+ puts "👤 Citizen 911 Emergency Caller"
144
+ puts " Press Enter to make a random 911 call"
145
+ puts " Type 'auto' for automatic calls every 15-30 seconds"
146
+ puts " Type 'quit' to exit\n\n"
147
+
148
+ loop do
149
+ print "Action (enter/auto/quit): "
150
+ input = gets&.chomp&.downcase
151
+
152
+ case input
153
+ when '', nil
154
+ make_emergency_call
155
+ when 'auto'
156
+ run_automatic
157
+ break
158
+ when 'quit', 'q', 'exit'
159
+ puts "👤 Citizen exiting..."
160
+ break
161
+ else
162
+ puts "Unknown command. Press Enter for call, 'auto' for automatic, 'quit' to exit"
163
+ end
164
+ end
165
+ end
166
+
167
+ def run_automatic
168
+ puts "\n👤 Starting automatic 911 calls (every 15-30 seconds)"
169
+ puts " Press Ctrl+C to stop\n\n"
170
+
171
+ Signal.trap('INT') do
172
+ puts "\n👤 Stopping automatic calls..."
173
+ exit(0)
174
+ end
175
+
176
+ loop do
177
+ make_emergency_call
178
+ wait_time = rand(15..30)
179
+ puts " ⏰ Next call in #{wait_time} seconds...\n"
180
+ sleep(wait_time)
181
+ end
182
+ end
183
+ end
184
+
185
+ # Run the citizen caller
186
+ if __FILE__ == $0
187
+ citizen = Citizen.new
188
+
189
+ # Check for command line argument
190
+ if ARGV[0] == 'auto'
191
+ citizen.run_automatic
192
+ else
193
+ citizen.run_interactive
194
+ end
195
+ end
@@ -0,0 +1,125 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="1200" height="800" xmlns="http://www.w3.org/2000/svg">
3
+ <style>
4
+ .service-box { fill: #f0f8ff; stroke: #4169e1; stroke-width: 2; }
5
+ .message-arrow { stroke: #2e8b57; stroke-width: 2; marker-end: url(#arrowhead); }
6
+ .emergency-arrow { stroke: #dc143c; stroke-width: 3; marker-end: url(#arrowhead); }
7
+ .health-arrow { stroke: #1e90ff; stroke-width: 2; marker-end: url(#arrowhead); }
8
+ .response-arrow { stroke: #ff8c00; stroke-width: 2; marker-end: url(#arrowhead); }
9
+ .service-text { font-family: Arial, sans-serif; font-size: 14px; font-weight: bold; text-anchor: middle; }
10
+ .message-text { font-family: Arial, sans-serif; font-size: 12px; fill: #333; }
11
+ .title-text { font-family: Arial, sans-serif; font-size: 18px; font-weight: bold; text-anchor: middle; }
12
+ .legend-text { font-family: Arial, sans-serif; font-size: 12px; }
13
+ </style>
14
+
15
+ <defs>
16
+ <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
17
+ <polygon points="0 0, 10 3.5, 0 7" fill="#333"/>
18
+ </marker>
19
+ </defs>
20
+
21
+ <!-- Title -->
22
+ <text x="600" y="30" class="title-text">SmartMessage City Demo - Service Communication</text>
23
+
24
+ <!-- Services -->
25
+
26
+ <!-- Health Department (Central Hub) -->
27
+ <rect x="500" y="60" width="200" height="80" class="service-box" rx="10"/>
28
+ <text x="600" y="85" class="service-text">Health Department</text>
29
+ <text x="600" y="105" class="message-text">Broadcasts HealthCheck every 5s</text>
30
+ <text x="600" y="120" class="message-text">Displays HealthStatus with colors</text>
31
+
32
+ <!-- Police Department -->
33
+ <rect x="100" y="200" width="180" height="80" class="service-box" rx="10"/>
34
+ <text x="190" y="225" class="service-text">Police Department</text>
35
+ <text x="190" y="245" class="message-text">Responds to health checks</text>
36
+ <text x="190" y="260" class="message-text">Dispatches cars to bank alarms</text>
37
+
38
+ <!-- Fire Department -->
39
+ <rect x="920" y="200" width="180" height="80" class="service-box" rx="10"/>
40
+ <text x="1010" y="225" class="service-text">Fire Department</text>
41
+ <text x="1010" y="245" class="message-text">Responds to health checks</text>
42
+ <text x="1010" y="260" class="message-text">Dispatches engines to fires</text>
43
+
44
+ <!-- Local Bank -->
45
+ <rect x="300" y="400" width="180" height="80" class="service-box" rx="10"/>
46
+ <text x="390" y="425" class="service-text">Local Bank</text>
47
+ <text x="390" y="445" class="message-text">Responds to health checks</text>
48
+ <text x="390" y="460" class="message-text">Triggers silent alarms</text>
49
+
50
+ <!-- Houses -->
51
+ <rect x="720" y="400" width="180" height="80" class="service-box" rx="10"/>
52
+ <text x="810" y="425" class="service-text">Houses</text>
53
+ <text x="810" y="445" class="message-text">Respond to health checks</text>
54
+ <text x="810" y="460" class="message-text">Occasionally catch fire</text>
55
+
56
+ <!-- Health Check Broadcasts (Blue arrows) -->
57
+ <path d="M 580 140 L 220 200" class="health-arrow"/>
58
+ <text x="350" y="165" class="message-text">HealthCheck</text>
59
+
60
+ <path d="M 620 140 L 990 200" class="health-arrow"/>
61
+ <text x="750" y="165" class="message-text">HealthCheck</text>
62
+
63
+ <path d="M 570 140 L 420 400" class="health-arrow"/>
64
+ <text x="450" y="270" class="message-text">HealthCheck</text>
65
+
66
+ <path d="M 630 140 L 780 400" class="health-arrow"/>
67
+ <text x="750" y="270" class="message-text">HealthCheck</text>
68
+
69
+ <!-- Health Status Responses (Orange arrows) -->
70
+ <path d="M 220 200 L 580 140" class="response-arrow"/>
71
+ <text x="350" y="185" class="message-text">HealthStatus</text>
72
+
73
+ <path d="M 990 200 L 620 140" class="response-arrow"/>
74
+ <text x="750" y="185" class="message-text">HealthStatus</text>
75
+
76
+ <path d="M 420 400 L 570 140" class="response-arrow"/>
77
+ <text x="470" y="290" class="message-text">HealthStatus</text>
78
+
79
+ <path d="M 780 400 L 630 140" class="response-arrow"/>
80
+ <text x="730" y="290" class="message-text">HealthStatus</text>
81
+
82
+ <!-- Emergency Communications (Red arrows) -->
83
+
84
+ <!-- Bank Silent Alarm -->
85
+ <path d="M 360 400 L 220 280" class="emergency-arrow"/>
86
+ <text x="250" y="340" class="message-text">SilentAlarm</text>
87
+
88
+ <!-- Police Dispatch Response -->
89
+ <path d="M 220 280 L 360 400" class="emergency-arrow"/>
90
+ <text x="250" y="360" class="message-text">PoliceDispatch</text>
91
+
92
+ <!-- House Fire Emergency -->
93
+ <path d="M 840 400 L 980 280" class="emergency-arrow"/>
94
+ <text x="950" y="340" class="message-text">FireEmergency</text>
95
+
96
+ <!-- Fire Dispatch Response -->
97
+ <path d="M 980 280 L 840 400" class="emergency-arrow"/>
98
+ <text x="950" y="360" class="message-text">FireDispatch</text>
99
+
100
+ <!-- Emergency Resolution (Green arrows) -->
101
+ <path d="M 300 440 L 500 140" class="message-arrow"/>
102
+ <text x="350" y="320" class="message-text">EmergencyResolved</text>
103
+
104
+ <path d="M 900 440 L 700 140" class="message-arrow"/>
105
+ <text x="850" y="320" class="message-text">EmergencyResolved</text>
106
+
107
+ <!-- Legend -->
108
+ <rect x="50" y="600" width="400" height="150" fill="#f9f9f9" stroke="#ccc" stroke-width="1" rx="5"/>
109
+ <text x="60" y="620" class="legend-text" font-weight="bold">Message Types:</text>
110
+
111
+ <line x1="60" y1="635" x2="90" y2="635" class="health-arrow"/>
112
+ <text x="100" y="640" class="legend-text">HealthCheck - Broadcast every 5 seconds</text>
113
+
114
+ <line x1="60" y1="655" x2="90" y2="655" class="response-arrow"/>
115
+ <text x="100" y="660" class="legend-text">HealthStatus - Response with status (healthy/warning/critical/failed)</text>
116
+
117
+ <line x1="60" y1="675" x2="90" y2="675" class="emergency-arrow"/>
118
+ <text x="100" y="680" class="legend-text">Emergency Messages - SilentAlarm, FireEmergency, Dispatch responses</text>
119
+
120
+ <line x1="60" y1="695" x2="90" y2="695" class="message-arrow"/>
121
+ <text x="100" y="700" class="legend-text">EmergencyResolved - Services report when emergency is handled</text>
122
+
123
+ <text x="60" y="725" class="legend-text" font-weight="bold">Status Colors (health_department output):</text>
124
+ <text x="60" y="740" class="legend-text">• Green: healthy • Yellow: warning • Orange: critical • Red: failed</text>
125
+ </svg>
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+ # examples/multi_program_demo/common/health_monitor.rb
3
+ # A common module used for system health monitoring
4
+ #
5
+ # Any class that inclues this module MUST define a method named get_status_details
6
+ # which is works like this:
7
+ #
8
+ # def get_status_details
9
+ # # calculate @status and @details
10
+ # [@status, @details]
11
+ # end
12
+ #
13
+ # The class MUST also have an instance variable @service_name
14
+ #
15
+
16
+ require_relative '../messages/health_check_message'
17
+ require_relative '../messages/health_status_message'
18
+
19
+ module Common
20
+ module HealthMonitor
21
+ FAIL_SAFE = 15 # seconds
22
+
23
+ def setup_health_monitor
24
+ @health_timer_mutex = Mutex.new
25
+ @health_timer = nil
26
+
27
+ Messages::HealthCheckMessage.subscribe(broadcast: true) do |message|
28
+ respond_to_health_check(message)
29
+ end
30
+
31
+ Messages::HealthStatusMessage.from = @service_name
32
+
33
+ start_health_countdown_timer
34
+ end
35
+
36
+ def start_health_countdown_timer
37
+ @health_timer_mutex.synchronize do
38
+ @health_timer&.kill # Kill existing timer if any
39
+ @health_timer = Thread.new do
40
+ sleep(FAIL_SAFE)
41
+ shutdown_due_to_health_failure
42
+ end
43
+ end
44
+ end
45
+
46
+ def reset_health_timer
47
+ start_health_countdown_timer
48
+ end
49
+
50
+ def shutdown_due_to_health_failure
51
+ emoji = respond_to?(:service_emoji) ? service_emoji : "🔧"
52
+ warning_message = "⚠️ WARNING: No health checks received for over #{FAIL_SAFE} seconds!"
53
+ puts "\n#{warning_message}"
54
+ puts "#{emoji} #{self.class.name} services are going offline..."
55
+ @logger.fatal(warning_message)
56
+ @logger.fatal("#{self.class.name} shutting down - no health checks received")
57
+ exit(1)
58
+ end
59
+
60
+ def respond_to_health_check(health_check)
61
+ reset_health_timer
62
+
63
+ status, details = get_status_details
64
+
65
+ status_msg = Messages::HealthStatusMessage.new(
66
+ service_name: @service_name,
67
+ status: status,
68
+ check_id: health_check.check_id,
69
+ details: details
70
+ )
71
+
72
+ status_msg.publish
73
+ @logger.info("Sent health status: #{status} (#{details})")
74
+ rescue => e
75
+ emoji = respond_to?(:service_emoji) ? service_emoji : "🔧"
76
+ puts "#{emoji} Error responding to health check: #{e.message}"
77
+ @logger.error("Error responding to health check: #{e.message}")
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+ # examples/multi_program_demo/common/logger.rb
3
+
4
+ module Common
5
+ module Logger
6
+ def setup_logger(options = {})
7
+ # Auto-detect program name from filename if not provided
8
+ program_name = options.delete(:name) || File.basename($0, '.rb')
9
+
10
+ # Build options with defaults
11
+ opts = {
12
+ log_file: "log/#{program_name}.log",
13
+ level: ::Logger::INFO
14
+ }.merge(options)
15
+
16
+ # Configure SmartMessage with the logger
17
+ SmartMessage.configure do |config|
18
+ config.logger = SmartMessage::Logger::Default.new(**opts)
19
+ end
20
+
21
+ # Store and return the logger instance
22
+ @logger = SmartMessage::Logger.default
23
+ end
24
+
25
+ def logger
26
+ # Return existing logger or create with defaults
27
+ @logger ||= setup_logger
28
+ end
29
+ end
30
+ end