openc3 5.20.0 → 6.0.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 +4 -4
- data/bin/openc3cli +12 -120
- data/data/config/command_modifiers.yaml +13 -1
- data/data/config/interface_modifiers.yaml +21 -4
- data/data/config/item_modifiers.yaml +1 -1
- data/data/config/microservice.yaml +15 -2
- data/data/config/param_item_modifiers.yaml +1 -1
- data/data/config/parameter_modifiers.yaml +1 -1
- data/data/config/table_manager.yaml +2 -2
- data/data/config/target.yaml +11 -0
- data/data/config/telemetry_modifiers.yaml +17 -1
- data/data/config/tool.yaml +12 -0
- data/data/config/widgets.yaml +13 -17
- data/lib/openc3/accessors/form_accessor.rb +4 -3
- data/lib/openc3/accessors/html_accessor.rb +3 -3
- data/lib/openc3/accessors/http_accessor.rb +13 -13
- data/lib/openc3/accessors/xml_accessor.rb +16 -4
- data/lib/openc3/api/target_api.rb +0 -30
- data/lib/openc3/config/config_parser.rb +6 -3
- data/lib/openc3/core_ext/array.rb +0 -16
- data/lib/openc3/core_ext.rb +0 -1
- data/lib/openc3/interfaces/file_interface.rb +198 -0
- data/lib/openc3/interfaces/http_client_interface.rb +71 -39
- data/lib/openc3/interfaces/http_server_interface.rb +0 -7
- data/lib/openc3/interfaces/interface.rb +2 -0
- data/lib/openc3/interfaces/mqtt_interface.rb +32 -15
- data/lib/openc3/interfaces/mqtt_stream_interface.rb +19 -4
- data/lib/openc3/interfaces/protocols/crc_protocol.rb +7 -0
- data/lib/openc3/interfaces/serial_interface.rb +1 -0
- data/lib/openc3/interfaces.rb +2 -4
- data/lib/openc3/microservices/multi_microservice.rb +3 -3
- data/lib/openc3/migrations/20241208080000_no_critical_cmd.rb +31 -0
- data/lib/openc3/migrations/20241208080001_no_trigger_group.rb +46 -0
- data/lib/openc3/models/interface_model.rb +9 -3
- data/lib/openc3/models/microservice_model.rb +8 -1
- data/lib/openc3/models/plugin_model.rb +6 -1
- data/lib/openc3/models/python_package_model.rb +6 -1
- data/lib/openc3/models/reaction_model.rb +14 -10
- data/lib/openc3/models/scope_model.rb +60 -42
- data/lib/openc3/models/target_model.rb +17 -1
- data/lib/openc3/models/timeline_model.rb +17 -5
- data/lib/openc3/models/tool_model.rb +15 -3
- data/lib/openc3/models/trigger_group_model.rb +6 -3
- data/lib/openc3/operators/microservice_operator.rb +8 -0
- data/lib/openc3/packets/commands.rb +17 -6
- data/lib/openc3/packets/limits.rb +0 -12
- data/lib/openc3/packets/packet.rb +1 -1
- data/lib/openc3/packets/packet_item.rb +30 -36
- data/lib/openc3/packets/structure_item.rb +2 -2
- data/lib/openc3/script/script.rb +0 -10
- data/lib/openc3/script/web_socket_api.rb +2 -2
- data/lib/openc3/streams/mqtt_stream.rb +41 -33
- data/lib/openc3/streams/serial_stream.rb +27 -27
- data/lib/openc3/streams/stream.rb +17 -17
- data/lib/openc3/streams/tcpip_client_stream.rb +1 -1
- data/lib/openc3/streams/tcpip_socket_stream.rb +19 -19
- data/lib/openc3/system/system.rb +1 -1
- data/lib/openc3/system.rb +2 -3
- data/lib/openc3/tools/table_manager/table.rb +2 -2
- data/lib/openc3/tools/table_manager/table_parser.rb +1 -1
- data/lib/openc3/top_level.rb +0 -5
- data/lib/openc3/topics/command_decom_topic.rb +0 -7
- data/lib/openc3/utilities/bucket_utilities.rb +1 -1
- data/lib/openc3/utilities/cli_generator.rb +0 -1
- data/lib/openc3/version.rb +6 -6
- data/templates/plugin/README.md +1 -1
- data/templates/target/targets/TARGET/lib/target.rb +1 -1
- data/templates/tool_angular/package.json +8 -8
- data/templates/tool_angular/src/app/app.component.html +4 -13
- data/templates/tool_angular/src/app/app.component.scss +5 -13
- data/templates/tool_angular/src/app/app.component.ts +5 -4
- data/templates/tool_angular/src/app/custom-overlay-container.ts +2 -2
- data/templates/tool_angular/src/app/openc3-api.d.ts +1 -1
- data/templates/tool_angular/src/main.single-spa.ts +1 -1
- data/templates/tool_react/package.json +1 -0
- data/templates/tool_react/src/root.component.js +1 -1
- data/templates/tool_svelte/package.json +11 -9
- data/templates/tool_svelte/rollup.config.js +2 -0
- data/templates/tool_svelte/src/App.svelte +2 -2
- data/templates/tool_vue/eslint.config.mjs +68 -0
- data/templates/tool_vue/jsconfig.json +1 -1
- data/templates/tool_vue/package.json +26 -43
- data/templates/tool_vue/src/App.vue +3 -5
- data/templates/tool_vue/src/main.js +12 -23
- data/templates/tool_vue/src/router.js +19 -18
- data/templates/tool_vue/src/tools/tool_name/tool_name.vue +2 -2
- data/templates/tool_vue/vite.config.js +52 -0
- data/templates/widget/package.json +19 -26
- data/templates/widget/src/Widget.vue +13 -15
- data/templates/widget/vite.config.js +26 -0
- metadata +10 -41
- data/lib/openc3/core_ext/hash.rb +0 -40
- data/lib/openc3/core_ext/httpclient.rb +0 -11
- data/lib/openc3/interfaces/linc_interface.rb +0 -480
- data/lib/openc3/interfaces/protocols/override_protocol.rb +0 -4
- data/lib/openc3/microservices/critical_cmd_microservice.rb +0 -74
- data/lib/openc3/microservices/reaction_microservice.rb +0 -607
- data/lib/openc3/microservices/timeline_microservice.rb +0 -398
- data/lib/openc3/microservices/trigger_group_microservice.rb +0 -698
- data/lib/openc3/migrations/20230615000000_autonomic.rb +0 -86
- data/lib/openc3/migrations/20240915000000_activity_uuid.rb +0 -28
- data/lib/openc3/migrations/20241016000000_scope_critical_cmd.rb +0 -24
- data/lib/openc3/system/system_config.rb +0 -413
- data/templates/tool_svelte/src/services/api.js +0 -92
- data/templates/tool_svelte/src/services/axios.js +0 -85
- data/templates/tool_svelte/src/services/cable.js +0 -65
- data/templates/tool_svelte/src/services/config-parser.js +0 -198
- data/templates/tool_svelte/src/services/openc3-api.js +0 -606
- data/templates/tool_vue/.eslintrc.js +0 -43
- data/templates/tool_vue/babel.config.json +0 -11
- data/templates/tool_vue/vue.config.js +0 -38
- data/templates/widget/.eslintrc.js +0 -43
- data/templates/widget/babel.config.json +0 -11
- data/templates/widget/vue.config.js +0 -28
- /data/templates/tool_vue/{.prettierrc.js → .prettierrc.cjs} +0 -0
- /data/templates/widget/{.prettierrc.js → .prettierrc.cjs} +0 -0
|
@@ -1,398 +0,0 @@
|
|
|
1
|
-
# encoding: ascii-8bit
|
|
2
|
-
|
|
3
|
-
# Copyright 2022 Ball Aerospace & Technologies Corp.
|
|
4
|
-
# All Rights Reserved.
|
|
5
|
-
#
|
|
6
|
-
# This program is free software; you can modify and/or redistribute it
|
|
7
|
-
# under the terms of the GNU Affero General Public License
|
|
8
|
-
# as published by the Free Software Foundation; version 3 with
|
|
9
|
-
# attribution addendums as found in the LICENSE.txt
|
|
10
|
-
#
|
|
11
|
-
# This program is distributed in the hope that it will be useful,
|
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
-
# GNU Affero General Public License for more details.
|
|
15
|
-
|
|
16
|
-
# Modified by OpenC3, Inc.
|
|
17
|
-
# All changes Copyright 2023, OpenC3, Inc.
|
|
18
|
-
# All Rights Reserved
|
|
19
|
-
#
|
|
20
|
-
# This file may also be used under the terms of a commercial license
|
|
21
|
-
# if purchased from OpenC3, Inc.
|
|
22
|
-
|
|
23
|
-
require 'openc3/utilities/authentication'
|
|
24
|
-
require 'openc3/microservices/microservice'
|
|
25
|
-
require 'openc3/models/activity_model'
|
|
26
|
-
require 'openc3/models/timeline_model'
|
|
27
|
-
require 'openc3/models/tool_config_model'
|
|
28
|
-
require 'openc3/topics/timeline_topic'
|
|
29
|
-
|
|
30
|
-
require 'openc3/script'
|
|
31
|
-
|
|
32
|
-
module OpenC3
|
|
33
|
-
# The Timeline worker is a very simple thread pool worker. Once
|
|
34
|
-
# the timeline manager has pushed a job to the schedule one of
|
|
35
|
-
# these workers will run the CMD (command) or SCRIPT (script)
|
|
36
|
-
# or anything that could be expanded in the future.
|
|
37
|
-
class TimelineWorker
|
|
38
|
-
def initialize(name:, logger:, scope:, queue:)
|
|
39
|
-
@timeline_name = name
|
|
40
|
-
@logger = logger
|
|
41
|
-
@scope = scope
|
|
42
|
-
@queue = queue
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def get_token(username)
|
|
46
|
-
if ENV['OPENC3_API_CLIENT'].nil?
|
|
47
|
-
ENV['OPENC3_API_PASSWORD'] ||= ENV['OPENC3_SERVICE_PASSWORD']
|
|
48
|
-
return OpenC3Authentication.new().token
|
|
49
|
-
else
|
|
50
|
-
# Check for offline access token
|
|
51
|
-
model = nil
|
|
52
|
-
model = OpenC3::OfflineAccessModel.get_model(name: username, scope: @scope) if username and username != ''
|
|
53
|
-
if model and model.offline_access_token
|
|
54
|
-
auth = OpenC3KeycloakAuthentication.new(ENV['OPENC3_KEYCLOAK_URL'])
|
|
55
|
-
return auth.get_token_from_refresh_token(model.offline_access_token)
|
|
56
|
-
else
|
|
57
|
-
return nil
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def run
|
|
63
|
-
@logger.info "#{@timeline_name} timeline worker running"
|
|
64
|
-
loop do
|
|
65
|
-
activity = @queue.pop
|
|
66
|
-
break if activity.nil?
|
|
67
|
-
|
|
68
|
-
run_activity(activity)
|
|
69
|
-
end
|
|
70
|
-
@logger.info "#{@timeline_name} timeline worker exiting"
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def run_activity(activity)
|
|
74
|
-
case activity.kind.downcase
|
|
75
|
-
when 'command'
|
|
76
|
-
run_command(activity)
|
|
77
|
-
when 'script'
|
|
78
|
-
run_script(activity)
|
|
79
|
-
when 'expire'
|
|
80
|
-
clear_expired(activity)
|
|
81
|
-
else
|
|
82
|
-
@logger.error "Unknown kind passed to microservice #{@timeline_name}: #{activity.as_json(:allow_nan => true)}"
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def get_exec_setting()
|
|
87
|
-
json = ToolConfigModel.load_config('calendar-settings', 'default', scope: @scope)
|
|
88
|
-
if json
|
|
89
|
-
settings = JSON.parse(json)
|
|
90
|
-
return settings['execEnabled']
|
|
91
|
-
else
|
|
92
|
-
# Default is execute
|
|
93
|
-
return true
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def run_command(activity)
|
|
98
|
-
@logger.info "#{@timeline_name} run_command > #{activity.as_json(:allow_nan => true)}"
|
|
99
|
-
begin
|
|
100
|
-
if get_exec_setting()
|
|
101
|
-
username = activity.data['username']
|
|
102
|
-
token = get_token(username)
|
|
103
|
-
raise "No token available for username: #{username}" unless token
|
|
104
|
-
cmd_no_hazardous_check(activity.data['command'], scope: @scope, token: token)
|
|
105
|
-
activity.commit(status: 'completed', fulfillment: true)
|
|
106
|
-
else
|
|
107
|
-
activity.commit(status: 'disabled', message: 'Execution is disabled')
|
|
108
|
-
@logger.warn "#{@timeline_name} run_command disabled > #{activity.as_json(:allow_nan => true)}"
|
|
109
|
-
end
|
|
110
|
-
rescue StandardError => e
|
|
111
|
-
activity.commit(status: 'failed', message: e.message)
|
|
112
|
-
@logger.error "#{@timeline_name} run_command failed > #{activity.as_json(:allow_nan => true)}, #{e.formatted}"
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def run_script(activity)
|
|
117
|
-
@logger.info "#{@timeline_name} run_script > #{activity.as_json(:allow_nan => true)}"
|
|
118
|
-
begin
|
|
119
|
-
if get_exec_setting()
|
|
120
|
-
username = activity.data['username']
|
|
121
|
-
token = get_token(username)
|
|
122
|
-
raise "No token available for username: #{username}" unless token
|
|
123
|
-
request = Net::HTTP::Post.new(
|
|
124
|
-
"/script-api/scripts/#{activity.data['script']}/run?scope=#{@scope}",
|
|
125
|
-
'Content-Type' => 'application/json',
|
|
126
|
-
'Authorization' => token
|
|
127
|
-
)
|
|
128
|
-
request.body = JSON.generate({
|
|
129
|
-
'scope' => @scope,
|
|
130
|
-
'environment' => activity.data['environment'],
|
|
131
|
-
'timeline' => @timeline_name,
|
|
132
|
-
'id' => activity.start
|
|
133
|
-
})
|
|
134
|
-
hostname = ENV['OPENC3_SCRIPT_HOSTNAME'] || 'openc3-cosmos-script-runner-api'
|
|
135
|
-
response = Net::HTTP.new(hostname, 2902).request(request)
|
|
136
|
-
raise "failed to call #{hostname}, for script: #{activity.data['script']}, response code: #{response.code}" if response.code != '200'
|
|
137
|
-
|
|
138
|
-
activity.commit(status: 'completed', message: "#{activity.data['script']} => #{response.body}", fulfillment: true)
|
|
139
|
-
else
|
|
140
|
-
activity.commit(status: 'disabled', message: 'Execution is disabled')
|
|
141
|
-
@logger.warn "#{@timeline_name} run_script disabled > #{activity.as_json(:allow_nan => true)}"
|
|
142
|
-
end
|
|
143
|
-
rescue StandardError => e
|
|
144
|
-
activity.commit(status: 'failed', message: e.message)
|
|
145
|
-
@logger.error "#{@timeline_name} run_script failed > #{activity.as_json(:allow_nan => true)}, #{e.message}"
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def clear_expired(activity)
|
|
150
|
-
begin
|
|
151
|
-
num = ActivityModel.range_destroy(name: @timeline_name, scope: @scope, min: activity.start, max: activity.stop)
|
|
152
|
-
@logger.info "#{@timeline_name} clear_expired removed #{num} items from #{activity.start} to #{activity.stop}"
|
|
153
|
-
activity.add_event(status: 'completed')
|
|
154
|
-
rescue StandardError => e
|
|
155
|
-
@logger.error "#{@timeline_name} clear_expired failed > #{activity.as_json(:allow_nan => true)} #{e.message}"
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
# Shared between the monitor thread and the manager thread to
|
|
161
|
-
# share the planned activities. This should remain a thread
|
|
162
|
-
# safe implementation.
|
|
163
|
-
class Schedule
|
|
164
|
-
def initialize(name)
|
|
165
|
-
@name = name
|
|
166
|
-
@activities_mutex = Mutex.new
|
|
167
|
-
@activities = []
|
|
168
|
-
# This can stay relatively small since it's only the currently queued
|
|
169
|
-
# activities. Once a worker thread processes it we no longer care.
|
|
170
|
-
@size = 20
|
|
171
|
-
@queue = Array.new(@size)
|
|
172
|
-
@index = 0
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def not_queued?(activity)
|
|
176
|
-
return false if @queue.index(activity.uuid)
|
|
177
|
-
@queue[@index] = activity.uuid
|
|
178
|
-
@index = @index + 1 >= @size ? 0 : @index + 1
|
|
179
|
-
return true
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def activities
|
|
183
|
-
@activities_mutex.synchronize do
|
|
184
|
-
return @activities.dup
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
def update(input_activities)
|
|
189
|
-
@activities_mutex.synchronize do
|
|
190
|
-
@activities = input_activities.dup
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
def add_activity(activity)
|
|
195
|
-
@activities_mutex.synchronize do
|
|
196
|
-
@activities << activity
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
def remove_activity(data)
|
|
201
|
-
@activities_mutex.synchronize do
|
|
202
|
-
@activities.delete_if do |a|
|
|
203
|
-
a.start == data['start'] && a.uuid == data['uuid']
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
# The timeline manager starts a thread pool and looks at the
|
|
210
|
-
# schedule and if an "activity" should be run. TimelineManager
|
|
211
|
-
# adds the "activity" to the thread pool and the thread will
|
|
212
|
-
# execute the "activity".
|
|
213
|
-
class TimelineManager
|
|
214
|
-
def initialize(name:, logger:, scope:, schedule:)
|
|
215
|
-
@timeline_name = name
|
|
216
|
-
@logger = logger
|
|
217
|
-
@scope = scope
|
|
218
|
-
@schedule = schedule
|
|
219
|
-
@worker_count = 3
|
|
220
|
-
@queue = Queue.new
|
|
221
|
-
@thread_pool = generate_thread_pool()
|
|
222
|
-
@cancel_thread = false
|
|
223
|
-
@expire = 0
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
def generate_thread_pool
|
|
227
|
-
thread_pool = []
|
|
228
|
-
@worker_count.times {
|
|
229
|
-
worker = TimelineWorker.new(name: @timeline_name, logger: @logger, scope: @scope, queue: @queue)
|
|
230
|
-
thread_pool << Thread.new { worker.run }
|
|
231
|
-
}
|
|
232
|
-
return thread_pool
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
def run
|
|
236
|
-
@logger.info "#{@timeline_name} timeline manager running"
|
|
237
|
-
loop do
|
|
238
|
-
start = Time.now.to_f
|
|
239
|
-
@schedule.activities.each do |activity|
|
|
240
|
-
start_difference = activity.start - start
|
|
241
|
-
if start_difference <= 0 && @schedule.not_queued?(activity)
|
|
242
|
-
@logger.debug "#{@timeline_name} #{@scope} current start: #{start}, vs #{activity.start}, #{start_difference}"
|
|
243
|
-
activity.add_event(status: 'queued')
|
|
244
|
-
@queue << activity
|
|
245
|
-
end
|
|
246
|
-
end
|
|
247
|
-
if start >= @expire
|
|
248
|
-
@queue << add_expire_activity()
|
|
249
|
-
request_update(start: start)
|
|
250
|
-
end
|
|
251
|
-
break if @cancel_thread
|
|
252
|
-
|
|
253
|
-
sleep(1)
|
|
254
|
-
break if @cancel_thread
|
|
255
|
-
end
|
|
256
|
-
@logger.info "#{@timeline_name} timeline manager exiting"
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
# Add task to remove events older than 7 days
|
|
260
|
-
def add_expire_activity
|
|
261
|
-
now = Time.now.to_f
|
|
262
|
-
@expire = now + 3540 # Needs to be less than 3600 which is the hour we store in memory
|
|
263
|
-
activity = ActivityModel.new(
|
|
264
|
-
name: @timeline_name,
|
|
265
|
-
scope: @scope,
|
|
266
|
-
start: 0,
|
|
267
|
-
stop: (now - (86_400 * 7)),
|
|
268
|
-
kind: 'expire',
|
|
269
|
-
data: {}
|
|
270
|
-
)
|
|
271
|
-
return activity
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
# This can feedback to ensure the schedule will not run out so this should fire once an
|
|
275
|
-
# hour to make sure the TimelineMicroservice will collect the next hour and update the
|
|
276
|
-
# schedule.
|
|
277
|
-
def request_update(start:)
|
|
278
|
-
notification = {
|
|
279
|
-
'data' => JSON.generate({ 'time' => start }),
|
|
280
|
-
'kind' => 'refresh',
|
|
281
|
-
'type' => 'timeline',
|
|
282
|
-
'timeline' => @timeline_name
|
|
283
|
-
}
|
|
284
|
-
begin
|
|
285
|
-
TimelineTopic.write_activity(notification, scope: @scope)
|
|
286
|
-
rescue StandardError
|
|
287
|
-
@logger.error "#{@name} manager failed to request update"
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
def shutdown
|
|
292
|
-
@cancel_thread = true
|
|
293
|
-
@worker_count.times {
|
|
294
|
-
@queue << nil
|
|
295
|
-
}
|
|
296
|
-
end
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
# The timeline microservice starts a manager then gets the activities
|
|
300
|
-
# from the sorted set in redis and updates the schedule for the
|
|
301
|
-
# manager. Timeline will then wait for an update on the timeline
|
|
302
|
-
# stream this will trigger an update again to the schedule.
|
|
303
|
-
class TimelineMicroservice < Microservice
|
|
304
|
-
def initialize(name)
|
|
305
|
-
super(name)
|
|
306
|
-
@timeline_name = name.split('__')[2]
|
|
307
|
-
@schedule = Schedule.new(@timeline_name)
|
|
308
|
-
@manager = TimelineManager.new(name: @timeline_name, logger: @logger, scope: @scope, schedule: @schedule)
|
|
309
|
-
@manager_thread = nil
|
|
310
|
-
@read_topic = true
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
def run
|
|
314
|
-
@logger.info "#{@name} timeline running"
|
|
315
|
-
@manager_thread = Thread.new { @manager.run }
|
|
316
|
-
loop do
|
|
317
|
-
current_activities = ActivityModel.activities(name: @timeline_name, scope: @scope)
|
|
318
|
-
@schedule.update(current_activities)
|
|
319
|
-
break if @cancel_thread
|
|
320
|
-
|
|
321
|
-
block_for_updates()
|
|
322
|
-
break if @cancel_thread
|
|
323
|
-
end
|
|
324
|
-
@logger.info "#{@name} timeline exiting"
|
|
325
|
-
end
|
|
326
|
-
|
|
327
|
-
def topic_lookup_functions
|
|
328
|
-
{
|
|
329
|
-
'timeline' => {
|
|
330
|
-
'created' => :timeline_noop,
|
|
331
|
-
'refresh' => :schedule_refresh,
|
|
332
|
-
'updated' => :timeline_noop,
|
|
333
|
-
'deleted' => :timeline_noop
|
|
334
|
-
},
|
|
335
|
-
'activity' => {
|
|
336
|
-
'event' => :timeline_noop,
|
|
337
|
-
'created' => :create_activity_from_event,
|
|
338
|
-
'updated' => :schedule_refresh,
|
|
339
|
-
'deleted' => :remove_activity_from_event
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
end
|
|
343
|
-
|
|
344
|
-
def block_for_updates
|
|
345
|
-
@read_topic = true
|
|
346
|
-
while @read_topic
|
|
347
|
-
begin
|
|
348
|
-
TimelineTopic.read_topics(@topics) do |_topic, _msg_id, msg_hash, _redis|
|
|
349
|
-
if msg_hash['timeline'] == @timeline_name
|
|
350
|
-
data = JSON.parse(msg_hash['data'], :allow_nan => true, :create_additions => true)
|
|
351
|
-
public_send(topic_lookup_functions[msg_hash['type']][msg_hash['kind']], data)
|
|
352
|
-
end
|
|
353
|
-
end
|
|
354
|
-
rescue StandardError => e
|
|
355
|
-
@logger.error "#{@timeline_name} failed to read topics #{@topics}\n#{e.formatted}"
|
|
356
|
-
end
|
|
357
|
-
end
|
|
358
|
-
end
|
|
359
|
-
|
|
360
|
-
def timeline_noop(data)
|
|
361
|
-
@logger.debug "#{@name} timeline web socket event: #{data}"
|
|
362
|
-
end
|
|
363
|
-
|
|
364
|
-
def schedule_refresh(data)
|
|
365
|
-
@logger.debug "#{@name} timeline web socket schedule refresh: #{data}"
|
|
366
|
-
@read_topic = false
|
|
367
|
-
end
|
|
368
|
-
|
|
369
|
-
# Add the activity to the schedule. We don't need to hold the job in memory
|
|
370
|
-
# if it is longer than an hour away. A refresh task will update that.
|
|
371
|
-
def create_activity_from_event(data)
|
|
372
|
-
diff = data['start'] - Time.now.to_f
|
|
373
|
-
return if diff < 0 or diff > 3600
|
|
374
|
-
|
|
375
|
-
activity = ActivityModel.from_json(data, name: @timeline_name, scope: @scope)
|
|
376
|
-
@schedule.add_activity(activity)
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
# Remove the activity from the schedule. We don't need to remove the activity
|
|
380
|
-
# if it is longer than an hour away. It will be removed from the data.
|
|
381
|
-
def remove_activity_from_event(data)
|
|
382
|
-
diff = data['start'] - Time.now.to_f
|
|
383
|
-
return if diff < 0 or diff > 3600
|
|
384
|
-
@schedule.remove_activity(data)
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
def shutdown
|
|
388
|
-
@manager.shutdown
|
|
389
|
-
# super also sets @cancel_thread = true but we want to set it first
|
|
390
|
-
# so when we set @read_topic = false the run loop stops
|
|
391
|
-
@cancel_thread = true
|
|
392
|
-
@read_topic = false
|
|
393
|
-
super()
|
|
394
|
-
end
|
|
395
|
-
end
|
|
396
|
-
end
|
|
397
|
-
|
|
398
|
-
OpenC3::TimelineMicroservice.run if __FILE__ == $0
|