openc3 5.0.6

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 (307) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +18 -0
  3. data/Guardfile +35 -0
  4. data/LICENSE.txt +727 -0
  5. data/README.md +37 -0
  6. data/Rakefile +131 -0
  7. data/bin/cstol_converter +1178 -0
  8. data/bin/openc3cli +531 -0
  9. data/bin/rubysloc +139 -0
  10. data/data/config/_array_params.yaml +23 -0
  11. data/data/config/_id_items.yaml +24 -0
  12. data/data/config/_id_params.yaml +58 -0
  13. data/data/config/_interfaces.yaml +214 -0
  14. data/data/config/_interfaces.yaml.err +1017 -0
  15. data/data/config/_items.yaml +20 -0
  16. data/data/config/_params.yaml +60 -0
  17. data/data/config/cmd_tlm_server.yaml +136 -0
  18. data/data/config/command.yaml +44 -0
  19. data/data/config/command_modifiers.yaml +160 -0
  20. data/data/config/command_telemetry.yaml +3 -0
  21. data/data/config/interface_modifiers.yaml +104 -0
  22. data/data/config/item_modifiers.yaml +221 -0
  23. data/data/config/microservice.yaml +78 -0
  24. data/data/config/param_item_modifiers.yaml +52 -0
  25. data/data/config/parameter_modifiers.yaml +200 -0
  26. data/data/config/plugins.yaml +80 -0
  27. data/data/config/protocols.yaml +290 -0
  28. data/data/config/screen.yaml +147 -0
  29. data/data/config/table_manager.yaml +89 -0
  30. data/data/config/table_parameter_modifiers.yaml +9 -0
  31. data/data/config/target.yaml +142 -0
  32. data/data/config/target_config.yaml +94 -0
  33. data/data/config/telemetry.yaml +87 -0
  34. data/data/config/telemetry_modifiers.yaml +159 -0
  35. data/data/config/tool.yaml +63 -0
  36. data/data/config/unknown.yaml +3 -0
  37. data/data/config/widgets.yaml +1505 -0
  38. data/ext/mkrf_conf.rb +49 -0
  39. data/ext/openc3/ext/array/array.c +122 -0
  40. data/ext/openc3/ext/array/extconf.rb +13 -0
  41. data/ext/openc3/ext/buffered_file/buffered_file.c +198 -0
  42. data/ext/openc3/ext/buffered_file/extconf.rb +13 -0
  43. data/ext/openc3/ext/config_parser/config_parser.c +280 -0
  44. data/ext/openc3/ext/config_parser/extconf.rb +13 -0
  45. data/ext/openc3/ext/crc/crc.c +351 -0
  46. data/ext/openc3/ext/crc/extconf.rb +13 -0
  47. data/ext/openc3/ext/openc3_io/extconf.rb +13 -0
  48. data/ext/openc3/ext/openc3_io/openc3_io.c +158 -0
  49. data/ext/openc3/ext/packet/extconf.rb +13 -0
  50. data/ext/openc3/ext/packet/packet.c +318 -0
  51. data/ext/openc3/ext/platform/extconf.rb +13 -0
  52. data/ext/openc3/ext/platform/platform.c +134 -0
  53. data/ext/openc3/ext/polynomial_conversion/extconf.rb +13 -0
  54. data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +79 -0
  55. data/ext/openc3/ext/string/extconf.rb +13 -0
  56. data/ext/openc3/ext/string/string.c +63 -0
  57. data/ext/openc3/ext/structure/structure.c +1719 -0
  58. data/ext/openc3/ext/tabbed_plots_config/extconf.rb +13 -0
  59. data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +62 -0
  60. data/ext/openc3/ext/telemetry/extconf.rb +13 -0
  61. data/ext/openc3/ext/telemetry/telemetry.c +336 -0
  62. data/lib/cosmos.rb +20 -0
  63. data/lib/cosmosc2.rb +20 -0
  64. data/lib/openc3/api/api.rb +39 -0
  65. data/lib/openc3/api/authorized_api.rb +30 -0
  66. data/lib/openc3/api/cmd_api.rb +451 -0
  67. data/lib/openc3/api/config_api.rb +58 -0
  68. data/lib/openc3/api/interface_api.rb +117 -0
  69. data/lib/openc3/api/limits_api.rb +375 -0
  70. data/lib/openc3/api/router_api.rb +117 -0
  71. data/lib/openc3/api/settings_api.rb +70 -0
  72. data/lib/openc3/api/target_api.rb +78 -0
  73. data/lib/openc3/api/tlm_api.rb +455 -0
  74. data/lib/openc3/bridge/bridge.rb +54 -0
  75. data/lib/openc3/bridge/bridge_config.rb +167 -0
  76. data/lib/openc3/bridge/bridge_interface_thread.rb +42 -0
  77. data/lib/openc3/bridge/bridge_router_thread.rb +42 -0
  78. data/lib/openc3/ccsds/ccsds_packet.rb +68 -0
  79. data/lib/openc3/ccsds/ccsds_parser.rb +148 -0
  80. data/lib/openc3/config/config_parser.rb +549 -0
  81. data/lib/openc3/config/meta_config_parser.rb +74 -0
  82. data/lib/openc3/conversions/conversion.rb +70 -0
  83. data/lib/openc3/conversions/generic_conversion.rb +83 -0
  84. data/lib/openc3/conversions/packet_time_formatted_conversion.rb +43 -0
  85. data/lib/openc3/conversions/packet_time_seconds_conversion.rb +43 -0
  86. data/lib/openc3/conversions/polynomial_conversion.rb +87 -0
  87. data/lib/openc3/conversions/processor_conversion.rb +70 -0
  88. data/lib/openc3/conversions/received_count_conversion.rb +38 -0
  89. data/lib/openc3/conversions/received_time_formatted_conversion.rb +42 -0
  90. data/lib/openc3/conversions/received_time_seconds_conversion.rb +42 -0
  91. data/lib/openc3/conversions/segmented_polynomial_conversion.rb +171 -0
  92. data/lib/openc3/conversions/unix_time_conversion.rb +68 -0
  93. data/lib/openc3/conversions/unix_time_formatted_conversion.rb +49 -0
  94. data/lib/openc3/conversions/unix_time_seconds_conversion.rb +49 -0
  95. data/lib/openc3/conversions.rb +34 -0
  96. data/lib/openc3/core_ext/array.rb +416 -0
  97. data/lib/openc3/core_ext/binding.rb +29 -0
  98. data/lib/openc3/core_ext/class.rb +72 -0
  99. data/lib/openc3/core_ext/exception.rb +61 -0
  100. data/lib/openc3/core_ext/file.rb +83 -0
  101. data/lib/openc3/core_ext/hash.rb +37 -0
  102. data/lib/openc3/core_ext/io.rb +134 -0
  103. data/lib/openc3/core_ext/kernel.rb +42 -0
  104. data/lib/openc3/core_ext/math.rb +128 -0
  105. data/lib/openc3/core_ext/matrix.rb +156 -0
  106. data/lib/openc3/core_ext/objectspace.rb +36 -0
  107. data/lib/openc3/core_ext/openc3_io.rb +57 -0
  108. data/lib/openc3/core_ext/range.rb +27 -0
  109. data/lib/openc3/core_ext/socket.rb +38 -0
  110. data/lib/openc3/core_ext/string.rb +389 -0
  111. data/lib/openc3/core_ext/stringio.rb +33 -0
  112. data/lib/openc3/core_ext/time.rb +508 -0
  113. data/lib/openc3/core_ext.rb +36 -0
  114. data/lib/openc3/interfaces/interface.rb +498 -0
  115. data/lib/openc3/interfaces/linc_interface.rb +475 -0
  116. data/lib/openc3/interfaces/protocols/burst_protocol.rb +192 -0
  117. data/lib/openc3/interfaces/protocols/crc_protocol.rb +193 -0
  118. data/lib/openc3/interfaces/protocols/fixed_protocol.rb +155 -0
  119. data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +56 -0
  120. data/lib/openc3/interfaces/protocols/length_protocol.rb +165 -0
  121. data/lib/openc3/interfaces/protocols/override_protocol.rb +60 -0
  122. data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +206 -0
  123. data/lib/openc3/interfaces/protocols/protocol.rb +82 -0
  124. data/lib/openc3/interfaces/protocols/template_protocol.rb +261 -0
  125. data/lib/openc3/interfaces/protocols/terminated_protocol.rb +93 -0
  126. data/lib/openc3/interfaces/serial_interface.rb +94 -0
  127. data/lib/openc3/interfaces/simulated_target_interface.rb +168 -0
  128. data/lib/openc3/interfaces/stream_interface.rb +81 -0
  129. data/lib/openc3/interfaces/tcpip_client_interface.rb +69 -0
  130. data/lib/openc3/interfaces/tcpip_server_interface.rb +629 -0
  131. data/lib/openc3/interfaces/udp_interface.rb +169 -0
  132. data/lib/openc3/interfaces.rb +44 -0
  133. data/lib/openc3/io/buffered_file.rb +109 -0
  134. data/lib/openc3/io/io_multiplexer.rb +80 -0
  135. data/lib/openc3/io/json_api_object.rb +208 -0
  136. data/lib/openc3/io/json_drb.rb +335 -0
  137. data/lib/openc3/io/json_drb_object.rb +114 -0
  138. data/lib/openc3/io/json_drb_rack.rb +84 -0
  139. data/lib/openc3/io/json_rpc.rb +420 -0
  140. data/lib/openc3/io/openc3_snmp.rb +58 -0
  141. data/lib/openc3/io/posix_serial_driver.rb +156 -0
  142. data/lib/openc3/io/raw_logger.rb +167 -0
  143. data/lib/openc3/io/raw_logger_pair.rb +77 -0
  144. data/lib/openc3/io/serial_driver.rb +105 -0
  145. data/lib/openc3/io/stderr.rb +43 -0
  146. data/lib/openc3/io/stdout.rb +43 -0
  147. data/lib/openc3/io/udp_sockets.rb +194 -0
  148. data/lib/openc3/io/win32_serial_driver.rb +196 -0
  149. data/lib/openc3/logs/log_writer.rb +302 -0
  150. data/lib/openc3/logs/packet_log_constants.rb +62 -0
  151. data/lib/openc3/logs/packet_log_reader.rb +345 -0
  152. data/lib/openc3/logs/packet_log_writer.rb +299 -0
  153. data/lib/openc3/logs/text_log_writer.rb +68 -0
  154. data/lib/openc3/logs.rb +25 -0
  155. data/lib/openc3/microservices/cleanup_microservice.rb +68 -0
  156. data/lib/openc3/microservices/decom_microservice.rb +136 -0
  157. data/lib/openc3/microservices/interface_microservice.rb +532 -0
  158. data/lib/openc3/microservices/log_microservice.rb +108 -0
  159. data/lib/openc3/microservices/microservice.rb +204 -0
  160. data/lib/openc3/microservices/plugin_microservice.rb +43 -0
  161. data/lib/openc3/microservices/reaction_microservice.rb +541 -0
  162. data/lib/openc3/microservices/reducer_microservice.rb +313 -0
  163. data/lib/openc3/microservices/router_microservice.rb +44 -0
  164. data/lib/openc3/microservices/text_log_microservice.rb +84 -0
  165. data/lib/openc3/microservices/timeline_microservice.rb +363 -0
  166. data/lib/openc3/microservices/trigger_group_microservice.rb +638 -0
  167. data/lib/openc3/models/activity_model.rb +319 -0
  168. data/lib/openc3/models/auth_model.rb +65 -0
  169. data/lib/openc3/models/cvt_model.rb +185 -0
  170. data/lib/openc3/models/environment_model.rb +58 -0
  171. data/lib/openc3/models/gem_model.rb +137 -0
  172. data/lib/openc3/models/info_model.rb +31 -0
  173. data/lib/openc3/models/interface_model.rb +281 -0
  174. data/lib/openc3/models/interface_status_model.rb +117 -0
  175. data/lib/openc3/models/metadata_model.rb +139 -0
  176. data/lib/openc3/models/metric_model.rb +59 -0
  177. data/lib/openc3/models/microservice_model.rb +206 -0
  178. data/lib/openc3/models/microservice_status_model.rb +74 -0
  179. data/lib/openc3/models/model.rb +204 -0
  180. data/lib/openc3/models/note_model.rb +122 -0
  181. data/lib/openc3/models/notification_model.rb +40 -0
  182. data/lib/openc3/models/ping_model.rb +35 -0
  183. data/lib/openc3/models/plugin_model.rb +292 -0
  184. data/lib/openc3/models/process_status_model.rb +76 -0
  185. data/lib/openc3/models/reaction_model.rb +322 -0
  186. data/lib/openc3/models/reducer_model.rb +65 -0
  187. data/lib/openc3/models/router_model.rb +35 -0
  188. data/lib/openc3/models/router_status_model.rb +27 -0
  189. data/lib/openc3/models/scope_model.rb +153 -0
  190. data/lib/openc3/models/settings_model.rb +55 -0
  191. data/lib/openc3/models/sorted_model.rb +167 -0
  192. data/lib/openc3/models/target_model.rb +759 -0
  193. data/lib/openc3/models/timeline_model.rb +154 -0
  194. data/lib/openc3/models/tool_config_model.rb +38 -0
  195. data/lib/openc3/models/tool_model.rb +262 -0
  196. data/lib/openc3/models/trigger_group_model.rb +186 -0
  197. data/lib/openc3/models/trigger_model.rb +330 -0
  198. data/lib/openc3/models/widget_model.rb +138 -0
  199. data/lib/openc3/operators/microservice_operator.rb +128 -0
  200. data/lib/openc3/operators/operator.rb +277 -0
  201. data/lib/openc3/packets/binary_accessor.rb +1207 -0
  202. data/lib/openc3/packets/commands.rb +373 -0
  203. data/lib/openc3/packets/json_packet.rb +134 -0
  204. data/lib/openc3/packets/limits.rb +271 -0
  205. data/lib/openc3/packets/limits_response.rb +53 -0
  206. data/lib/openc3/packets/packet.rb +1168 -0
  207. data/lib/openc3/packets/packet_config.rb +625 -0
  208. data/lib/openc3/packets/packet_item.rb +586 -0
  209. data/lib/openc3/packets/packet_item_limits.rb +162 -0
  210. data/lib/openc3/packets/parsers/format_string_parser.rb +65 -0
  211. data/lib/openc3/packets/parsers/limits_parser.rb +159 -0
  212. data/lib/openc3/packets/parsers/limits_response_parser.rb +61 -0
  213. data/lib/openc3/packets/parsers/packet_item_parser.rb +272 -0
  214. data/lib/openc3/packets/parsers/packet_parser.rb +134 -0
  215. data/lib/openc3/packets/parsers/processor_parser.rb +73 -0
  216. data/lib/openc3/packets/parsers/state_parser.rb +127 -0
  217. data/lib/openc3/packets/parsers/xtce_converter.rb +442 -0
  218. data/lib/openc3/packets/parsers/xtce_parser.rb +722 -0
  219. data/lib/openc3/packets/structure.rb +553 -0
  220. data/lib/openc3/packets/structure_item.rb +365 -0
  221. data/lib/openc3/packets/telemetry.rb +487 -0
  222. data/lib/openc3/processors/processor.rb +86 -0
  223. data/lib/openc3/processors/statistics_processor.rb +82 -0
  224. data/lib/openc3/processors/watermark_processor.rb +58 -0
  225. data/lib/openc3/processors.rb +24 -0
  226. data/lib/openc3/script/api_shared.rb +828 -0
  227. data/lib/openc3/script/calendar.rb +89 -0
  228. data/lib/openc3/script/commands.rb +227 -0
  229. data/lib/openc3/script/exceptions.rb +29 -0
  230. data/lib/openc3/script/extract.rb +161 -0
  231. data/lib/openc3/script/limits.rb +60 -0
  232. data/lib/openc3/script/script.rb +299 -0
  233. data/lib/openc3/script/script_runner.rb +238 -0
  234. data/lib/openc3/script/storage.rb +146 -0
  235. data/lib/openc3/script/suite.rb +542 -0
  236. data/lib/openc3/script/suite_results.rb +196 -0
  237. data/lib/openc3/script/suite_runner.rb +217 -0
  238. data/lib/openc3/script.rb +21 -0
  239. data/lib/openc3/streams/serial_stream.rb +167 -0
  240. data/lib/openc3/streams/stream.rb +63 -0
  241. data/lib/openc3/streams/tcpip_client_stream.rb +116 -0
  242. data/lib/openc3/streams/tcpip_socket_stream.rb +195 -0
  243. data/lib/openc3/system/system.rb +127 -0
  244. data/lib/openc3/system/system_config.rb +411 -0
  245. data/lib/openc3/system/target.rb +269 -0
  246. data/lib/openc3/system.rb +24 -0
  247. data/lib/openc3/tools/cmd_tlm_server/api.rb +20 -0
  248. data/lib/openc3/tools/cmd_tlm_server/cmd_tlm_server_config.rb +320 -0
  249. data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +294 -0
  250. data/lib/openc3/tools/table_manager/table.rb +77 -0
  251. data/lib/openc3/tools/table_manager/table_config.rb +273 -0
  252. data/lib/openc3/tools/table_manager/table_item.rb +90 -0
  253. data/lib/openc3/tools/table_manager/table_item_parser.rb +66 -0
  254. data/lib/openc3/tools/table_manager/table_manager_core.rb +333 -0
  255. data/lib/openc3/tools/table_manager/table_parser.rb +93 -0
  256. data/lib/openc3/tools/test_runner/test.rb +67 -0
  257. data/lib/openc3/top_level.rb +595 -0
  258. data/lib/openc3/topics/autonomic_topic.rb +52 -0
  259. data/lib/openc3/topics/calendar_topic.rb +44 -0
  260. data/lib/openc3/topics/command_decom_topic.rb +76 -0
  261. data/lib/openc3/topics/command_topic.rb +83 -0
  262. data/lib/openc3/topics/config_topic.rb +68 -0
  263. data/lib/openc3/topics/interface_topic.rb +73 -0
  264. data/lib/openc3/topics/limits_event_topic.rb +109 -0
  265. data/lib/openc3/topics/notifications_topic.rb +28 -0
  266. data/lib/openc3/topics/router_topic.rb +85 -0
  267. data/lib/openc3/topics/telemetry_decom_topic.rb +54 -0
  268. data/lib/openc3/topics/telemetry_topic.rb +36 -0
  269. data/lib/openc3/topics/timeline_topic.rb +45 -0
  270. data/lib/openc3/topics/topic.rb +53 -0
  271. data/lib/openc3/utilities/authentication.rb +141 -0
  272. data/lib/openc3/utilities/authorization.rb +51 -0
  273. data/lib/openc3/utilities/crc.rb +278 -0
  274. data/lib/openc3/utilities/csv.rb +153 -0
  275. data/lib/openc3/utilities/logger.rb +187 -0
  276. data/lib/openc3/utilities/message_log.rb +91 -0
  277. data/lib/openc3/utilities/metric.rb +141 -0
  278. data/lib/openc3/utilities/process_manager.rb +139 -0
  279. data/lib/openc3/utilities/quaternion.rb +257 -0
  280. data/lib/openc3/utilities/ruby_lex_utils.rb +568 -0
  281. data/lib/openc3/utilities/s3.rb +202 -0
  282. data/lib/openc3/utilities/s3_autoload.rb +9 -0
  283. data/lib/openc3/utilities/s3_file_cache.rb +274 -0
  284. data/lib/openc3/utilities/simulated_target.rb +117 -0
  285. data/lib/openc3/utilities/sleeper.rb +51 -0
  286. data/lib/openc3/utilities/store.rb +23 -0
  287. data/lib/openc3/utilities/store_autoload.rb +237 -0
  288. data/lib/openc3/utilities/zip.rb +21 -0
  289. data/lib/openc3/utilities.rb +35 -0
  290. data/lib/openc3/version.rb +14 -0
  291. data/lib/openc3/win32/excel.rb +132 -0
  292. data/lib/openc3/win32/win32.rb +402 -0
  293. data/lib/openc3/win32/win32_main.rb +333 -0
  294. data/lib/openc3.rb +49 -0
  295. data/tasks/gemfile_stats.rake +113 -0
  296. data/tasks/spec.rake +30 -0
  297. data/templates/plugin-template/README.md +15 -0
  298. data/templates/plugin-template/Rakefile +12 -0
  299. data/templates/plugin-template/plugin.gemspec +23 -0
  300. data/templates/plugin-template/plugin.txt +9 -0
  301. data/templates/plugin-template/targets/TARGET/cmd_tlm/cmd.txt +8 -0
  302. data/templates/plugin-template/targets/TARGET/cmd_tlm/tlm.txt +8 -0
  303. data/templates/plugin-template/targets/TARGET/lib/target.rb +10 -0
  304. data/templates/plugin-template/targets/TARGET/procedures/procedure.rb +3 -0
  305. data/templates/plugin-template/targets/TARGET/screens/status.txt +9 -0
  306. data/templates/plugin-template/targets/TARGET/target.txt +5 -0
  307. metadata +849 -0
