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,130 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="900" height="600" viewBox="0 0 900 600" xmlns="http://www.w3.org/2000/svg">
3
+ <defs>
4
+ <style>
5
+ .bg { fill: transparent; }
6
+ .health { fill: #1a3a2a; stroke: #4aff4a; stroke-width: 2; rx: 8; }
7
+ .fire { fill: #4a2a1a; stroke: #ffaa4a; stroke-width: 2; rx: 8; }
8
+ .police { fill: #1a2a3a; stroke: #4aafff; stroke-width: 2; rx: 8; }
9
+ .bank { fill: #3a2a1a; stroke: #ffcc4a; stroke-width: 2; rx: 8; }
10
+ .house { fill: #2a1a3a; stroke: #aa4aff; stroke-width: 2; rx: 8; }
11
+ .check-msg { stroke: #4aff4a; stroke-width: 2; fill: none; marker-end: url(#arrowhead-green); }
12
+ .status-msg { stroke: #ffaa4a; stroke-width: 2; fill: none; marker-end: url(#arrowhead-orange); stroke-dasharray: 5,3; }
13
+ .text { fill: #ffffff; font-family: 'Arial', sans-serif; font-size: 11px; }
14
+ .title { fill: #4a9eff; font-family: 'Arial', sans-serif; font-size: 18px; font-weight: bold; }
15
+ .subtitle { fill: #ffaa4a; font-family: 'Arial', sans-serif; font-size: 11px; }
16
+ .note { fill: #aaaaaa; font-family: 'Arial', sans-serif; font-size: 9px; }
17
+ </style>
18
+ <marker id="arrowhead-green" markerWidth="8" markerHeight="6"
19
+ refX="8" refY="3" orient="auto">
20
+ <polygon points="0 0, 8 3, 0 6" fill="#4aff4a" />
21
+ </marker>
22
+ <marker id="arrowhead-orange" markerWidth="8" markerHeight="6"
23
+ refX="8" refY="3" orient="auto">
24
+ <polygon points="0 0, 8 3, 0 6" fill="#ffaa4a" />
25
+ </marker>
26
+ </defs>
27
+
28
+ <!-- Background -->
29
+ <rect class="bg" width="900" height="600"/>
30
+
31
+ <!-- Title -->
32
+ <text x="450" y="25" text-anchor="middle" class="title">Health Monitoring System</text>
33
+ <text x="450" y="45" text-anchor="middle" class="subtitle">COVID-19 Compliant Service Health Checks (Every 5 seconds)</text>
34
+
35
+ <!-- Participants -->
36
+ <rect x="50" y="80" width="120" height="80" class="health"/>
37
+ <text x="110" y="105" text-anchor="middle" class="text">🏥 Health</text>
38
+ <text x="110" y="120" text-anchor="middle" class="text">Department</text>
39
+ <text x="110" y="140" text-anchor="middle" class="subtitle">Central Monitor</text>
40
+ <text x="110" y="155" text-anchor="middle" class="subtitle">COVID-19 Compliance</text>
41
+
42
+ <rect x="240" y="80" width="120" height="80" class="fire"/>
43
+ <text x="300" y="105" text-anchor="middle" class="text">🚒 Fire</text>
44
+ <text x="300" y="120" text-anchor="middle" class="text">Department</text>
45
+ <text x="300" y="140" text-anchor="middle" class="subtitle">Emergency Response</text>
46
+
47
+ <rect x="430" y="80" width="120" height="80" class="police"/>
48
+ <text x="490" y="105" text-anchor="middle" class="text">👮 Police</text>
49
+ <text x="490" y="120" text-anchor="middle" class="text">Department</text>
50
+ <text x="490" y="140" text-anchor="middle" class="subtitle">Law Enforcement</text>
51
+
52
+ <rect x="620" y="80" width="120" height="80" class="bank"/>
53
+ <text x="680" y="105" text-anchor="middle" class="text">🏦 Local</text>
54
+ <text x="680" y="120" text-anchor="middle" class="text">Bank</text>
55
+ <text x="680" y="140" text-anchor="middle" class="subtitle">Financial Security</text>
56
+
57
+ <rect x="810" y="80" width="80" height="80" class="house"/>
58
+ <text x="850" y="105" text-anchor="middle" class="text">🏠 House</text>
59
+ <text x="850" y="125" text-anchor="middle" class="subtitle">Residential</text>
60
+ <text x="850" y="140" text-anchor="middle" class="subtitle">Safety</text>
61
+
62
+ <!-- Vertical lifelines -->
63
+ <line x1="110" y1="160" x2="110" y2="520" stroke="#666" stroke-width="2" stroke-dasharray="3,3"/>
64
+ <line x1="300" y1="160" x2="300" y2="520" stroke="#666" stroke-width="2" stroke-dasharray="3,3"/>
65
+ <line x1="490" y1="160" x2="490" y2="520" stroke="#666" stroke-width="2" stroke-dasharray="3,3"/>
66
+ <line x1="680" y1="160" x2="680" y2="520" stroke="#666" stroke-width="2" stroke-dasharray="3,3"/>
67
+ <line x1="850" y1="160" x2="850" y2="520" stroke="#666" stroke-width="2" stroke-dasharray="3,3"/>
68
+
69
+ <!-- Health check broadcast note -->
70
+ <rect x="50" y="180" width="120" height="30" fill="#1a3a2a" stroke="#4aff4a" rx="4"/>
71
+ <text x="110" y="200" text-anchor="middle" class="note">Every 5 seconds</text>
72
+
73
+ <!-- Health check messages (broadcast to all) -->
74
+ <path d="M 110 220 L 300 220" class="check-msg"/>
75
+ <path d="M 110 240 L 490 240" class="check-msg"/>
76
+ <path d="M 110 260 L 680 260" class="check-msg"/>
77
+ <path d="M 110 280 L 850 280" class="check-msg"/>
78
+
79
+ <text x="205" y="215" text-anchor="middle" class="text">HealthCheckMessage</text>
80
+ <text x="300" y="235" text-anchor="middle" class="text">HealthCheckMessage</text>
81
+ <text x="395" y="255" text-anchor="middle" class="text">HealthCheckMessage</text>
82
+ <text x="480" y="275" text-anchor="middle" class="text">HealthCheckMessage</text>
83
+
84
+ <!-- Health status responses -->
85
+ <path d="M 300 320 L 110 320" class="status-msg"/>
86
+ <path d="M 490 340 L 110 340" class="status-msg"/>
87
+ <path d="M 680 360 L 110 360" class="status-msg"/>
88
+ <path d="M 850 380 L 110 380" class="status-msg"/>
89
+
90
+ <text x="205" y="315" text-anchor="middle" class="text">HealthStatusMessage</text>
91
+ <text x="300" y="335" text-anchor="middle" class="text">HealthStatusMessage</text>
92
+ <text x="395" y="355" text-anchor="middle" class="text">HealthStatusMessage</text>
93
+ <text x="480" y="375" text-anchor="middle" class="text">HealthStatusMessage</text>
94
+
95
+ <!-- Status indicators -->
96
+ <circle cx="300" cy="310" r="6" fill="#4aff4a"/>
97
+ <text x="320" y="315" class="note">Green</text>
98
+
99
+ <circle cx="490" cy="330" r="6" fill="#ffff4a"/>
100
+ <text x="510" y="335" class="note">Yellow</text>
101
+
102
+ <circle cx="680" cy="350" r="6" fill="#4aff4a"/>
103
+ <text x="700" y="355" class="note">Green</text>
104
+
105
+ <circle cx="850" cy="370" r="6" fill="#ff4a4a"/>
106
+ <text x="820" y="375" class="note">Red</text>
107
+
108
+ <!-- Countdown timer notes -->
109
+ <rect x="200" y="420" width="500" height="60" fill="#1a1a1a" stroke="#ffaa4a" rx="6"/>
110
+ <text x="210" y="440" class="text">10-second Countdown Timer System:</text>
111
+ <text x="210" y="455" class="note">• Resets on each HealthCheckMessage received</text>
112
+ <text x="210" y="470" class="note">• Services shut down after 10 seconds without health check (COVID-19 protocol)</text>
113
+ <text x="210" y="485" class="note">• Status: Green (healthy), Yellow (warning), Red (critical/offline)</text>
114
+
115
+ <!-- Service status legend -->
116
+ <rect x="50" y="500" width="840" height="80" fill="#2a2a2a" stroke="#4a9eff" rx="6"/>
117
+ <text x="70" y="520" class="title">Service Health Status Indicators:</text>
118
+
119
+ <circle cx="90" cy="540" r="8" fill="#4aff4a"/>
120
+ <text x="110" y="545" class="text">Green: Service healthy and responsive</text>
121
+
122
+ <circle cx="320" cy="540" r="8" fill="#ffff4a"/>
123
+ <text x="340" y="545" class="text">Yellow: Service degraded or slow response</text>
124
+
125
+ <circle cx="580" cy="540" r="8" fill="#ff4a4a"/>
126
+ <text x="600" y="545" class="text">Red: Service critical or unresponsive</text>
127
+
128
+ <text x="70" y="565" class="text">All services implement countdown timer health monitoring for COVID-19 compliance</text>
129
+ <text x="70" y="580" class="text">Health Department broadcasts HealthCheckMessage every 5 seconds to maintain service operation</text>
130
+ </svg>
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env ruby
2
+ # examples/multi_program_demo/house.rb
3
+
4
+ require_relative '../../lib/smart_message'
5
+ require_relative 'messages/fire_emergency_message'
6
+ require_relative 'messages/fire_dispatch_message'
7
+
8
+ require_relative 'common/health_monitor'
9
+ require_relative 'common/logger'
10
+
11
+ class House
12
+ include Common::HealthMonitor
13
+ include Common::Logger
14
+
15
+ def initialize(address = nil)
16
+ @address = address || generate_random_address
17
+ @service_name = "house-#{@address.gsub(/\s+/, '-').downcase}"
18
+ @status = 'healthy'
19
+ @start_time = Time.now
20
+ @fire_active = false
21
+ @last_fire_time = nil
22
+ @occupants = rand(1..4)
23
+ @occupant_status = 'safe'
24
+
25
+ setup_messaging
26
+ setup_signal_handlers
27
+ setup_health_monitor
28
+ end
29
+
30
+ # def setup_logging
31
+ # # Create log file name based on address (sanitized)
32
+ # address_slug = @address.gsub(/\s+/, '_').gsub(/[^\w\-_]/, '').downcase
33
+ # log_file = File.join(__dir__, "house_#{address_slug}.log")
34
+ # logger = Logger.new(log_file)
35
+ # logger.level = Logger::INFO
36
+ # logger.formatter = proc do |severity, datetime, progname, msg|
37
+ # "#{datetime.strftime('%Y-%m-%d %H:%M:%S')} [#{severity}] #{msg}\n"
38
+ # end
39
+ # logger.info("House at #{@address} logging started")
40
+ # end
41
+
42
+ def setup_messaging
43
+ Messages::FireEmergencyMessage.from = @service_name
44
+
45
+ # Subscribe to fire dispatch responses
46
+ Messages::FireDispatchMessage.subscribe(to: @service_name) do |message|
47
+ handle_fire_response(message)
48
+ end
49
+
50
+ address_slug = @address.gsub(/\s+/, '_').gsub(/[^\w\-_]/, '').downcase
51
+ puts "🏠 House at #{@address} monitoring systems active"
52
+ puts " Occupants: #{@occupants}"
53
+ puts " Status: #{@occupant_status}"
54
+ puts " Press Ctrl+C to shutdown monitoring\n\n"
55
+ logger.info("House monitoring started: #{@occupants} occupants, status: #{@occupant_status}")
56
+ end
57
+
58
+ def setup_signal_handlers
59
+ %w[INT TERM].each do |signal|
60
+ Signal.trap(signal) do
61
+ puts "\n🏠 #{@address} monitoring system shutting down..."
62
+ logger.info("House monitoring system shutting down")
63
+ exit(0)
64
+ end
65
+ end
66
+ end
67
+
68
+
69
+ def start_monitoring
70
+ loop do
71
+ simulate_house_activity
72
+ sleep(rand(15..45)) # Random events every 15-45 seconds
73
+ end
74
+ rescue => e
75
+ puts "🏠 Error in house monitoring: #{e.message}"
76
+ logger.error("Error in house monitoring: #{e.message}")
77
+ retry
78
+ end
79
+
80
+ private
81
+
82
+ def service_emoji
83
+ "🏠"
84
+ end
85
+
86
+ def generate_random_address
87
+ street_numbers = (100..999).to_a
88
+ street_names = [
89
+ 'Oak Street', 'Maple Avenue', 'Pine Lane', 'Cedar Drive', 'Elm Court',
90
+ 'Birch Road', 'Willow Way', 'Ash Boulevard', 'Cherry Street', 'Poplar Lane'
91
+ ]
92
+ "#{street_numbers.sample} #{street_names.sample}"
93
+ end
94
+
95
+ def get_status_details
96
+ # Status depends on fire situation and occupant safety
97
+ @status = if @fire_active
98
+ 'critical'
99
+ elsif @occupant_status.include?('trapped') || @occupant_status.include?('rescued')
100
+ 'warning'
101
+ else
102
+ 'healthy'
103
+ end
104
+
105
+ details = case @status
106
+ when 'healthy' then "All systems normal, #{@occupants} occupants #{@occupant_status}"
107
+ when 'warning' then "Emergency response active, #{@occupants} occupants #{@occupant_status}"
108
+ when 'critical' then "FIRE DETECTED - #{@occupants} occupants status: #{@occupant_status}"
109
+ when 'failed' then "Power outage, backup systems failed"
110
+ end
111
+
112
+ [@status, details]
113
+ end
114
+
115
+ def simulate_house_activity
116
+ # Only start fires occasionally and not too frequently
117
+ return if @fire_active
118
+ return if @last_fire_time && (Time.now - @last_fire_time) < 600 # 10 minutes minimum between fires
119
+
120
+ # 6% chance of fire
121
+ if rand(100) < 6
122
+ start_fire
123
+ else
124
+ # Normal house activities
125
+ activities = [
126
+ 'Security system armed',
127
+ 'Temperature adjusted',
128
+ 'Motion detected - normal activity',
129
+ 'Smoke detector test completed',
130
+ 'Door/window sensor check',
131
+ 'All systems operational'
132
+ ]
133
+ activity = activities.sample
134
+ puts "🏠 #{activity}"
135
+ logger.info("Normal activity: #{activity}")
136
+ end
137
+ end
138
+
139
+ def start_fire
140
+ @fire_active = true
141
+ @last_fire_time = Time.now
142
+
143
+ fire_types = ['kitchen', 'electrical', 'basement', 'garage']
144
+ severities = ['small', 'medium', 'large']
145
+
146
+ # Garage fires tend to be more severe
147
+ fire_type = fire_types.sample
148
+ severity = if fire_type == 'garage'
149
+ ['medium', 'large', 'out_of_control'].sample
150
+ else
151
+ severities.sample
152
+ end
153
+
154
+ # Determine occupant status based on fire severity and time of day
155
+ hour = Time.now.hour
156
+ if severity == 'out_of_control' || (hour >= 22 || hour <= 6) # Night time
157
+ @occupant_status = ['safe - evacuated', 'trapped - need rescue'].sample
158
+ else
159
+ @occupant_status = 'safe - evacuated'
160
+ end
161
+
162
+ # Determine spread risk
163
+ spread_risk = case severity
164
+ when 'small' then 'Low risk to neighboring structures'
165
+ when 'medium' then 'Moderate risk if not contained quickly'
166
+ when 'large' then 'High risk to adjacent buildings'
167
+ when 'out_of_control' then 'EXTREME RISK - evacuate neighbors'
168
+ end
169
+
170
+ emergency = Messages::FireEmergencyMessage.new(
171
+ house_address: @address,
172
+ fire_type: fire_type,
173
+ severity: severity,
174
+ timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S'),
175
+ occupants_status: @occupant_status,
176
+ spread_risk: spread_risk,
177
+ )
178
+ emergency.publish
179
+
180
+ puts "🏠 🔥 FIRE EMERGENCY 🔥"
181
+ puts " Address: #{@address}"
182
+ puts " Type: #{fire_type.upcase}"
183
+ puts " Severity: #{severity.upcase}"
184
+ puts " Occupants: #{@occupant_status}"
185
+ puts " Spread Risk: #{spread_risk}"
186
+ logger.warn("FIRE EMERGENCY: #{fire_type} fire (#{severity}) - Occupants: #{@occupant_status}")
187
+ rescue => e
188
+ puts "🏠 Error starting fire emergency: #{e.message}"
189
+ logger.error("Error starting fire emergency: #{e.message}")
190
+ end
191
+
192
+ def handle_fire_response(dispatch)
193
+ # Process fire dispatch message
194
+ puts "🚒 \e[31mFIRE DISPATCH\e[0m ##{dispatch.dispatch_id}"
195
+ puts " Engines: #{dispatch.engines_assigned.join(', ')}"
196
+ puts " Location: #{dispatch.location}"
197
+ puts " Fire Type: #{dispatch.fire_type}"
198
+ puts " Equipment: #{dispatch.equipment_needed}" if dispatch.equipment_needed
199
+ puts " ETA: #{dispatch.estimated_arrival}" if dispatch.estimated_arrival
200
+ puts " Dispatched: #{dispatch.timestamp}"
201
+
202
+ puts "🏠 Fire department response received"
203
+ puts " #{dispatch.engines_assigned.size} engines dispatched"
204
+ puts " ETA: #{dispatch.estimated_arrival}"
205
+ puts " Equipment: #{dispatch.equipment_needed}"
206
+ logger.info("Fire department response: #{dispatch.engines_assigned.join(', ')} dispatched, ETA #{dispatch.estimated_arrival}")
207
+
208
+ # If occupants were trapped, fire department rescues them
209
+ if @occupant_status.include?('trapped')
210
+ @occupant_status = 'rescued by fire department'
211
+ puts "🏠 🚒 Occupants successfully rescued!"
212
+ logger.info("Occupants rescued by fire department")
213
+ end
214
+
215
+ # Simulate fire resolution when fire department arrives
216
+ Thread.new do
217
+ sleep(rand(300..900)) # 5-15 minutes for fire suppression
218
+ extinguish_fire
219
+ end
220
+ rescue => e
221
+ puts "🏠 Error handling fire response: #{e.message}"
222
+ logger.error("Error handling fire response: #{e.message}")
223
+ end
224
+
225
+ def extinguish_fire
226
+ @fire_active = false
227
+ @occupant_status = 'safe'
228
+
229
+ puts "🏠 ✅ Fire extinguished by fire department"
230
+ puts " All occupants accounted for and safe"
231
+ puts " House systems returning to normal"
232
+ logger.info("Fire extinguished, all occupants safe, returning to normal")
233
+ rescue => e
234
+ puts "🏠 Error extinguishing fire: #{e.message}"
235
+ logger.error("Error extinguishing fire: #{e.message}")
236
+ end
237
+ end
238
+
239
+ if __FILE__ == $0
240
+ # Allow specifying address as command line argument
241
+ address = ARGV[0]
242
+ house = House.new(address)
243
+ house.start_monitoring
244
+ end
@@ -0,0 +1,217 @@
1
+ #!/usr/bin/env ruby
2
+ # examples/multi_program_demo/local_bank.rb
3
+
4
+ require_relative '../../lib/smart_message'
5
+ require_relative 'messages/health_check_message'
6
+ require_relative 'messages/health_status_message'
7
+ require_relative 'messages/silent_alarm_message'
8
+ require_relative 'messages/police_dispatch_message'
9
+
10
+ require_relative 'common/health_monitor'
11
+ require_relative 'common/logger'
12
+
13
+ class LocalBank
14
+ include Common::HealthMonitor
15
+ include Common::Logger
16
+
17
+ def initialize
18
+ @service_name = 'first-national-bank'
19
+ @location = '123 Main Street'
20
+ @status = 'healthy'
21
+ @start_time = Time.now
22
+ @alarm_active = false
23
+ @last_alarm_time = nil
24
+ @security_level = 'normal'
25
+
26
+ setup_messaging
27
+ setup_signal_handlers
28
+ setup_health_monitor
29
+ end
30
+
31
+ # def setup_logging
32
+ # log_file = File.join(__dir__, 'local_bank.log')
33
+ # logger = Logger.new(log_file)
34
+ # logger.level = Logger::INFO
35
+ # logger.formatter = proc do |severity, datetime, progname, msg|
36
+ # "#{datetime.strftime('%Y-%m-%d %H:%M:%S')} [#{severity}] #{msg}\n"
37
+ # end
38
+ # logger.info("Local Bank logging started")
39
+ # end
40
+
41
+ def setup_messaging
42
+ # Subscribe to police dispatch responses
43
+ Messages::PoliceDispatchMessage.subscribe(to: @service_name) do |message|
44
+ handle_police_response(message)
45
+ end
46
+
47
+ puts "🏦 #{@service_name} open for business"
48
+ puts " Location: #{@location}"
49
+ puts " Security level: #{@security_level}"
50
+ puts " Logging to: local_bank.log"
51
+ puts " Press Ctrl+C to close\n\n"
52
+ logger.info("#{@service_name} open for business at #{@location}")
53
+ end
54
+
55
+ def setup_signal_handlers
56
+ %w[INT TERM].each do |signal|
57
+ Signal.trap(signal) do
58
+ puts "\n🏦 #{@service_name} closing for the day..."
59
+ logger.info("#{@service_name} closing for the day")
60
+ exit(0)
61
+ end
62
+ end
63
+ end
64
+
65
+
66
+ def start_operations
67
+ loop do
68
+ simulate_bank_activity
69
+ sleep(rand(10..30)) # Random activities every 10-30 seconds
70
+ end
71
+ rescue => e
72
+ puts "🏦 Error in bank operations: #{e.message}"
73
+ logger.error("Error in bank operations: #{e.message}")
74
+ retry
75
+ end
76
+
77
+ private
78
+
79
+ def service_emoji
80
+ "🏦"
81
+ end
82
+
83
+ def get_status_details
84
+ # Determine status based on security level and alarm state
85
+ @status = if @alarm_active
86
+ 'critical'
87
+ elsif @security_level == 'high'
88
+ 'warning'
89
+ else
90
+ 'healthy'
91
+ end
92
+
93
+ details = case @status
94
+ when 'healthy' then "All systems operational, security level: #{@security_level}"
95
+ when 'warning' then "Elevated security, monitoring active"
96
+ when 'critical' then "Security breach detected, lockdown protocols active"
97
+ when 'failed' then "Systems offline, emergency procedures in effect"
98
+ end
99
+
100
+ [@status, details]
101
+ end
102
+
103
+ def simulate_bank_activity
104
+ # Only trigger alarms occasionally and not too frequently
105
+ return if @alarm_active
106
+ return if @last_alarm_time && (Time.now - @last_alarm_time) < 300 # 5 minutes minimum between alarms
107
+
108
+ # 8% chance of suspicious activity
109
+ if rand(100) < 8
110
+ trigger_silent_alarm
111
+ else
112
+ # Normal bank operations
113
+ activities = [
114
+ 'Customer transaction completed',
115
+ 'ATM refilled',
116
+ 'Vault inspection completed',
117
+ 'Security patrol completed',
118
+ 'System backup completed'
119
+ ]
120
+ activity = activities.sample
121
+ puts "🏦 #{activity}"
122
+ logger.info("Normal operation: #{activity}")
123
+ end
124
+ end
125
+
126
+ def trigger_silent_alarm
127
+ @alarm_active = true
128
+ @last_alarm_time = Time.now
129
+ @security_level = 'high'
130
+
131
+ alarm_types = ['robbery', 'vault_breach', 'suspicious_activity']
132
+ severities = ['medium', 'high', 'critical']
133
+
134
+ alarm_type = alarm_types.sample
135
+ severity = alarm_type == 'robbery' ? 'critical' : severities.sample
136
+
137
+ details = case alarm_type
138
+ when 'robbery'
139
+ 'Armed individuals at teller window, customers on floor'
140
+ when 'vault_breach'
141
+ 'Unauthorized access attempt detected in vault area'
142
+ when 'suspicious_activity'
143
+ 'Multiple individuals casing the building, unusual behavior'
144
+ end
145
+
146
+ alarm = Messages::SilentAlarmMessage.new(
147
+ bank_name: @service_name,
148
+ location: @location,
149
+ alarm_type: alarm_type,
150
+ timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S'),
151
+ severity: severity,
152
+ details: details
153
+ )
154
+ alarm._sm_from = @service_name
155
+ alarm._sm_to = 'police-department'
156
+ alarm.publish
157
+
158
+ puts "🏦 🚨 SILENT ALARM TRIGGERED 🚨"
159
+ puts " Type: #{alarm_type.upcase}"
160
+ puts " Severity: #{severity.upcase}"
161
+ puts " Details: #{details}"
162
+ logger.warn("SILENT ALARM TRIGGERED: #{alarm_type} (#{severity}) - #{details}")
163
+ rescue => e
164
+ puts "🏦 Error triggering silent alarm: #{e.message}"
165
+ logger.error("Error triggering silent alarm: #{e.message}")
166
+ end
167
+
168
+ def handle_police_response(dispatch)
169
+ # Process police dispatch message with colored output
170
+ priority_color = case dispatch.priority
171
+ when 'low' then "\e[32m" # Green
172
+ when 'medium' then "\e[33m" # Yellow
173
+ when 'high' then "\e[93m" # Orange
174
+ when 'emergency' then "\e[31m" # Red
175
+ else "\e[0m"
176
+ end
177
+
178
+ puts "🚔 #{priority_color}POLICE DISPATCH\e[0m ##{dispatch.dispatch_id}"
179
+ puts " Units: #{dispatch.units_assigned.join(', ')}"
180
+ puts " Location: #{dispatch.location}"
181
+ puts " Incident: #{dispatch.incident_type} (#{dispatch.priority.upcase} priority)"
182
+ puts " ETA: #{dispatch.estimated_arrival}" if dispatch.estimated_arrival
183
+ puts " Dispatched: #{dispatch.timestamp}"
184
+
185
+ puts "🏦 Police response received - #{dispatch.units_assigned.size} units dispatched"
186
+ puts " ETA: #{dispatch.estimated_arrival}"
187
+ puts " Implementing security protocols..."
188
+ logger.info("Police response received: #{dispatch.units_assigned.join(', ')} dispatched, ETA #{dispatch.estimated_arrival}")
189
+
190
+ # Simulate resolution after police arrive
191
+ Thread.new do
192
+ sleep(rand(180..600)) # 3-10 minutes for resolution
193
+ resolve_security_incident
194
+ end
195
+ rescue => e
196
+ puts "🏦 Error handling police response: #{e.message}"
197
+ logger.error("Error handling police response: #{e.message}")
198
+ end
199
+
200
+ def resolve_security_incident
201
+ @alarm_active = false
202
+ @security_level = 'normal'
203
+
204
+ puts "🏦 ✅ Security incident resolved"
205
+ puts " Returning to normal operations"
206
+ puts " Security level: #{@security_level}"
207
+ logger.info("Security incident resolved, returning to normal operations")
208
+ rescue => e
209
+ puts "🏦 Error resolving security incident: #{e.message}"
210
+ logger.error("Error resolving security incident: #{e.message}")
211
+ end
212
+ end
213
+
214
+ if __FILE__ == $0
215
+ bank = LocalBank.new
216
+ bank.start_operations
217
+ end
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+ # examples/messages/emergency_911_message.rb
3
+
4
+ require_relative '../../../lib/smart_message'
5
+
6
+ module Messages
7
+ class Emergency911Message < SmartMessage::Base
8
+ version 1
9
+
10
+ description 'Emergency 911 call for reporting fires, crimes, accidents, medical emergencies, or other urgent situations requiring police, fire, or medical response'
11
+
12
+ transport SmartMessage::Transport::RedisTransport.new
13
+ serializer SmartMessage::Serializer::Json.new
14
+
15
+ VALID_EMERGENCY_TYPES = %w[fire medical crime accident hazmat rescue other]
16
+ VALID_SEVERITY = %w[critical high medium low]
17
+
18
+ # Caller information
19
+ property :caller_name,
20
+ description: 'Name of the person calling 911'
21
+
22
+ property :caller_phone,
23
+ description: 'Phone number of the caller'
24
+
25
+ property :caller_location,
26
+ required: true,
27
+ description: 'Location of the emergency (address or description)'
28
+
29
+ property :emergency_type,
30
+ required: true,
31
+ validate: ->(v) { VALID_EMERGENCY_TYPES.include?(v) },
32
+ validation_message: "Emergency type must be: #{VALID_EMERGENCY_TYPES.join(', ')}",
33
+ description: "Type of emergency being reported. Valid values: #{VALID_EMERGENCY_TYPES.join(', ')}"
34
+
35
+ property :description,
36
+ required: true,
37
+ description: 'Detailed description of the emergency'
38
+
39
+ property :severity,
40
+ validate: ->(v) { VALID_SEVERITY.include?(v) },
41
+ validation_message: "Severity must be: #{VALID_SEVERITY.join(', ')}",
42
+ description: "Perceived severity of the emergency. Valid values: #{VALID_SEVERITY.join(', ')}"
43
+
44
+ property :injuries_reported,
45
+ description: 'Are there injuries? (true/false)'
46
+
47
+ property :number_of_victims,
48
+ description: 'Number of people affected or injured'
49
+
50
+ property :fire_involved,
51
+ description: 'Is there fire involved? (true/false)'
52
+
53
+ property :weapons_involved,
54
+ description: 'Are weapons involved? (true/false)'
55
+
56
+ property :hazardous_materials,
57
+ description: 'Are hazardous materials involved? (true/false)'
58
+
59
+ property :vehicles_involved,
60
+ description: 'Number of vehicles involved (for accidents)'
61
+
62
+ property :suspects_on_scene,
63
+ description: 'Are suspects still on scene? (true/false)'
64
+
65
+ property :additional_info,
66
+ description: 'Any additional information provided by caller'
67
+
68
+ property :dispatch_to,
69
+ description: 'Which departments to dispatch to (array of department names)'
70
+
71
+ property :priority,
72
+ description: 'Dispatch priority level (1-5, 1 being highest)'
73
+
74
+ property :call_id,
75
+ description: 'Unique identifier for this 911 call'
76
+
77
+ property :call_received_at,
78
+ default: -> { Time.now.iso8601 },
79
+ description: 'When the 911 call was received'
80
+ end
81
+ end