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.
- checksums.yaml +4 -4
- data/.github/workflows/deploy-github-pages.yml +38 -0
- data/.gitignore +5 -0
- data/CHANGELOG.md +30 -0
- data/Gemfile.lock +35 -4
- data/README.md +169 -71
- data/Rakefile +29 -4
- data/docs/assets/images/ddq_architecture.svg +130 -0
- data/docs/assets/images/dlq_architecture.svg +115 -0
- data/docs/assets/images/enhanced-dual-publishing.svg +136 -0
- data/docs/assets/images/enhanced-fluent-api.svg +149 -0
- data/docs/assets/images/enhanced-microservices-routing.svg +115 -0
- data/docs/assets/images/enhanced-pattern-matching.svg +107 -0
- data/docs/assets/images/fluent-api-demo.svg +59 -0
- data/docs/assets/images/performance-comparison.svg +161 -0
- data/docs/assets/images/redis-basic-architecture.svg +53 -0
- data/docs/assets/images/redis-enhanced-architecture.svg +88 -0
- data/docs/assets/images/redis-queue-architecture.svg +101 -0
- data/docs/assets/images/smart_message.jpg +0 -0
- data/docs/assets/images/smart_message_walking.jpg +0 -0
- data/docs/assets/images/smartmessage_architecture_overview.svg +173 -0
- data/docs/assets/images/transport-comparison-matrix.svg +171 -0
- data/docs/assets/javascripts/mathjax.js +17 -0
- data/docs/assets/stylesheets/extra.css +51 -0
- data/docs/{addressing.md → core-concepts/addressing.md} +5 -7
- data/docs/{architecture.md → core-concepts/architecture.md} +78 -138
- data/docs/{dispatcher.md → core-concepts/dispatcher.md} +21 -21
- data/docs/{message_filtering.md → core-concepts/message-filtering.md} +2 -3
- data/docs/{message_processing.md → core-concepts/message-processing.md} +17 -17
- data/docs/{troubleshooting.md → development/troubleshooting.md} +7 -7
- data/docs/{examples.md → getting-started/examples.md} +115 -89
- data/docs/{getting-started.md → getting-started/quick-start.md} +47 -18
- data/docs/guides/redis-queue-getting-started.md +697 -0
- data/docs/guides/redis-queue-patterns.md +889 -0
- data/docs/guides/redis-queue-production.md +1091 -0
- data/docs/index.md +64 -0
- data/docs/{dead_letter_queue.md → reference/dead-letter-queue.md} +2 -3
- data/docs/{logging.md → reference/logging.md} +1 -1
- data/docs/{message_deduplication.md → reference/message-deduplication.md} +1 -0
- data/docs/{proc_handlers_summary.md → reference/proc-handlers.md} +7 -6
- data/docs/{serializers.md → reference/serializers.md} +3 -5
- data/docs/{transports.md → reference/transports.md} +133 -11
- data/docs/transports/memory-transport.md +374 -0
- data/docs/transports/redis-enhanced-transport.md +524 -0
- data/docs/transports/redis-queue-transport.md +1304 -0
- data/docs/transports/redis-transport-comparison.md +496 -0
- data/docs/transports/redis-transport.md +509 -0
- data/examples/README.md +98 -5
- data/examples/city_scenario/911_emergency_call_flow.svg +99 -0
- data/examples/city_scenario/README.md +515 -0
- data/examples/city_scenario/ai_visitor_intelligence_flow.svg +108 -0
- data/examples/city_scenario/citizen.rb +195 -0
- data/examples/city_scenario/city_diagram.svg +125 -0
- data/examples/city_scenario/common/health_monitor.rb +80 -0
- data/examples/city_scenario/common/logger.rb +30 -0
- data/examples/city_scenario/emergency_dispatch_center.rb +270 -0
- data/examples/city_scenario/fire_department.rb +446 -0
- data/examples/city_scenario/fire_emergency_flow.svg +95 -0
- data/examples/city_scenario/health_department.rb +100 -0
- data/examples/city_scenario/health_monitoring_system.svg +130 -0
- data/examples/city_scenario/house.rb +244 -0
- data/examples/city_scenario/local_bank.rb +217 -0
- data/examples/city_scenario/messages/emergency_911_message.rb +81 -0
- data/examples/city_scenario/messages/emergency_resolved_message.rb +43 -0
- data/examples/city_scenario/messages/fire_dispatch_message.rb +43 -0
- data/examples/city_scenario/messages/fire_emergency_message.rb +45 -0
- data/examples/city_scenario/messages/health_check_message.rb +22 -0
- data/examples/city_scenario/messages/health_status_message.rb +35 -0
- data/examples/city_scenario/messages/police_dispatch_message.rb +46 -0
- data/examples/city_scenario/messages/silent_alarm_message.rb +38 -0
- data/examples/city_scenario/police_department.rb +316 -0
- data/examples/city_scenario/redis_monitor.rb +129 -0
- data/examples/city_scenario/redis_stats.rb +743 -0
- data/examples/city_scenario/room_for_improvement.md +240 -0
- data/examples/city_scenario/security_emergency_flow.svg +95 -0
- data/examples/city_scenario/service_internal_architecture.svg +154 -0
- data/examples/city_scenario/smart_message_ai_agent.rb +364 -0
- data/examples/city_scenario/start_demo.sh +236 -0
- data/examples/city_scenario/stop_demo.sh +106 -0
- data/examples/city_scenario/visitor.rb +631 -0
- data/examples/{10_message_deduplication.rb → memory/01_message_deduplication_demo.rb} +1 -1
- data/examples/{09_dead_letter_queue_demo.rb → memory/02_dead_letter_queue_demo.rb} +13 -40
- data/examples/{01_point_to_point_orders.rb → memory/03_point_to_point_orders.rb} +1 -1
- data/examples/{02_publish_subscribe_events.rb → memory/04_publish_subscribe_events.rb} +2 -2
- data/examples/{03_many_to_many_chat.rb → memory/05_many_to_many_chat.rb} +4 -4
- data/examples/{show_me.rb → memory/06_pretty_print_demo.rb} +1 -1
- data/examples/{05_proc_handlers.rb → memory/07_proc_handlers_demo.rb} +2 -2
- data/examples/{06_custom_logger_example.rb → memory/08_custom_logger_demo.rb} +17 -14
- data/examples/{07_error_handling_scenarios.rb → memory/09_error_handling_demo.rb} +4 -4
- data/examples/{08_entity_addressing_basic.rb → memory/10_entity_addressing_basic.rb} +8 -8
- data/examples/{08_entity_addressing_with_filtering.rb → memory/11_entity_addressing_with_filtering.rb} +6 -6
- data/examples/{09_regex_filtering_microservices.rb → memory/12_regex_filtering_microservices.rb} +2 -2
- data/examples/{10_header_block_configuration.rb → memory/13_header_block_configuration.rb} +6 -6
- data/examples/{11_global_configuration_example.rb → memory/14_global_configuration_demo.rb} +19 -8
- data/examples/{show_logger.rb → memory/15_logger_demo.rb} +1 -1
- data/examples/memory/README.md +163 -0
- data/examples/memory/memory_transport_architecture.svg +90 -0
- data/examples/memory/point_to_point_pattern.svg +94 -0
- data/examples/memory/publish_subscribe_pattern.svg +125 -0
- data/examples/{04_redis_smart_home_iot.rb → redis/01_smart_home_iot_demo.rb} +5 -5
- data/examples/redis/README.md +230 -0
- data/examples/redis/alert_system_flow.svg +127 -0
- data/examples/redis/dashboard_status_flow.svg +107 -0
- data/examples/redis/device_command_flow.svg +113 -0
- data/examples/redis/redis_transport_architecture.svg +115 -0
- data/examples/{smart_home_iot_dataflow.md → redis/smart_home_iot_dataflow.md} +4 -116
- data/examples/redis/smart_home_system_architecture.svg +133 -0
- data/examples/redis_enhanced/README.md +319 -0
- data/examples/redis_enhanced/enhanced_01_basic_patterns.rb +233 -0
- data/examples/redis_enhanced/enhanced_02_fluent_api.rb +331 -0
- data/examples/redis_enhanced/enhanced_03_dual_publishing.rb +281 -0
- data/examples/redis_enhanced/enhanced_04_advanced_routing.rb +419 -0
- data/examples/redis_queue/01_basic_messaging.rb +221 -0
- data/examples/redis_queue/01_comprehensive_examples.rb +508 -0
- data/examples/redis_queue/02_pattern_routing.rb +405 -0
- data/examples/redis_queue/03_fluent_api.rb +422 -0
- data/examples/redis_queue/04_load_balancing.rb +486 -0
- data/examples/redis_queue/05_microservices.rb +735 -0
- data/examples/redis_queue/06_emergency_alerts.rb +777 -0
- data/examples/redis_queue/07_queue_management.rb +587 -0
- data/examples/redis_queue/README.md +366 -0
- data/examples/redis_queue/enhanced_01_basic_patterns.rb +233 -0
- data/examples/redis_queue/enhanced_02_fluent_api.rb +331 -0
- data/examples/redis_queue/enhanced_03_dual_publishing.rb +281 -0
- data/examples/redis_queue/enhanced_04_advanced_routing.rb +419 -0
- data/examples/redis_queue/redis_queue_architecture.svg +148 -0
- data/ideas/README.md +41 -0
- data/ideas/agents.md +1001 -0
- data/ideas/database_transport.md +980 -0
- data/ideas/improvement.md +359 -0
- data/ideas/meshage.md +1788 -0
- data/ideas/message_discovery.md +178 -0
- data/ideas/message_schema.md +1381 -0
- data/lib/smart_message/.idea/.gitignore +8 -0
- data/lib/smart_message/.idea/markdown.xml +6 -0
- data/lib/smart_message/.idea/misc.xml +4 -0
- data/lib/smart_message/.idea/modules.xml +8 -0
- data/lib/smart_message/.idea/smart_message.iml +16 -0
- data/lib/smart_message/.idea/vcs.xml +6 -0
- data/lib/smart_message/addressing.rb +15 -0
- data/lib/smart_message/base.rb +0 -2
- data/lib/smart_message/configuration.rb +1 -1
- data/lib/smart_message/logger.rb +15 -4
- data/lib/smart_message/plugins.rb +5 -2
- data/lib/smart_message/serializer.rb +14 -0
- data/lib/smart_message/transport/redis_enhanced_transport.rb +399 -0
- data/lib/smart_message/transport/redis_queue_transport.rb +555 -0
- data/lib/smart_message/transport/registry.rb +1 -0
- data/lib/smart_message/transport.rb +34 -1
- data/lib/smart_message/version.rb +1 -1
- data/lib/smart_message.rb +5 -52
- data/mkdocs.yml +184 -0
- data/p2p_plan.md +326 -0
- data/p2p_roadmap.md +287 -0
- data/smart_message.gemspec +2 -0
- data/smart_message.svg +51 -0
- metadata +170 -44
- data/docs/README.md +0 -57
- data/examples/dead_letters.jsonl +0 -12
- data/examples/temp.txt +0 -94
- data/examples/tmux_chat/README.md +0 -283
- data/examples/tmux_chat/bot_agent.rb +0 -278
- data/examples/tmux_chat/human_agent.rb +0 -199
- data/examples/tmux_chat/room_monitor.rb +0 -160
- data/examples/tmux_chat/shared_chat_system.rb +0 -328
- data/examples/tmux_chat/start_chat_demo.sh +0 -190
- data/examples/tmux_chat/stop_chat_demo.sh +0 -22
- /data/docs/{properties.md → core-concepts/properties.md} +0 -0
- /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
|