@@ -0,0 +1,363 @@
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 2022, OpenC3, Inc.
18
+ # All Rights Reserved
19
+
20
+ require 'openc3/utilities/authentication'
21
+ require 'openc3/microservices/microservice'
22
+ require 'openc3/models/activity_model'
23
+ require 'openc3/models/notification_model'
24
+ require 'openc3/models/timeline_model'
25
+ require 'openc3/topics/timeline_topic'
26
+
27
+ require 'openc3/script'
28
+
29
+ module OpenC3
30
+ # The Timeline worker is a very simple thread pool worker. Once
31
+ # the timeline manager has pushed a job to the schedule one of
32
+ # these workers will run the CMD (command) or SCRIPT (script)
33
+ # or anything that could be expanded in the future.
34
+ class TimelineWorker
35
+ def initialize(name:, scope:, queue:)
36
+ @timeline_name = name
37
+ @scope = scope
38
+ @queue = queue
39
+ @authentication = generate_auth()
40
+ end
41
+
42
+ # generate the auth object
43
+ def generate_auth
44
+ if ENV['OPENC3_API_USER'].nil? || ENV['OPENC3_API_CLIENT'].nil?
45
+ return OpenC3Authentication.new()
46
+ else
47
+ return OpenC3KeycloakAuthentication.new(ENV['OPENC3_KEYCLOAK_URL'])
48
+ end
49
+ end
50
+
51
+ def run
52
+ Logger.info "#{@timeline_name} timeline worker running"
53
+ loop do
54
+ activity = @queue.pop
55
+ break if activity.nil?
56
+
57
+ run_activity(activity)
58
+ end
59
+ Logger.info "#{@timeline_name} timeine worker exiting"
60
+ end
61
+
62
+ def run_activity(activity)
63
+ case activity.kind.upcase
64
+ when 'COMMAND'
65
+ run_command(activity)
66
+ when 'SCRIPT'
67
+ run_script(activity)
68
+ when 'EXPIRE'
69
+ clear_expired(activity)
70
+ else
71
+ Logger.error "Unknown kind passed to microservice #{@timeline_name}: #{activity.as_json(:allow_nan => true)}"
72
+ end
73
+ end
74
+
75
+ def run_command(activity)
76
+ Logger.info "#{@timeline_name} run_command > #{activity.as_json(:allow_nan => true)}"
77
+ begin
78
+ cmd_no_hazardous_check(activity.data['command'], scope: @scope)
79
+ activity.commit(status: 'completed', fulfillment: true)
80
+ rescue StandardError => e
81
+ activity.commit(status: 'failed', message: e.message)
82
+ Logger.error "#{@timeline_name} run_cmd failed > #{activity.as_json(:allow_nan => true)}, #{e.message}"
83
+ end
84
+ end
85
+
86
+ def run_script(activity)
87
+ Logger.info "#{@timeline_name} run_script > #{activity.as_json(:allow_nan => true)}"
88
+ begin
89
+ request = Net::HTTP::Post.new(
90
+ "/script-api/scripts/#{activity.data['script']}/run?scope=#{@scope}",
91
+ 'Content-Type' => 'application/json',
92
+ 'Authorization' => @authentication.token()
93
+ )
94
+ request.body = JSON.generate({
95
+ 'scope' => @scope,
96
+ 'environment' => activity.data['environment'],
97
+ 'timeline' => @timeline_name,
98
+ 'id' => activity.start
99
+ })
100
+ hostname = ENV['OPENC3_SCRIPT_HOSTNAME'] || 'openc3-script-runner-api'
101
+ response = Net::HTTP.new(hostname, 2902).request(request)
102
+ raise "failed to call #{hostname}, for script: #{activity.data['script']}, response code: #{response.code}" if response.code != '200'
103
+
104
+ activity.commit(status: 'completed', message: "#{activity.data['script']} => #{response.body}", fulfillment: true)
105
+ rescue StandardError => e
106
+ activity.commit(status: 'failed', message: e.message)
107
+ Logger.error "#{@timeline_name} run_script failed > #{activity.as_json(:allow_nan => true).to_s}, #{e.message}"
108
+ end
109
+ end
110
+
111
+ def clear_expired(activity)
112
+ begin
113
+ ActivityModel.range_destroy(name: @timeline_name, scope: @scope, min: activity.start, max: activity.stop)
114
+ activity.add_event(status: 'completed')
115
+ rescue StandardError => e
116
+ Logger.error "#{@timeline_name} clear_expired failed > #{activity.as_json(:allow_nan => true)} #{e.message}"
117
+ end
118
+ end
119
+ end
120
+
121
+ # Shared between the monitor thread and the manager thread to
122
+ # share the planned activities. This should remain a thread
123
+ # safe implamentation.
124
+ class Schedule
125
+ def initialize(name)
126
+ @name = name
127
+ @activities_mutex = Mutex.new
128
+ @activities = []
129
+ @size = 20
130
+ @queue = Array.new(@size)
131
+ @index = 0
132
+ end
133
+
134
+ def not_queued?(start)
135
+ return false if @queue.index(start)
136
+
137
+ @queue[@index] = start
138
+ @index = @index + 1 >= @size ? 0 : @index + 1
139
+ return true
140
+ end
141
+
142
+ def activities
143
+ @activities_mutex.synchronize do
144
+ return @activities.dup
145
+ end
146
+ end
147
+
148
+ def update(input_activities)
149
+ @activities_mutex.synchronize do
150
+ @activities = input_activities.dup
151
+ end
152
+ end
153
+
154
+ def add_activity(input_activity)
155
+ @activities_mutex.synchronize do
156
+ if @activities.find { |x| x.start == input_activity.start }.nil?
157
+ @activities << input_activity
158
+ end
159
+ end
160
+ end
161
+
162
+ def remove_activity(input_activity)
163
+ @activities_mutex.synchronize do
164
+ @activities.delete_if { |h| h.start == input_activity.start }
165
+ end
166
+ end
167
+ end
168
+
169
+ # The timeline manager starts a thread pool and looks at the
170
+ # schedule and if an "activity" should be run. TimelineManager
171
+ # adds the "activity" to the thread pool and the thread will
172
+ # execute the "activity".
173
+ class TimelineManager
174
+ def initialize(name:, scope:, schedule:)
175
+ @timeline_name = name
176
+ @scope = scope
177
+ @schedule = schedule
178
+ @worker_count = 3
179
+ @queue = Queue.new
180
+ @thread_pool = generate_thread_pool()
181
+ @cancel_thread = false
182
+ @expire = 0
183
+ end
184
+
185
+ def generate_thread_pool
186
+ thread_pool = []
187
+ @worker_count.times {
188
+ worker = TimelineWorker.new(name: @timeline_name, scope: @scope, queue: @queue)
189
+ thread_pool << Thread.new { worker.run }
190
+ }
191
+ return thread_pool
192
+ end
193
+
194
+ def run
195
+ Logger.info "#{@timeline_name} timeline manager running"
196
+ loop do
197
+ start = Time.now.to_i
198
+ @schedule.activities.each do |activity|
199
+ start_difference = activity.start - start
200
+ if start_difference <= 0 && @schedule.not_queued?(activity.start)
201
+ Logger.debug "#{@timeline_name} #{@scope} current start: #{start}, vs #{activity.start}, #{start_difference}"
202
+ activity.add_event(status: 'queued')
203
+ @queue << activity
204
+ end
205
+ end
206
+ if start >= @expire
207
+ add_expire_activity()
208
+ request_update(start: start)
209
+ end
210
+ break if @cancel_thread
211
+
212
+ sleep(1)
213
+ break if @cancel_thread
214
+ end
215
+ Logger.info "#{@timeline_name} timeine manager exiting"
216
+ end
217
+
218
+ # Add task to remove events older than 7 time
219
+ def add_expire_activity
220
+ now = Time.now.to_i
221
+ @expire = now + 3_000
222
+ activity = ActivityModel.new(
223
+ name: @timeline_name,
224
+ scope: @scope,
225
+ start: (now - 86_400 * 7),
226
+ stop: (now - 82_800 * 7),
227
+ kind: 'EXPIRE',
228
+ data: {}
229
+ )
230
+ @queue << activity
231
+ return activity
232
+ end
233
+
234
+ # This can feedback to ensure the schedule will not run out so this should fire once an
235
+ # hour to make sure the TimelineMicroservice will collect the next hour and update the
236
+ # schedule.
237
+ def request_update(start:)
238
+ notification = {
239
+ 'data' => JSON.generate({ 'time' => start }),
240
+ 'kind' => 'refresh',
241
+ 'type' => 'timeline',
242
+ 'timeline' => @timeline_name
243
+ }
244
+ begin
245
+ TimelineTopic.write_activity(notification, scope: @scope)
246
+ rescue StandardError
247
+ Logger.error "#{@name} manager failed to request update"
248
+ end
249
+ end
250
+
251
+ def shutdown
252
+ @cancel_thread = true
253
+ @worker_count.times {
254
+ @queue << nil
255
+ }
256
+ end
257
+ end
258
+
259
+ # The timeline microservice starts a manager then gets the activities
260
+ # from the sorted set in redis and updates the schedule for the
261
+ # manager. Timeline will then wait for an update on the timeline
262
+ # stream this will trigger an update again to the schedule.
263
+ class TimelineMicroservice < Microservice
264
+ TIMELINE_METRIC_NAME = 'timeline_activities_duration_seconds'.freeze
265
+
266
+ def initialize(name)
267
+ super(name)
268
+ @timeline_name = name.split('__')[2]
269
+ @schedule = Schedule.new(@timeline_name)
270
+ @manager = TimelineManager.new(name: @timeline_name, scope: scope, schedule: @schedule)
271
+ @manager_thread = nil
272
+ @read_topic = true
273
+ end
274
+
275
+ def run
276
+ Logger.info "#{@name} timeine running"
277
+ @manager_thread = Thread.new { @manager.run }
278
+ loop do
279
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
280
+ current_activities = ActivityModel.activities(name: @timeline_name, scope: @scope)
281
+ @schedule.update(current_activities)
282
+ diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
283
+ metric_labels = { 'timeline' => @timeline_name, 'thread' => 'microservice' }
284
+ @metric.add_sample(name: TIMELINE_METRIC_NAME, value: diff, labels: metric_labels)
285
+ break if @cancel_thread
286
+
287
+ block_for_updates()
288
+ break if @cancel_thread
289
+ end
290
+ Logger.info "#{@name} timeine exitting"
291
+ end
292
+
293
+ def topic_lookup_functions
294
+ {
295
+ 'timeline' => {
296
+ 'created' => :timeline_nop,
297
+ 'refresh' => :schedule_refresh,
298
+ 'updated' => :timeline_nop,
299
+ 'deleted' => :timeline_nop
300
+ },
301
+ 'activity' => {
302
+ 'event' => :timeline_nop,
303
+ 'created' => :create_activity_from_event,
304
+ 'updated' => :schedule_refresh,
305
+ 'deleted' => :remove_activity_from_event
306
+ }
307
+ }
308
+ end
309
+
310
+ def block_for_updates
311
+ @read_topic = true
312
+ while @read_topic
313
+ begin
314
+ TimelineTopic.read_topics(@topics) do |_topic, _msg_id, msg_hash, _redis|
315
+ if msg_hash['timeline'] == @timeline_name
316
+ data = JSON.parse(msg_hash['data'], :allow_nan => true, :create_additions => true)
317
+ public_send(topic_lookup_functions[msg_hash['type']][msg_hash['kind']], data)
318
+ end
319
+ end
320
+ rescue StandardError => e
321
+ Logger.error "#{@timeline_name} failed to read topics #{@topics}\n#{e.formatted}"
322
+ end
323
+ end
324
+ end
325
+
326
+ def timeline_nop(data)
327
+ Logger.debug "#{@name} timeline web socket event: #{data}"
328
+ end
329
+
330
+ def schedule_refresh(data)
331
+ Logger.debug "#{@name} timeline web socket schedule refresh: #{data}"
332
+ @read_topic = false
333
+ end
334
+
335
+ # Add the activity to the schedule. We don't need to hold the job in memory
336
+ # if it is longer than an hour away. A refresh task will update that.
337
+ def create_activity_from_event(data)
338
+ diff = data['start'] - Time.now.to_i
339
+ return unless (2..3600).include? diff
340
+
341
+ activity = ActivityModel.from_json(data, name: @timeline_name, scope: @scope)
342
+ @schedule.add_activity(activity)
343
+ end
344
+
345
+ # Remove the activity from the schedule. We don't need to remove the activity
346
+ # if it is longer than an hour away. It will be removed from the data.
347
+ def remove_activity_from_event(data)
348
+ diff = data['start'] - Time.now.to_i
349
+ return unless (2..3600).include? diff
350
+
351
+ activity = ActivityModel.from_json(data, name: @timeline_name, scope: @scope)
352
+ @schedule.remove_activity(activity)
353
+ end
354
+
355
+ def shutdown
356
+ @read_topic = false
357
+ @manager.shutdown
358
+ super
359
+ end
360
+ end
361
+ end
362
+
363
+ OpenC3::TimelineMicroservice.run if __FILE__ == $0