rsmp 0.1.0
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 +7 -0
- data/.gitignore +15 -0
- data/.gitmodules +3 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +101 -0
- data/LICENSE +7 -0
- data/README.md +204 -0
- data/Rakefile +6 -0
- data/bin/console +51 -0
- data/bin/setup +8 -0
- data/config/site.yaml +41 -0
- data/config/supervisor.yaml +33 -0
- data/exe/rsmp +4 -0
- data/lib/rsmp/alarm.rb +15 -0
- data/lib/rsmp/archive.rb +75 -0
- data/lib/rsmp/base.rb +26 -0
- data/lib/rsmp/cli.rb +52 -0
- data/lib/rsmp/component.rb +65 -0
- data/lib/rsmp/error.rb +44 -0
- data/lib/rsmp/logger.rb +153 -0
- data/lib/rsmp/message.rb +313 -0
- data/lib/rsmp/node.rb +53 -0
- data/lib/rsmp/probe.rb +104 -0
- data/lib/rsmp/probe_collection.rb +28 -0
- data/lib/rsmp/proxy.rb +508 -0
- data/lib/rsmp/rsmp.rb +31 -0
- data/lib/rsmp/site.rb +165 -0
- data/lib/rsmp/site_base.rb +26 -0
- data/lib/rsmp/site_proxy.rb +220 -0
- data/lib/rsmp/supervisor.rb +220 -0
- data/lib/rsmp/supervisor_base.rb +10 -0
- data/lib/rsmp/supervisor_proxy.rb +292 -0
- data/lib/rsmp/version.rb +3 -0
- data/lib/rsmp/wait.rb +17 -0
- data/lib/rsmp.rb +29 -0
- data/rsmp.gemspec +43 -0
- metadata +266 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
module RSMP
|
2
|
+
class Component
|
3
|
+
attr_reader :c_id, :alarms, :statuses, :aggregated_status, :aggregated_status_bools, :grouped
|
4
|
+
|
5
|
+
AGGREGATED_STATUS_KEYS = [ :local_control,
|
6
|
+
:communication_distruption,
|
7
|
+
:high_priority_alarm,
|
8
|
+
:medium_priority_alarm,
|
9
|
+
:low_priority_alarm,
|
10
|
+
:normal,
|
11
|
+
:rest,
|
12
|
+
:not_connected ]
|
13
|
+
|
14
|
+
def initialize node:, id:, grouped:
|
15
|
+
@c_id = id
|
16
|
+
@node = node
|
17
|
+
@grouped = grouped
|
18
|
+
@alarms = {}
|
19
|
+
@statuses = {}
|
20
|
+
clear_aggregated_status
|
21
|
+
end
|
22
|
+
|
23
|
+
def clear_aggregated_status
|
24
|
+
@aggregated_status = []
|
25
|
+
@aggregated_status_bools = Array.new(8,false)
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_aggregated_status status
|
29
|
+
status = [status] if status.is_a? Symbol
|
30
|
+
raise InvalidArgument unless status.is_a? Array
|
31
|
+
input = status & AGGREGATED_STATUS_KEYS
|
32
|
+
if input != @aggregated_status
|
33
|
+
AGGREGATED_STATUS_KEYS.each_with_index do |key,index|
|
34
|
+
@aggregated_status_bools[index] = status.include?(key)
|
35
|
+
end
|
36
|
+
aggrated_status_changed
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def set_aggregated_status_bools status
|
41
|
+
raise InvalidArgument unless status.is_a? Array
|
42
|
+
raise InvalidArgument unless status.size == 8
|
43
|
+
if status != @aggregated_status_bools
|
44
|
+
@aggregated_status = []
|
45
|
+
AGGREGATED_STATUS_KEYS.each_with_index do |key,index|
|
46
|
+
on = status[index] == true
|
47
|
+
@aggregated_status_bools[index] = on
|
48
|
+
@aggregated_status << key if on
|
49
|
+
end
|
50
|
+
aggrated_status_changed
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def aggrated_status_changed
|
55
|
+
@node.aggrated_status_changed self
|
56
|
+
end
|
57
|
+
|
58
|
+
def alarm code:, status:
|
59
|
+
end
|
60
|
+
|
61
|
+
def status code:, value:
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
data/lib/rsmp/error.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module RSMP
|
2
|
+
class Error < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class InvalidPacket < Error
|
6
|
+
end
|
7
|
+
|
8
|
+
class MalformedMessage < Error
|
9
|
+
end
|
10
|
+
|
11
|
+
class SchemaError < Error
|
12
|
+
end
|
13
|
+
|
14
|
+
class InvalidMessage < Error
|
15
|
+
end
|
16
|
+
|
17
|
+
class UnknownMessage < Error
|
18
|
+
end
|
19
|
+
|
20
|
+
class MissingAcknowledgment < Error
|
21
|
+
end
|
22
|
+
|
23
|
+
class MissingWatchdog < Error
|
24
|
+
end
|
25
|
+
|
26
|
+
class MissingAcknowledgment < Error
|
27
|
+
end
|
28
|
+
|
29
|
+
class MissingAttribute < InvalidMessage
|
30
|
+
end
|
31
|
+
|
32
|
+
class FatalError < Error
|
33
|
+
end
|
34
|
+
|
35
|
+
class NotReady < Error
|
36
|
+
end
|
37
|
+
|
38
|
+
class TimeoutError < Error
|
39
|
+
end
|
40
|
+
|
41
|
+
class ConnectionError < Error
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/lib/rsmp/logger.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
module RSMP
|
2
|
+
class Logger
|
3
|
+
|
4
|
+
def initialize settings
|
5
|
+
defaults = {
|
6
|
+
'active'=>false,
|
7
|
+
'author'=>false,
|
8
|
+
'color'=>true,
|
9
|
+
'site_id'=>true,
|
10
|
+
'component'=>false,
|
11
|
+
'level'=>false,
|
12
|
+
'ip'=>false,
|
13
|
+
'index'=>false,
|
14
|
+
'timestamp'=>true,
|
15
|
+
'json'=>false,
|
16
|
+
'debug'=>false,
|
17
|
+
'statistics'=>false
|
18
|
+
}
|
19
|
+
@settings = defaults.merge settings
|
20
|
+
@muted = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def mute ip, port
|
24
|
+
@muted["#{ip}:#{port}"] = true
|
25
|
+
end
|
26
|
+
|
27
|
+
def unmute ip, port
|
28
|
+
@muted.delete "#{ip}:#{port}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def unmute_all
|
32
|
+
@muted = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
def output? item, force=false
|
36
|
+
return false if item[:ip] && item[:port] && @muted["#{item[:ip]}:#{item[:port]}"]
|
37
|
+
return false if @settings["active"] == false && force != true
|
38
|
+
return false if @settings["info"] == false && item[:level] == :info
|
39
|
+
return false if @settings["debug"] != true && item[:level] == :debug
|
40
|
+
return false if @settings["statistics"] != true && item[:level] == :statistics
|
41
|
+
|
42
|
+
if item[:message]
|
43
|
+
type = item[:message].type
|
44
|
+
ack = type == "MessageAck" || type == "MessageNotAck"
|
45
|
+
if @settings["watchdogs"] == false
|
46
|
+
return false if type == "Watchdog"
|
47
|
+
if ack
|
48
|
+
return false if item[:message].original && item[:message].original.type == "Watchdog"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
return false if ack && @settings["acknowledgements"] == false &&
|
52
|
+
[:not_acknowledged,:warning,:error].include?(item[:level]) == false
|
53
|
+
end
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
def output level, str
|
58
|
+
return if str.empty? || /^\s+$/.match(str)
|
59
|
+
streams = [$stdout]
|
60
|
+
#streams << $stderr if level == :error
|
61
|
+
str = colorize level, str
|
62
|
+
streams.each do |stream|
|
63
|
+
stream.puts str
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def colorize level, str
|
68
|
+
#p String.color_samples
|
69
|
+
if @settings["color"] == false || @settings["color"] == nil
|
70
|
+
str
|
71
|
+
elsif @settings["color"] == true
|
72
|
+
case level
|
73
|
+
when :error
|
74
|
+
str.colorize(:red)
|
75
|
+
when :warning
|
76
|
+
str.colorize(:light_yellow)
|
77
|
+
when :not_acknowledged
|
78
|
+
str.colorize(:cyan)
|
79
|
+
when :log
|
80
|
+
str.colorize(:light_blue)
|
81
|
+
when :statistics
|
82
|
+
str.colorize(:light_black)
|
83
|
+
else
|
84
|
+
str
|
85
|
+
end
|
86
|
+
else
|
87
|
+
if level == :nack || level == :warning || level == :error
|
88
|
+
str.colorize(@settings["color"]).bold
|
89
|
+
else
|
90
|
+
str.colorize @settings["color"]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def log item, force:false
|
96
|
+
if output?(item, force)
|
97
|
+
output item[:level], build_output(item)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.shorten_message_id m_id, length=4
|
102
|
+
if m_id
|
103
|
+
m_id[0..length-1].ljust(length)
|
104
|
+
else
|
105
|
+
' '*length
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def dump archive, force:false
|
110
|
+
archive.items.each do |item|
|
111
|
+
log item, force:force
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def build_output item
|
118
|
+
parts = []
|
119
|
+
parts << item[:index].to_s.ljust(7) if @settings["index"] == true
|
120
|
+
parts << item[:author].to_s.ljust(13) if @settings["author"] == true
|
121
|
+
parts << item[:timestamp].to_s.ljust(24) unless @settings["timestamp"] == false
|
122
|
+
parts << item[:ip].to_s.ljust(22) unless @settings["ip"] == false
|
123
|
+
parts << item[:site_id].to_s.ljust(13) unless @settings["site_id"] == false
|
124
|
+
parts << item[:component_id].to_s.ljust(18) unless @settings["component"] == false
|
125
|
+
|
126
|
+
directions = {in:"-->",out:"<--"}
|
127
|
+
parts << directions[item[:direction]].to_s.ljust(4) unless @settings["direction"] == false
|
128
|
+
|
129
|
+
parts << item[:level].to_s.capitalize.ljust(7) unless @settings["level"] == false
|
130
|
+
|
131
|
+
|
132
|
+
unless @settings["id"] == false
|
133
|
+
length = 4
|
134
|
+
if item[:message]
|
135
|
+
parts << Logger.shorten_message_id(item[:message].m_id,length)+' '
|
136
|
+
else
|
137
|
+
parts << " "*(length+1)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
parts << item[:str].to_s.strip unless @settings["text"] == false
|
141
|
+
parts << item[:message].json unless @settings["json"] == false || item[:message] == nil
|
142
|
+
|
143
|
+
if item[:exception]
|
144
|
+
parts << "#{item[:exception].class.to_s}\n"
|
145
|
+
parts << item[:exception].backtrace.join("\n")
|
146
|
+
end
|
147
|
+
|
148
|
+
out = parts.join(' ').chomp(' ')
|
149
|
+
out
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
end
|
data/lib/rsmp/message.rb
ADDED
@@ -0,0 +1,313 @@
|
|
1
|
+
# rsmp messages
|
2
|
+
module RSMP
|
3
|
+
class Message
|
4
|
+
|
5
|
+
attr_reader :now, :attributes, :out, :timestamp
|
6
|
+
attr_accessor :json, :direction
|
7
|
+
|
8
|
+
def self.load_schemas
|
9
|
+
# path to files in submodule folder
|
10
|
+
schema_path = File.join(File.dirname(__dir__),'rsmp_schema','schema')
|
11
|
+
@@schemas = {}
|
12
|
+
|
13
|
+
core_schema_path = File.join(schema_path,'core','rsmp.json')
|
14
|
+
@@schemas['core'] = JSONSchemer.schema( Pathname.new(core_schema_path) )
|
15
|
+
|
16
|
+
tlc_schema_path = File.join(schema_path,'tlc','sxl.json')
|
17
|
+
@@schemas['traffic_light_controller'] = JSONSchemer.schema( Pathname.new(tlc_schema_path) )
|
18
|
+
|
19
|
+
@@schemas
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.get_schema sxl = 'core'
|
23
|
+
schema = @@schemas[sxl]
|
24
|
+
raise SchemaError.new("Unknown schema #{sxl}") unless schema
|
25
|
+
schema
|
26
|
+
end
|
27
|
+
|
28
|
+
@@schemas = load_schemas
|
29
|
+
|
30
|
+
|
31
|
+
def self.parse_attributes packet
|
32
|
+
raise ArgumentError unless packet
|
33
|
+
JSON.parse packet
|
34
|
+
rescue JSON::ParserError
|
35
|
+
raise InvalidPacket, bin_to_chars(packet)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.build attributes, packet
|
39
|
+
validate_message_type attributes
|
40
|
+
case attributes["type"]
|
41
|
+
when "MessageAck"
|
42
|
+
message = MessageAck.new attributes
|
43
|
+
when "MessageNotAck"
|
44
|
+
message = MessageNotAck.new attributes
|
45
|
+
when "Version"
|
46
|
+
message = Version.new attributes
|
47
|
+
when "AggregatedStatus"
|
48
|
+
message = AggregatedStatus.new attributes
|
49
|
+
when "Watchdog"
|
50
|
+
message = Watchdog.new attributes
|
51
|
+
when "Alarm"
|
52
|
+
message = Alarm.new attributes
|
53
|
+
when "CommandRequest"
|
54
|
+
message = CommandRequest.new attributes
|
55
|
+
when "CommandResponse"
|
56
|
+
message = CommandResponse.new attributes
|
57
|
+
when "StatusRequest"
|
58
|
+
message = StatusRequest.new attributes
|
59
|
+
when "StatusResponse"
|
60
|
+
message = StatusResponse.new attributes
|
61
|
+
when "StatusSubscribe"
|
62
|
+
message = StatusSubscribe.new attributes
|
63
|
+
when "StatusUnsubscribe"
|
64
|
+
message = StatusUnsubscribe.new attributes
|
65
|
+
when "StatusUpdate"
|
66
|
+
message = StatusUpdate.new attributes
|
67
|
+
else
|
68
|
+
message = Unknown.new attributes
|
69
|
+
end
|
70
|
+
message.json = packet
|
71
|
+
message.direction = :in
|
72
|
+
message
|
73
|
+
end
|
74
|
+
|
75
|
+
def type
|
76
|
+
@attributes["type"]
|
77
|
+
end
|
78
|
+
|
79
|
+
def m_id
|
80
|
+
@attributes["mId"]
|
81
|
+
end
|
82
|
+
|
83
|
+
def m_id_short
|
84
|
+
@attributes["mId"][0..3]
|
85
|
+
end
|
86
|
+
|
87
|
+
def attribute key
|
88
|
+
unless @attributes.key? key # note that this is not the same as @attributes[key] when
|
89
|
+
maybe = @attributes.find { |k,v| k.downcase == key.downcase }
|
90
|
+
if maybe
|
91
|
+
raise MissingAttribute.new "attribute '#{maybe.first}' should be named '#{key}'"
|
92
|
+
else
|
93
|
+
raise MissingAttribute.new "missing attribute '#{key}'"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
@attributes[key]
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.bin_to_chars(s)
|
100
|
+
out = s.gsub(/[^[:print:]]/i, '.')
|
101
|
+
max = 120
|
102
|
+
if out.size <= max
|
103
|
+
out
|
104
|
+
else
|
105
|
+
mid = " ... "
|
106
|
+
length = (max-mid.size)/2 - 1
|
107
|
+
"#{out[0..length]} ... #{out[-length-1..-1]}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.validate_message_type attributes
|
112
|
+
raise MalformedMessage.new("JSON must be a Hash, got #{attributes.class} ") unless attributes.is_a?(Hash)
|
113
|
+
raise MalformedMessage.new("'mType' is missing") unless attributes["mType"]
|
114
|
+
raise MalformedMessage.new("'mType' must be a String, got #{attributes["mType"].class}") unless attributes["mType"].is_a? String
|
115
|
+
raise MalformedMessage.new("'mType' must be 'rSMsg', got '#{attributes["mType"]}'") unless attributes["mType"] == "rSMsg"
|
116
|
+
raise MalformedMessage.new("'type' is missing") unless attributes["type"]
|
117
|
+
raise MalformedMessage.new("'type' must be a String, got #{attributes["type"].class}") unless attributes["type"].is_a? String
|
118
|
+
end
|
119
|
+
|
120
|
+
def initialize attributes = {}
|
121
|
+
@timestamp = RSMP.now_object
|
122
|
+
@attributes = { "mType"=> "rSMsg" }.merge attributes
|
123
|
+
|
124
|
+
ensure_message_id
|
125
|
+
end
|
126
|
+
|
127
|
+
def ensure_message_id
|
128
|
+
# if message id is empty, generate a new one
|
129
|
+
@attributes["mId"] ||= SecureRandom.uuid()
|
130
|
+
end
|
131
|
+
|
132
|
+
def validate
|
133
|
+
unless Message.get_schema.valid? attributes
|
134
|
+
errors = Message.get_schema.validate attributes
|
135
|
+
error_string = errors.map do |item|
|
136
|
+
[item['data_pointer'],item['type'],item['details']].compact.join(' ')
|
137
|
+
end.join(", ")
|
138
|
+
raise SchemaError.new error_string
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def validate_type
|
143
|
+
@attributes["mType"] == "rSMsg"
|
144
|
+
end
|
145
|
+
|
146
|
+
def validate_id
|
147
|
+
(@attributes["mId"] =~ /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}/i) != nil
|
148
|
+
end
|
149
|
+
|
150
|
+
def valid?
|
151
|
+
true
|
152
|
+
end
|
153
|
+
|
154
|
+
def generate_json
|
155
|
+
@json = JSON.generate @attributes
|
156
|
+
|
157
|
+
# wrap json with a form feed to create an rsmp packet,
|
158
|
+
#as required by the rsmp specification
|
159
|
+
@out = "#{@json}"
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
class Malformed < Message
|
165
|
+
def initialize attributes = {}
|
166
|
+
# don't call super, just copy (potentially invalid) attributes
|
167
|
+
@attributes = {}
|
168
|
+
@invalid_attributes = attributes
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
class Version < Message
|
173
|
+
def initialize attributes = {}
|
174
|
+
super({
|
175
|
+
"type" => "Version",
|
176
|
+
}.merge attributes)
|
177
|
+
end
|
178
|
+
|
179
|
+
def validate
|
180
|
+
super &&
|
181
|
+
@attributes["RSMP"].is_a?(Array) && @attributes["RSMP"].size >= 1
|
182
|
+
end
|
183
|
+
|
184
|
+
def versions
|
185
|
+
attribute("RSMP").map{ |item| item["vers"] }
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
class Unknown < Message
|
190
|
+
end
|
191
|
+
|
192
|
+
class AggregatedStatus < Message
|
193
|
+
def initialize attributes = {}
|
194
|
+
super({
|
195
|
+
"type" => "AggregatedStatus",
|
196
|
+
}.merge attributes)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
class Alarm < Message
|
201
|
+
def initialize attributes = {}
|
202
|
+
super({
|
203
|
+
"type" => "Alarm",
|
204
|
+
}.merge attributes)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
class Watchdog < Message
|
209
|
+
def initialize attributes = {}
|
210
|
+
super({
|
211
|
+
"type" => "Watchdog",
|
212
|
+
}.merge attributes)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
class MessageAcking < Message
|
217
|
+
attr_reader :original
|
218
|
+
|
219
|
+
def self.build_from message
|
220
|
+
return new({
|
221
|
+
"oMId" => message.attributes["mId"]
|
222
|
+
})
|
223
|
+
end
|
224
|
+
|
225
|
+
def original= message
|
226
|
+
raise InvalidArgument unless message
|
227
|
+
@original = message
|
228
|
+
end
|
229
|
+
|
230
|
+
def validate_id
|
231
|
+
true
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
class MessageAck < MessageAcking
|
236
|
+
def initialize attributes = {}
|
237
|
+
super({
|
238
|
+
"type" => "MessageAck",
|
239
|
+
}.merge attributes)
|
240
|
+
end
|
241
|
+
|
242
|
+
def ensure_message_id
|
243
|
+
# Ack and NotAck does not have a mId
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
class MessageNotAck < MessageAcking
|
248
|
+
def initialize attributes = {}
|
249
|
+
super({
|
250
|
+
"type" => "MessageNotAck",
|
251
|
+
"rea" => "Unknown reason"
|
252
|
+
}.merge attributes)
|
253
|
+
@attributes.delete "mId"
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
class CommandRequest < Message
|
258
|
+
def initialize attributes = {}
|
259
|
+
super({
|
260
|
+
"type" => "CommandRequest",
|
261
|
+
}.merge attributes)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
class CommandResponse < Message
|
266
|
+
def initialize attributes = {}
|
267
|
+
super({
|
268
|
+
"type" => "CommandResponse",
|
269
|
+
}.merge attributes)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
class StatusRequest < Message
|
274
|
+
def initialize attributes = {}
|
275
|
+
super({
|
276
|
+
"type" => "StatusRequest",
|
277
|
+
}.merge attributes)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
class StatusResponse < Message
|
282
|
+
def initialize attributes = {}
|
283
|
+
super({
|
284
|
+
"type" => "StatusResponse",
|
285
|
+
}.merge attributes)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
class StatusSubscribe < Message
|
290
|
+
def initialize attributes = {}
|
291
|
+
super({
|
292
|
+
"type" => "StatusSubscribe",
|
293
|
+
}.merge attributes)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
class StatusUnsubscribe < Message
|
298
|
+
def initialize attributes = {}
|
299
|
+
super({
|
300
|
+
"type" => "StatusUnsubscribe",
|
301
|
+
}.merge attributes)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
class StatusUpdate < Message
|
306
|
+
def initialize attributes = {}
|
307
|
+
super({
|
308
|
+
"type" => "StatusUpdate",
|
309
|
+
}.merge attributes)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
data/lib/rsmp/node.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# RSMP site
|
2
|
+
#
|
3
|
+
# Handles a single connection to a supervisor.
|
4
|
+
# We connect to the supervisor.
|
5
|
+
|
6
|
+
module RSMP
|
7
|
+
class Node < Base
|
8
|
+
attr_reader :archive, :logger, :task
|
9
|
+
|
10
|
+
def initialize options
|
11
|
+
super options
|
12
|
+
end
|
13
|
+
|
14
|
+
def start
|
15
|
+
starting
|
16
|
+
Async do |task|
|
17
|
+
task.annotate self.class
|
18
|
+
@task = task
|
19
|
+
start_action
|
20
|
+
end
|
21
|
+
rescue Errno::EADDRINUSE => e
|
22
|
+
log "Cannot start: #{e.to_s}", level: :error
|
23
|
+
rescue SystemExit, SignalException, Interrupt
|
24
|
+
@logger.unmute_all
|
25
|
+
exiting
|
26
|
+
end
|
27
|
+
|
28
|
+
def stop
|
29
|
+
@task.stop if @task
|
30
|
+
end
|
31
|
+
|
32
|
+
def restart
|
33
|
+
stop
|
34
|
+
start
|
35
|
+
end
|
36
|
+
|
37
|
+
def exiting
|
38
|
+
log "Exiting", level: :info
|
39
|
+
end
|
40
|
+
|
41
|
+
def check_required_settings settings, required
|
42
|
+
raise ArgumentError.new "Settings is empty" unless settings
|
43
|
+
required.each do |setting|
|
44
|
+
raise ArgumentError.new "Missing setting: #{setting}" unless settings.include? setting.to_s
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def author
|
49
|
+
site_id
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|