openc3 7.3.0 → 7.4.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.
Files changed (499) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Guardfile +0 -0
  4. data/LICENSE.md +0 -0
  5. data/README.md +0 -0
  6. data/Rakefile +0 -0
  7. data/bin/openc3cli +138 -0
  8. data/bin/pipuninstall +0 -0
  9. data/bin/uvinstall +10 -3
  10. data/data/config/_array_params.yaml +0 -0
  11. data/data/config/_canvas_values.yaml +0 -0
  12. data/data/config/_graph_params.yaml +0 -0
  13. data/data/config/_id_items.yaml +0 -0
  14. data/data/config/_id_params.yaml +0 -0
  15. data/data/config/_interfaces.yaml +0 -0
  16. data/data/config/_items.yaml +0 -0
  17. data/data/config/_params.yaml +0 -0
  18. data/data/config/command.yaml +0 -0
  19. data/data/config/command_modifiers.yaml +2 -0
  20. data/data/config/command_telemetry.yaml +0 -0
  21. data/data/config/conversions.yaml +0 -0
  22. data/data/config/graph_settings.yaml +0 -0
  23. data/data/config/interface_modifiers.yaml +103 -1
  24. data/data/config/item_modifiers.yaml +0 -0
  25. data/data/config/microservice.yaml +5 -2
  26. data/data/config/param_item_modifiers.yaml +0 -0
  27. data/data/config/parameter_modifiers.yaml +0 -0
  28. data/data/config/plugins.yaml +0 -0
  29. data/data/config/processors.yaml +0 -0
  30. data/data/config/protocols.yaml +0 -0
  31. data/data/config/screen.yaml +0 -0
  32. data/data/config/settings.yaml +0 -0
  33. data/data/config/table_manager.yaml +0 -0
  34. data/data/config/table_parameter_modifiers.yaml +0 -0
  35. data/data/config/target.yaml +0 -0
  36. data/data/config/target_config.yaml +0 -0
  37. data/data/config/telemetry.yaml +0 -0
  38. data/data/config/telemetry_modifiers.yaml +2 -0
  39. data/data/config/tool.yaml +0 -0
  40. data/data/config/unknown.yaml +0 -0
  41. data/data/config/widgets.yaml +6 -0
  42. data/data/xtce_schemas/SpaceSystem_20180204.xsd +0 -0
  43. data/data/xtce_schemas/xml.xsd +0 -0
  44. data/ext/openc3/ext/array/array.c +0 -0
  45. data/ext/openc3/ext/array/extconf.rb +0 -0
  46. data/ext/openc3/ext/buffered_file/buffered_file.c +0 -0
  47. data/ext/openc3/ext/buffered_file/extconf.rb +0 -0
  48. data/ext/openc3/ext/burst_protocol/burst_protocol.c +6 -0
  49. data/ext/openc3/ext/burst_protocol/extconf.rb +0 -0
  50. data/ext/openc3/ext/config_parser/config_parser.c +0 -0
  51. data/ext/openc3/ext/config_parser/extconf.rb +0 -0
  52. data/ext/openc3/ext/crc/crc.c +0 -0
  53. data/ext/openc3/ext/crc/extconf.rb +0 -0
  54. data/ext/openc3/ext/openc3_io/extconf.rb +0 -0
  55. data/ext/openc3/ext/openc3_io/openc3_io.c +0 -0
  56. data/ext/openc3/ext/packet/extconf.rb +0 -0
  57. data/ext/openc3/ext/packet/packet.c +0 -0
  58. data/ext/openc3/ext/platform/extconf.rb +0 -0
  59. data/ext/openc3/ext/platform/platform.c +4 -1
  60. data/ext/openc3/ext/polynomial_conversion/extconf.rb +0 -0
  61. data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +0 -0
  62. data/ext/openc3/ext/string/extconf.rb +0 -0
  63. data/ext/openc3/ext/string/string.c +0 -0
  64. data/ext/openc3/ext/structure/structure.c +49 -17
  65. data/ext/openc3/ext/tabbed_plots_config/extconf.rb +0 -0
  66. data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +0 -0
  67. data/ext/openc3/ext/telemetry/extconf.rb +0 -0
  68. data/ext/openc3/ext/telemetry/telemetry.c +0 -0
  69. data/lib/cosmos.rb +0 -0
  70. data/lib/cosmosc2.rb +0 -0
  71. data/lib/openc3/accessors/accessor.rb +0 -0
  72. data/lib/openc3/accessors/binary_accessor.rb +63 -9
  73. data/lib/openc3/accessors/cbor_accessor.rb +0 -0
  74. data/lib/openc3/accessors/form_accessor.rb +0 -0
  75. data/lib/openc3/accessors/html_accessor.rb +0 -0
  76. data/lib/openc3/accessors/http_accessor.rb +0 -0
  77. data/lib/openc3/accessors/json_accessor.rb +0 -0
  78. data/lib/openc3/accessors/template_accessor.rb +0 -0
  79. data/lib/openc3/accessors/xml_accessor.rb +0 -0
  80. data/lib/openc3/accessors.rb +0 -0
  81. data/lib/openc3/api/README.md +0 -0
  82. data/lib/openc3/api/api.rb +0 -0
  83. data/lib/openc3/api/authorized_api.rb +0 -0
  84. data/lib/openc3/api/calendar_api.rb +0 -0
  85. data/lib/openc3/api/cmd_api.rb +1 -1
  86. data/lib/openc3/api/config_api.rb +0 -0
  87. data/lib/openc3/api/interface_api.rb +0 -0
  88. data/lib/openc3/api/limits_api.rb +0 -0
  89. data/lib/openc3/api/metrics_api.rb +1 -1
  90. data/lib/openc3/api/offline_access_api.rb +1 -1
  91. data/lib/openc3/api/router_api.rb +0 -0
  92. data/lib/openc3/api/settings_api.rb +22 -18
  93. data/lib/openc3/api/stash_api.rb +1 -1
  94. data/lib/openc3/api/target_api.rb +0 -0
  95. data/lib/openc3/api/tlm_api.rb +4 -3
  96. data/lib/openc3/bridge/bridge.rb +0 -0
  97. data/lib/openc3/bridge/bridge_config.rb +0 -0
  98. data/lib/openc3/bridge/bridge_interface_thread.rb +0 -0
  99. data/lib/openc3/bridge/bridge_router_thread.rb +0 -0
  100. data/lib/openc3/ccsds/ccsds_packet.rb +0 -0
  101. data/lib/openc3/ccsds/ccsds_parser.rb +0 -0
  102. data/lib/openc3/config/config_parser.rb +78 -17
  103. data/lib/openc3/config/meta_config_parser.rb +0 -0
  104. data/lib/openc3/conversions/bit_reverse_conversion.rb +0 -0
  105. data/lib/openc3/conversions/conversion.rb +0 -0
  106. data/lib/openc3/conversions/generic_conversion.rb +0 -0
  107. data/lib/openc3/conversions/ip_read_conversion.rb +0 -0
  108. data/lib/openc3/conversions/ip_write_conversion.rb +0 -0
  109. data/lib/openc3/conversions/object_read_conversion.rb +0 -0
  110. data/lib/openc3/conversions/object_write_conversion.rb +0 -0
  111. data/lib/openc3/conversions/packet_time_formatted_conversion.rb +0 -0
  112. data/lib/openc3/conversions/packet_time_seconds_conversion.rb +0 -0
  113. data/lib/openc3/conversions/polynomial_conversion.rb +0 -0
  114. data/lib/openc3/conversions/processor_conversion.rb +0 -0
  115. data/lib/openc3/conversions/received_count_conversion.rb +0 -0
  116. data/lib/openc3/conversions/received_time_formatted_conversion.rb +0 -0
  117. data/lib/openc3/conversions/received_time_seconds_conversion.rb +0 -0
  118. data/lib/openc3/conversions/segmented_polynomial_conversion.rb +0 -0
  119. data/lib/openc3/conversions/unix_time_conversion.rb +0 -0
  120. data/lib/openc3/conversions/unix_time_formatted_conversion.rb +0 -0
  121. data/lib/openc3/conversions/unix_time_seconds_conversion.rb +0 -0
  122. data/lib/openc3/conversions.rb +0 -0
  123. data/lib/openc3/core_ext/array.rb +0 -0
  124. data/lib/openc3/core_ext/binding.rb +0 -0
  125. data/lib/openc3/core_ext/class.rb +0 -0
  126. data/lib/openc3/core_ext/exception.rb +0 -0
  127. data/lib/openc3/core_ext/faraday.rb +0 -0
  128. data/lib/openc3/core_ext/file.rb +0 -0
  129. data/lib/openc3/core_ext/io.rb +0 -0
  130. data/lib/openc3/core_ext/kernel.rb +0 -0
  131. data/lib/openc3/core_ext/math.rb +0 -0
  132. data/lib/openc3/core_ext/matrix.rb +0 -0
  133. data/lib/openc3/core_ext/objectspace.rb +0 -0
  134. data/lib/openc3/core_ext/openc3_io.rb +0 -0
  135. data/lib/openc3/core_ext/range.rb +0 -0
  136. data/lib/openc3/core_ext/socket.rb +0 -0
  137. data/lib/openc3/core_ext/string.rb +0 -0
  138. data/lib/openc3/core_ext/stringio.rb +0 -0
  139. data/lib/openc3/core_ext/tempfile.rb +0 -0
  140. data/lib/openc3/core_ext/time.rb +0 -0
  141. data/lib/openc3/core_ext.rb +0 -0
  142. data/lib/openc3/ext/.keep +0 -0
  143. data/lib/openc3/interfaces/file_interface.rb +0 -0
  144. data/lib/openc3/interfaces/http_client_interface.rb +0 -0
  145. data/lib/openc3/interfaces/http_server_interface.rb +0 -0
  146. data/lib/openc3/interfaces/interface.rb +5 -4
  147. data/lib/openc3/interfaces/mqtt_interface.rb +0 -0
  148. data/lib/openc3/interfaces/mqtt_stream_interface.rb +2 -0
  149. data/lib/openc3/interfaces/protocols/burst_protocol.rb +27 -0
  150. data/lib/openc3/interfaces/protocols/cmd_response_protocol.rb +0 -0
  151. data/lib/openc3/interfaces/protocols/cobs_protocol.rb +0 -0
  152. data/lib/openc3/interfaces/protocols/crc_protocol.rb +0 -0
  153. data/lib/openc3/interfaces/protocols/fixed_protocol.rb +0 -0
  154. data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +0 -0
  155. data/lib/openc3/interfaces/protocols/length_protocol.rb +7 -0
  156. data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +7 -0
  157. data/lib/openc3/interfaces/protocols/protocol.rb +4 -4
  158. data/lib/openc3/interfaces/protocols/slip_protocol.rb +0 -0
  159. data/lib/openc3/interfaces/protocols/template_protocol.rb +2 -2
  160. data/lib/openc3/interfaces/protocols/terminated_protocol.rb +0 -0
  161. data/lib/openc3/interfaces/serial_interface.rb +2 -0
  162. data/lib/openc3/interfaces/simulated_target_interface.rb +0 -0
  163. data/lib/openc3/interfaces/stream_interface.rb +0 -0
  164. data/lib/openc3/interfaces/tcpip_client_interface.rb +2 -0
  165. data/lib/openc3/interfaces/tcpip_server_interface.rb +0 -0
  166. data/lib/openc3/interfaces/udp_interface.rb +16 -5
  167. data/lib/openc3/interfaces.rb +0 -0
  168. data/lib/openc3/io/buffered_file.rb +0 -0
  169. data/lib/openc3/io/io_multiplexer.rb +0 -0
  170. data/lib/openc3/io/json_api.rb +3 -2
  171. data/lib/openc3/io/json_api_object.rb +0 -0
  172. data/lib/openc3/io/json_drb.rb +20 -4
  173. data/lib/openc3/io/json_drb_object.rb +0 -0
  174. data/lib/openc3/io/json_drb_rack.rb +0 -0
  175. data/lib/openc3/io/json_rpc.rb +0 -0
  176. data/lib/openc3/io/posix_serial_driver.rb +0 -0
  177. data/lib/openc3/io/serial_driver.rb +0 -0
  178. data/lib/openc3/io/stderr.rb +0 -0
  179. data/lib/openc3/io/stdout.rb +0 -0
  180. data/lib/openc3/io/udp_sockets.rb +38 -8
  181. data/lib/openc3/io/win32_serial_driver.rb +1 -0
  182. data/lib/openc3/logs/buffered_packet_log_reader.rb +0 -0
  183. data/lib/openc3/logs/buffered_packet_log_writer.rb +0 -0
  184. data/lib/openc3/logs/log_writer.rb +0 -0
  185. data/lib/openc3/logs/packet_log_constants.rb +0 -0
  186. data/lib/openc3/logs/packet_log_reader.rb +23 -2
  187. data/lib/openc3/logs/packet_log_writer.rb +5 -0
  188. data/lib/openc3/logs/stream_log.rb +1 -1
  189. data/lib/openc3/logs/stream_log_pair.rb +0 -0
  190. data/lib/openc3/logs/text_log_writer.rb +0 -0
  191. data/lib/openc3/logs.rb +0 -0
  192. data/lib/openc3/microservices/cleanup_microservice.rb +0 -0
  193. data/lib/openc3/microservices/decom_common.rb +0 -0
  194. data/lib/openc3/microservices/decom_microservice.rb +0 -0
  195. data/lib/openc3/microservices/interface_decom_common.rb +2 -1
  196. data/lib/openc3/microservices/interface_microservice.rb +72 -25
  197. data/lib/openc3/microservices/log_microservice.rb +0 -0
  198. data/lib/openc3/microservices/microservice.rb +3 -3
  199. data/lib/openc3/microservices/multi_microservice.rb +1 -1
  200. data/lib/openc3/microservices/periodic_microservice.rb +2 -2
  201. data/lib/openc3/microservices/plugin_microservice.rb +0 -0
  202. data/lib/openc3/microservices/queue_microservice.rb +0 -0
  203. data/lib/openc3/microservices/router_microservice.rb +0 -0
  204. data/lib/openc3/microservices/scope_cleanup_microservice.rb +0 -0
  205. data/lib/openc3/microservices/text_log_microservice.rb +0 -0
  206. data/lib/openc3/migrations/20220420190000_log_stuff.rb +0 -0
  207. data/lib/openc3/migrations/20221202214600_add_target_names.rb +0 -0
  208. data/lib/openc3/migrations/20221210174900_convert_to_multi.rb +0 -0
  209. data/lib/openc3/migrations/20230915000002_no_scope_log_messages.rb +0 -0
  210. data/lib/openc3/migrations/20231022000000_tlm_viewer_config.rb +0 -0
  211. data/lib/openc3/migrations/20241208080000_no_critical_cmd.rb +0 -0
  212. data/lib/openc3/migrations/20241208080001_no_trigger_group.rb +0 -0
  213. data/lib/openc3/migrations/20250108060000_news_feed.rb +0 -0
  214. data/lib/openc3/migrations/20250402000000_periodic_only_default.rb +0 -0
  215. data/lib/openc3/migrations/20260203000000_remove_store_id.rb +0 -0
  216. data/lib/openc3/migrations/20260204000000_remove_decom_reducer.rb +0 -0
  217. data/lib/openc3/migrations/20260701000000_updated_at_to_int.rb +0 -0
  218. data/lib/openc3/migrations/20260704000000_default_bridge.rb +38 -0
  219. data/lib/openc3/migrations/20260731000000_system_health_json.rb +11 -0
  220. data/lib/openc3/models/activity_model.rb +0 -0
  221. data/lib/openc3/models/auth_model.rb +35 -7
  222. data/lib/openc3/models/bridge_model.rb +133 -0
  223. data/lib/openc3/models/config_keyword_model.rb +63 -0
  224. data/lib/openc3/models/cvt_model.rb +0 -0
  225. data/lib/openc3/models/db_sharded_model.rb +0 -0
  226. data/lib/openc3/models/environment_model.rb +0 -0
  227. data/lib/openc3/models/gem_model.rb +12 -9
  228. data/lib/openc3/models/host_interface_microservice_model.rb +114 -0
  229. data/lib/openc3/models/info_model.rb +0 -0
  230. data/lib/openc3/models/interface_model.rb +178 -19
  231. data/lib/openc3/models/interface_status_model.rb +0 -0
  232. data/lib/openc3/models/metadata_model.rb +0 -0
  233. data/lib/openc3/models/metric_model.rb +0 -0
  234. data/lib/openc3/models/microservice_model.rb +9 -22
  235. data/lib/openc3/models/microservice_status_model.rb +0 -0
  236. data/lib/openc3/models/migration_model.rb +0 -0
  237. data/lib/openc3/models/model.rb +0 -0
  238. data/lib/openc3/models/news_model.rb +0 -0
  239. data/lib/openc3/models/note_model.rb +0 -0
  240. data/lib/openc3/models/offline_access_model.rb +0 -0
  241. data/lib/openc3/models/ping_model.rb +0 -0
  242. data/lib/openc3/models/plugin_model.rb +9 -2
  243. data/lib/openc3/models/plugin_store_model.rb +0 -0
  244. data/lib/openc3/models/process_status_model.rb +0 -0
  245. data/lib/openc3/models/python_package_model.rb +4 -4
  246. data/lib/openc3/models/queue_model.rb +0 -0
  247. data/lib/openc3/models/reaction_model.rb +0 -0
  248. data/lib/openc3/models/reingest_job_model.rb +0 -0
  249. data/lib/openc3/models/router_model.rb +0 -0
  250. data/lib/openc3/models/router_status_model.rb +0 -0
  251. data/lib/openc3/models/scope_model.rb +51 -26
  252. data/lib/openc3/models/script_engine_model.rb +0 -0
  253. data/lib/openc3/models/script_status_model.rb +0 -0
  254. data/lib/openc3/models/secret_model.rb +0 -0
  255. data/lib/openc3/models/setting_model.rb +546 -3
  256. data/lib/openc3/models/sorted_model.rb +0 -0
  257. data/lib/openc3/models/stash_model.rb +0 -0
  258. data/lib/openc3/models/target_model.rb +30 -25
  259. data/lib/openc3/models/timeline_model.rb +0 -0
  260. data/lib/openc3/models/tool_config_model.rb +0 -0
  261. data/lib/openc3/models/tool_model.rb +1 -0
  262. data/lib/openc3/models/trigger_group_model.rb +0 -0
  263. data/lib/openc3/models/trigger_model.rb +20 -0
  264. data/lib/openc3/models/widget_model.rb +0 -0
  265. data/lib/openc3/operators/microservice_operator.rb +64 -22
  266. data/lib/openc3/operators/operator.rb +4 -4
  267. data/lib/openc3/packets/binary_accessor.rb +0 -0
  268. data/lib/openc3/packets/command_validator.rb +0 -0
  269. data/lib/openc3/packets/commands.rb +0 -0
  270. data/lib/openc3/packets/json_packet.rb +0 -0
  271. data/lib/openc3/packets/limits.rb +0 -0
  272. data/lib/openc3/packets/limits_response.rb +0 -0
  273. data/lib/openc3/packets/packet.rb +4 -0
  274. data/lib/openc3/packets/packet_config.rb +0 -0
  275. data/lib/openc3/packets/packet_item.rb +0 -0
  276. data/lib/openc3/packets/packet_item_limits.rb +0 -0
  277. data/lib/openc3/packets/parsers/format_string_parser.rb +0 -0
  278. data/lib/openc3/packets/parsers/limits_parser.rb +0 -0
  279. data/lib/openc3/packets/parsers/limits_response_parser.rb +0 -0
  280. data/lib/openc3/packets/parsers/packet_item_parser.rb +0 -0
  281. data/lib/openc3/packets/parsers/packet_parser.rb +0 -0
  282. data/lib/openc3/packets/parsers/processor_parser.rb +0 -0
  283. data/lib/openc3/packets/parsers/state_parser.rb +0 -0
  284. data/lib/openc3/packets/parsers/xtce_converter.rb +0 -0
  285. data/lib/openc3/packets/parsers/xtce_parser.rb +0 -0
  286. data/lib/openc3/packets/structure.rb +7 -1
  287. data/lib/openc3/packets/structure_item.rb +0 -0
  288. data/lib/openc3/packets/telemetry.rb +0 -0
  289. data/lib/openc3/processors/processor.rb +2 -0
  290. data/lib/openc3/processors/statistics_processor.rb +0 -0
  291. data/lib/openc3/processors/watermark_processor.rb +0 -0
  292. data/lib/openc3/processors.rb +0 -0
  293. data/lib/openc3/script/api_shared.rb +0 -0
  294. data/lib/openc3/script/autonomic.rb +12 -12
  295. data/lib/openc3/script/calendar.rb +0 -0
  296. data/lib/openc3/script/commands.rb +0 -0
  297. data/lib/openc3/script/critical_cmd.rb +0 -0
  298. data/lib/openc3/script/exceptions.rb +0 -0
  299. data/lib/openc3/script/extract.rb +0 -0
  300. data/lib/openc3/script/limits.rb +0 -0
  301. data/lib/openc3/script/metadata.rb +0 -0
  302. data/lib/openc3/script/packages.rb +0 -0
  303. data/lib/openc3/script/plugins.rb +0 -0
  304. data/lib/openc3/script/queue.rb +0 -0
  305. data/lib/openc3/script/screen.rb +0 -0
  306. data/lib/openc3/script/script.rb +2 -2
  307. data/lib/openc3/script/script_runner.rb +0 -0
  308. data/lib/openc3/script/storage.rb +4 -4
  309. data/lib/openc3/script/suite.rb +0 -0
  310. data/lib/openc3/script/suite_results.rb +0 -0
  311. data/lib/openc3/script/suite_runner.rb +26 -0
  312. data/lib/openc3/script/tables.rb +0 -0
  313. data/lib/openc3/script/telemetry.rb +9 -3
  314. data/lib/openc3/script/web_socket_api.rb +218 -145
  315. data/lib/openc3/script.rb +0 -0
  316. data/lib/openc3/script_engines/script_engine.rb +0 -0
  317. data/lib/openc3/streams/mqtt_stream.rb +0 -0
  318. data/lib/openc3/streams/serial_stream.rb +0 -0
  319. data/lib/openc3/streams/stream.rb +0 -0
  320. data/lib/openc3/streams/tcpip_client_stream.rb +0 -0
  321. data/lib/openc3/streams/tcpip_socket_stream.rb +0 -0
  322. data/lib/openc3/streams/web_socket_client_stream.rb +0 -0
  323. data/lib/openc3/subpacketizers/subpacketizer.rb +0 -0
  324. data/lib/openc3/system/system.rb +0 -0
  325. data/lib/openc3/system/target.rb +0 -0
  326. data/lib/openc3/system.rb +0 -0
  327. data/lib/openc3/tools/cmd_tlm_server/api.rb +0 -0
  328. data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +7 -0
  329. data/lib/openc3/tools/table_manager/table.rb +0 -0
  330. data/lib/openc3/tools/table_manager/table_config.rb +0 -0
  331. data/lib/openc3/tools/table_manager/table_item.rb +0 -0
  332. data/lib/openc3/tools/table_manager/table_item_parser.rb +0 -0
  333. data/lib/openc3/tools/table_manager/table_manager_core.rb +0 -0
  334. data/lib/openc3/tools/table_manager/table_parser.rb +0 -0
  335. data/lib/openc3/tools/test_runner/test.rb +0 -0
  336. data/lib/openc3/top_level.rb +1 -1
  337. data/lib/openc3/topics/autonomic_topic.rb +0 -0
  338. data/lib/openc3/topics/calendar_topic.rb +0 -0
  339. data/lib/openc3/topics/command_decom_topic.rb +0 -0
  340. data/lib/openc3/topics/command_topic.rb +0 -0
  341. data/lib/openc3/topics/config_topic.rb +0 -0
  342. data/lib/openc3/topics/decom_interface_topic.rb +2 -1
  343. data/lib/openc3/topics/interface_topic.rb +8 -2
  344. data/lib/openc3/topics/limits_event_topic.rb +0 -0
  345. data/lib/openc3/topics/notebook_topic.rb +0 -0
  346. data/lib/openc3/topics/queue_topic.rb +0 -0
  347. data/lib/openc3/topics/router_topic.rb +6 -1
  348. data/lib/openc3/topics/system_events_topic.rb +0 -0
  349. data/lib/openc3/topics/telemetry_decom_topic.rb +0 -0
  350. data/lib/openc3/topics/telemetry_topic.rb +0 -0
  351. data/lib/openc3/topics/timeline_topic.rb +0 -0
  352. data/lib/openc3/topics/topic.rb +0 -0
  353. data/lib/openc3/utilities/authentication.rb +4 -4
  354. data/lib/openc3/utilities/authorization.rb +0 -0
  355. data/lib/openc3/utilities/aws_bucket.rb +2 -2
  356. data/lib/openc3/utilities/bucket.rb +1 -1
  357. data/lib/openc3/utilities/bucket_file_cache.rb +55 -22
  358. data/lib/openc3/utilities/bucket_require.rb +0 -0
  359. data/lib/openc3/utilities/bucket_utilities.rb +3 -4
  360. data/lib/openc3/utilities/cli_generator.rb +0 -0
  361. data/lib/openc3/utilities/cmd_log.rb +0 -0
  362. data/lib/openc3/utilities/config_overlay.rb +75 -0
  363. data/lib/openc3/utilities/cosmos_rails_formatter.rb +0 -0
  364. data/lib/openc3/utilities/crc.rb +59 -32
  365. data/lib/openc3/utilities/csv.rb +0 -0
  366. data/lib/openc3/utilities/ctrf.rb +0 -0
  367. data/lib/openc3/utilities/env_helper.rb +0 -0
  368. data/lib/openc3/utilities/local_bucket.rb +0 -0
  369. data/lib/openc3/utilities/local_mode.rb +32 -6
  370. data/lib/openc3/utilities/logger.rb +30 -8
  371. data/lib/openc3/utilities/message_log.rb +0 -0
  372. data/lib/openc3/utilities/metric.rb +0 -0
  373. data/lib/openc3/utilities/migration.rb +0 -0
  374. data/lib/openc3/utilities/open_telemetry.rb +0 -0
  375. data/lib/openc3/utilities/process_manager.rb +0 -0
  376. data/lib/openc3/utilities/pypi_url.rb +0 -0
  377. data/lib/openc3/utilities/python_proxy.rb +0 -0
  378. data/lib/openc3/utilities/python_venv.rb +135 -0
  379. data/lib/openc3/utilities/quaternion.rb +0 -0
  380. data/lib/openc3/utilities/questdb_client.rb +0 -0
  381. data/lib/openc3/utilities/redis_secrets.rb +0 -0
  382. data/lib/openc3/utilities/reingest_job.rb +0 -0
  383. data/lib/openc3/utilities/ruby_lex_utils.rb +0 -0
  384. data/lib/openc3/utilities/rubygems_url.rb +39 -0
  385. data/lib/openc3/utilities/running_script.rb +24 -55
  386. data/lib/openc3/utilities/s3_autoload.rb +5 -5
  387. data/lib/openc3/utilities/script.rb +12 -8
  388. data/lib/openc3/utilities/secrets.rb +48 -3
  389. data/lib/openc3/utilities/simulated_target.rb +0 -0
  390. data/lib/openc3/utilities/sleeper.rb +0 -0
  391. data/lib/openc3/utilities/store.rb +0 -0
  392. data/lib/openc3/utilities/store_autoload.rb +2 -2
  393. data/lib/openc3/utilities/store_queued.rb +0 -0
  394. data/lib/openc3/utilities/target_file.rb +18 -1
  395. data/lib/openc3/utilities/thread_manager.rb +0 -0
  396. data/lib/openc3/utilities/throttle.rb +0 -0
  397. data/lib/openc3/utilities/zip.rb +0 -0
  398. data/lib/openc3/utilities.rb +0 -0
  399. data/lib/openc3/version.rb +5 -5
  400. data/lib/openc3/win32/excel.rb +0 -0
  401. data/lib/openc3/win32/win32.rb +0 -0
  402. data/lib/openc3/win32/win32_main.rb +0 -0
  403. data/lib/openc3.rb +2 -2
  404. data/tasks/gemfile_stats.rake +0 -0
  405. data/tasks/spec.rake +0 -0
  406. data/templates/command_validator/command_validator.py +0 -0
  407. data/templates/command_validator/command_validator.rb +0 -0
  408. data/templates/conversion/conversion.py +0 -0
  409. data/templates/conversion/conversion.rb +0 -0
  410. data/templates/limits_response/response.py +0 -0
  411. data/templates/limits_response/response.rb +0 -0
  412. data/templates/microservice/microservices/TEMPLATE/microservice.py +0 -0
  413. data/templates/microservice/microservices/TEMPLATE/microservice.rb +0 -0
  414. data/templates/plugin/.gitignore +0 -0
  415. data/templates/plugin/LICENSE.md +0 -0
  416. data/templates/plugin/README.md +0 -0
  417. data/templates/plugin/Rakefile +0 -0
  418. data/templates/plugin/plugin.gemspec +0 -0
  419. data/templates/plugin/plugin.txt +0 -0
  420. data/templates/processor/processor.py +1 -1
  421. data/templates/processor/processor.rb +0 -0
  422. data/templates/target/targets/TARGET/cmd_tlm/cmd.txt +0 -0
  423. data/templates/target/targets/TARGET/cmd_tlm/tlm.txt +0 -0
  424. data/templates/target/targets/TARGET/lib/target.py +0 -0
  425. data/templates/target/targets/TARGET/lib/target.rb +0 -0
  426. data/templates/target/targets/TARGET/procedures/procedure.py +0 -0
  427. data/templates/target/targets/TARGET/procedures/procedure.rb +0 -0
  428. data/templates/target/targets/TARGET/public/README.txt +0 -0
  429. data/templates/target/targets/TARGET/screens/status.txt +0 -0
  430. data/templates/target/targets/TARGET/target.txt +0 -0
  431. data/templates/tool_angular/.editorconfig +0 -0
  432. data/templates/tool_angular/.gitignore +0 -0
  433. data/templates/tool_angular/.vscode/extensions.json +0 -0
  434. data/templates/tool_angular/.vscode/launch.json +0 -0
  435. data/templates/tool_angular/.vscode/tasks.json +0 -0
  436. data/templates/tool_angular/angular.json +0 -0
  437. data/templates/tool_angular/extra-webpack.config.js +0 -0
  438. data/templates/tool_angular/package.json +2 -2
  439. data/templates/tool_angular/src/app/app-routing.module.ts +0 -0
  440. data/templates/tool_angular/src/app/app.component.html +0 -0
  441. data/templates/tool_angular/src/app/app.component.scss +0 -0
  442. data/templates/tool_angular/src/app/app.component.spec.ts +0 -0
  443. data/templates/tool_angular/src/app/app.component.ts +0 -0
  444. data/templates/tool_angular/src/app/app.module.ts +0 -0
  445. data/templates/tool_angular/src/app/custom-overlay-container.ts +0 -0
  446. data/templates/tool_angular/src/app/empty-route/empty-route.component.ts +0 -0
  447. data/templates/tool_angular/src/app/openc3-api.d.ts +0 -0
  448. data/templates/tool_angular/src/assets/.gitkeep +0 -0
  449. data/templates/tool_angular/src/environments/environment.prod.ts +0 -0
  450. data/templates/tool_angular/src/environments/environment.ts +0 -0
  451. data/templates/tool_angular/src/favicon.ico +0 -0
  452. data/templates/tool_angular/src/index.html +0 -0
  453. data/templates/tool_angular/src/main.single-spa.ts +0 -0
  454. data/templates/tool_angular/src/single-spa/asset-url.ts +0 -0
  455. data/templates/tool_angular/src/single-spa/single-spa-props.ts +0 -0
  456. data/templates/tool_angular/src/styles.scss +0 -0
  457. data/templates/tool_angular/tsconfig.app.json +0 -0
  458. data/templates/tool_angular/tsconfig.json +0 -0
  459. data/templates/tool_angular/tsconfig.spec.json +0 -0
  460. data/templates/tool_react/.eslintrc +0 -0
  461. data/templates/tool_react/.gitignore +0 -0
  462. data/templates/tool_react/.prettierignore +0 -0
  463. data/templates/tool_react/babel.config.json +0 -0
  464. data/templates/tool_react/jest.config.js +0 -0
  465. data/templates/tool_react/package.json +1 -1
  466. data/templates/tool_react/src/openc3-tool_name.js +0 -0
  467. data/templates/tool_react/src/root.component.js +0 -0
  468. data/templates/tool_react/src/root.component.test.js +0 -0
  469. data/templates/tool_react/webpack.config.js +0 -0
  470. data/templates/tool_svelte/.gitignore +0 -0
  471. data/templates/tool_svelte/.prettierignore +0 -0
  472. data/templates/tool_svelte/.prettierrc.js +0 -0
  473. data/templates/tool_svelte/babel.config.js +0 -0
  474. data/templates/tool_svelte/build/smui.css +0 -0
  475. data/templates/tool_svelte/jest.config.js +0 -0
  476. data/templates/tool_svelte/package.json +1 -1
  477. data/templates/tool_svelte/rollup.config.js +0 -0
  478. data/templates/tool_svelte/src/App.svelte +0 -0
  479. data/templates/tool_svelte/src/App.test.js +0 -0
  480. data/templates/tool_svelte/src/theme/_smui-theme.scss +0 -0
  481. data/templates/tool_svelte/src/tool_name.js +0 -0
  482. data/templates/tool_vue/.env.standalone +0 -0
  483. data/templates/tool_vue/.gitignore +0 -0
  484. data/templates/tool_vue/.prettierrc.cjs +0 -0
  485. data/templates/tool_vue/eslint.config.mjs +0 -0
  486. data/templates/tool_vue/jsconfig.json +0 -0
  487. data/templates/tool_vue/package.json +3 -3
  488. data/templates/tool_vue/src/App.vue +0 -0
  489. data/templates/tool_vue/src/main.js +0 -0
  490. data/templates/tool_vue/src/router.js +0 -0
  491. data/templates/tool_vue/src/tools/tool_name/tool_name.vue +0 -0
  492. data/templates/tool_vue/vite.config.js +1 -1
  493. data/templates/widget/.prettierrc.cjs +0 -0
  494. data/templates/widget/LICENSE.md +0 -0
  495. data/templates/widget/Rakefile +0 -0
  496. data/templates/widget/package.json +2 -2
  497. data/templates/widget/src/Widget.vue +0 -0
  498. data/templates/widget/vite.config.js +0 -0
  499. metadata +36 -9
@@ -20,17 +20,50 @@ module OpenC3
20
20
  class WebSocketApi
21
21
  USER_AGENT = 'OpenC3 / v7 (ruby/openc3/lib/io/web_socket_api)'.freeze
22
22
 
23
+ # Options every websocket api accepts, and their defaults. Subclasses
24
+ # forward **options rather than restating these.
25
+ DEFAULT_OPTIONS = {
26
+ write_timeout: 10.0,
27
+ read_timeout: 10.0,
28
+ connect_timeout: 5.0,
29
+ authentication: nil,
30
+ }.freeze
31
+
32
+ # Build a cable URL from the standard OPENC3 environment variable quartet:
33
+ # <prefix>_SCHEMA, <prefix>_HOSTNAME, <prefix>_CABLE_PORT, <prefix>_PORT
34
+ def self.cable_url(env_prefix:, default_hostname:, default_port:, path:)
35
+ schema = ENV.fetch("#{env_prefix}_SCHEMA", 'http')
36
+ # Normalize to the websocket schemes (mirrors the Python client). The
37
+ # websocket gem accepts http/https too, but ws/wss is what the URL
38
+ # actually is and Python's websockets library rejects anything else.
39
+ schema = 'ws' if schema == 'http'
40
+ schema = 'wss' if schema == 'https'
41
+ hostname = ENV.fetch("#{env_prefix}_HOSTNAME", nil) || (ENV['OPENC3_DEVEL'] ? '127.0.0.1' : default_hostname)
42
+ port = (ENV.fetch("#{env_prefix}_CABLE_PORT", nil) || ENV.fetch("#{env_prefix}_PORT", default_port)).to_i
43
+ return "#{schema}://#{hostname}:#{port}#{path}"
44
+ end
45
+
23
46
  # Create the WebsocketApi object. If a block is given will automatically connect/disconnect
24
- def initialize(url:, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope, &block)
47
+ #
48
+ # @param url [String] The cable URL to connect to
49
+ # @param scope [String] The scope to connect with
50
+ # @param options [Hash] See DEFAULT_OPTIONS
51
+ def initialize(url:, scope: $openc3_scope, **options, &block)
52
+ # Restore the arity checking that explicit keyword arguments used to give
53
+ # us, so a typo'd option is an error rather than a silently ignored value
54
+ unknown = options.keys - DEFAULT_OPTIONS.keys
55
+ raise ArgumentError, "unknown keyword#{'s' if unknown.length > 1}: #{unknown.join(', ')}" unless unknown.empty?
56
+
57
+ options = DEFAULT_OPTIONS.merge(options)
25
58
  # $openc3_scope is only set inside the Script Runner / microservice
26
59
  # environment. Fall back to OPENC3_SCOPE (mirrors the Python client) so a
27
60
  # bare `ruby script.rb` doesn't send a nil scope that the server rejects.
28
61
  @scope = scope || ENV.fetch('OPENC3_SCOPE', 'DEFAULT')
29
- @authentication = authentication.nil? ? generate_auth() : authentication
62
+ @authentication = options[:authentication] || generate_auth()
30
63
  @url = url
31
- @write_timeout = write_timeout
32
- @read_timeout = read_timeout
33
- @connect_timeout = connect_timeout
64
+ @write_timeout = options[:write_timeout]
65
+ @read_timeout = options[:read_timeout]
66
+ @connect_timeout = options[:connect_timeout]
34
67
  @subscribed = false
35
68
  if block_given?
36
69
  begin
@@ -58,23 +91,11 @@ module OpenC3
58
91
  # loops exit cleanly instead of hitting JSON::ParserError on JSON.parse("").
59
92
  return nil if message.nil? || message.empty?
60
93
 
61
- begin
62
- json_hash = JSON.parse(message, allow_nan: true, create_additions: true)
63
- rescue JSON::ParserError
64
- # Defense-in-depth: treat malformed frames as end-of-stream rather than crashing.
65
- return nil
66
- end
94
+ json_hash = parse_message(message)
67
95
  if ignore_protocol_messages
68
96
  type = json_hash['type']
69
97
  if type # ping, welcome, confirm_subscription, reject_subscription, disconnect
70
- if type == 'disconnect'
71
- if json_hash['reason'] == 'unauthorized'
72
- raise "Unauthorized"
73
- end
74
- end
75
- if type == 'reject_subscription'
76
- raise "Subscription Rejected"
77
- end
98
+ check_protocol_frame(json_hash)
78
99
  if timeout
79
100
  end_time = Time.now
80
101
  if (end_time - start_time) > timeout
@@ -98,10 +119,7 @@ module OpenC3
98
119
  # ApplicationCable::Channel#authenticate_subscription! — ActionCable
99
120
  # ignores `data` on `subscribe` commands.
100
121
  @identifier['token'] = @authentication.token(include_bearer: false)
101
- json_hash = {}
102
- json_hash['command'] = 'subscribe'
103
- json_hash['identifier'] = JSON.generate(@identifier, allow_nan: true)
104
- @stream.write(JSON.generate(json_hash, allow_nan: true))
122
+ write_command('subscribe')
105
123
  @subscribed = true
106
124
  wait_for_subscribed()
107
125
  end
@@ -117,30 +135,21 @@ module OpenC3
117
135
  def wait_for_subscribed
118
136
  while true
119
137
  message = @stream.read
138
+ # Unlike #read, end-of-stream is fatal here rather than a nil return:
139
+ # a socket that closes mid-handshake leaves nothing to carry on with.
120
140
  raise "WebSocket closed before subscription was confirmed" if message.nil? || message.empty?
121
141
 
122
- json_hash = JSON.parse(message, allow_nan: true, create_additions: true)
123
- case json_hash['type']
124
- when 'confirm_subscription'
125
- return
126
- when 'reject_subscription'
127
- raise "Subscription Rejected"
128
- when 'disconnect'
129
- raise "Unauthorized" if json_hash['reason'] == 'unauthorized'
130
- else
131
- # Ignore welcome / ping and keep waiting for confirmation
132
- next
133
- end
142
+ json_hash = parse_message(message)
143
+ check_protocol_frame(json_hash)
144
+ # Ignore welcome / ping and keep waiting for confirmation
145
+ return if json_hash['type'] == 'confirm_subscription'
134
146
  end
135
147
  end
136
148
 
137
149
  # Will unsubscribe to the channel based on @identifier
138
150
  def unsubscribe
139
151
  if @subscribed
140
- json_hash = {}
141
- json_hash['command'] = 'unsubscribe'
142
- json_hash['identifier'] = JSON.generate(@identifier, allow_nan: true)
143
- @stream.write(JSON.generate(json_hash, allow_nan: true))
152
+ write_command('unsubscribe')
144
153
  @subscribed = false
145
154
  end
146
155
  end
@@ -154,11 +163,7 @@ module OpenC3
154
163
  # the subscription identifier (with token) and the server would silently
155
164
  # ignore the action.
156
165
  subscribe()
157
- json_hash = {}
158
- json_hash['command'] = 'message'
159
- json_hash['identifier'] = JSON.generate(@identifier, allow_nan: true)
160
- json_hash['data'] = JSON.generate(data_hash, allow_nan: true)
161
- write(JSON.generate(json_hash, allow_nan: true))
166
+ write_command('message', data_hash)
162
167
  end
163
168
 
164
169
  # General write to the websocket
@@ -196,12 +201,49 @@ module OpenC3
196
201
  rescue
197
202
  # Oh well, we tried
198
203
  end
204
+ # unsubscribe only clears this after a successful write. The stream is
205
+ # being closed regardless, so it cannot remain subscribed.
206
+ @subscribed = false
199
207
  @stream.disconnect
208
+ else
209
+ @subscribed = false
200
210
  end
201
211
  end
202
212
 
203
213
  # private
204
214
 
215
+ # Write an ActionCable command frame for the current @identifier. Writes
216
+ # straight to the stream because the callers have already subscribed (and
217
+ # subscribe itself must not recurse through write).
218
+ def write_command(command, data_hash = nil)
219
+ json_hash = {}
220
+ json_hash['command'] = command
221
+ json_hash['identifier'] = JSON.generate(@identifier, allow_nan: true)
222
+ json_hash['data'] = JSON.generate(data_hash, allow_nan: true) if data_hash
223
+ @stream.write(JSON.generate(json_hash, allow_nan: true))
224
+ end
225
+
226
+ # Parse a server frame. Kept in one place so the JSON options cannot drift
227
+ # between the two readers.
228
+ def parse_message(message)
229
+ return JSON.parse(message, allow_nan: true, create_additions: true)
230
+ end
231
+
232
+ # Apply the protocol rules shared by #read and #wait_for_subscribed
233
+ def check_protocol_frame(json_hash)
234
+ case json_hash['type']
235
+ when 'reject_subscription'
236
+ raise "Subscription Rejected"
237
+ when 'disconnect'
238
+ # Any other disconnect reason is not fatal; the caller keeps reading
239
+ raise "Unauthorized" if json_hash['reason'] == 'unauthorized'
240
+ else
241
+ # ping, welcome, confirm_subscription and anything new the server adds
242
+ # are informational only
243
+ nil
244
+ end
245
+ end
246
+
205
247
  # Generate the appropriate token for OpenC3
206
248
  def generate_auth
207
249
  if ENV['OPENC3_API_TOKEN'].nil? and ENV['OPENC3_API_USER'].nil?
@@ -216,62 +258,119 @@ module OpenC3
216
258
  end
217
259
  end
218
260
 
261
+ # Identifier for channels whose only parameter is the event history count.
262
+ # Including classes supply the channel name as a CHANNEL constant.
263
+ module HistoryCountIdentifier
264
+ def initialize(history_count: 0, **options)
265
+ @identifier = {
266
+ channel: self.class::CHANNEL,
267
+ history_count: history_count
268
+ }
269
+ super(**options)
270
+ end
271
+ end
272
+
219
273
  # Base class for cmd-tlm-api websockets - Do not use directly
220
274
  class CmdTlmWebSocketApi < WebSocketApi
221
- def initialize(url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
275
+ def initialize(url: nil, **options)
222
276
  url = generate_url() unless url
223
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
277
+ super(url: url, **options)
224
278
  end
225
279
 
226
280
  def generate_url
227
- schema = ENV['OPENC3_API_SCHEMA'] || 'http'
228
- hostname = ENV['OPENC3_API_HOSTNAME'] || (ENV['OPENC3_DEVEL'] ? '127.0.0.1' : 'openc3-cosmos-cmd-tlm-api')
229
- port = ENV['OPENC3_API_CABLE_PORT'] || ENV['OPENC3_API_PORT'] || '3901'
230
- port = port.to_i
231
- return "#{schema}://#{hostname}:#{port}/openc3-api/cable"
281
+ return WebSocketApi.cable_url(
282
+ env_prefix: 'OPENC3_API',
283
+ default_hostname: 'openc3-cosmos-cmd-tlm-api',
284
+ default_port: '3901',
285
+ path: '/openc3-api/cable'
286
+ )
232
287
  end
233
288
  end
234
289
 
235
290
  # Base class for script-runner-api websockets - Do not use directly
236
291
  class ScriptWebSocketApi < WebSocketApi
237
- def initialize(url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
292
+ def initialize(url: nil, **options)
238
293
  url = generate_url() unless url
239
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
294
+ super(url: url, **options)
240
295
  end
241
296
 
242
297
  def generate_url
243
- schema = ENV['OPENC3_SCRIPT_API_SCHEMA'] || 'http'
244
- hostname = ENV['OPENC3_SCRIPT_API_HOSTNAME'] || (ENV['OPENC3_DEVEL'] ? '127.0.0.1' : 'openc3-cosmos-script-runner-api')
245
- port = ENV['OPENC3_SCRIPT_API_CABLE_PORT'] || ENV['OPENC3_SCRIPT_API_PORT'] || '3902'
246
- port = port.to_i
247
- return "#{schema}://#{hostname}:#{port}/script-api/cable"
298
+ return WebSocketApi.cable_url(
299
+ env_prefix: 'OPENC3_SCRIPT_API',
300
+ default_hostname: 'openc3-cosmos-script-runner-api',
301
+ default_port: '3902',
302
+ path: '/script-api/cable'
303
+ )
248
304
  end
249
305
  end
250
306
 
251
307
  # Running Script WebSocket
252
308
  class RunningScriptWebSocketApi < ScriptWebSocketApi
253
- def initialize(id:, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
309
+ def initialize(id:, **options)
310
+ @pending_events = []
254
311
  @identifier = {
255
312
  channel: "RunningScriptChannel",
256
313
  id: id
257
314
  }
258
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
315
+ super(**options)
316
+ end
317
+
318
+ # The backlog of script events is transmitted with the subscription
319
+ # confirmation, but LIVE events only flow once the client reports that it is
320
+ # ready to stream events (see RunningScriptChannel#ready) -- a broadcast sent
321
+ # before the gateway has registered this subscription's stream would be
322
+ # silently dropped. subscribe() blocks until confirm_subscription, so the
323
+ # 'ready' action is guaranteed to arrive after the stream is registered.
324
+ def subscribe
325
+ was_subscribed = @subscribed
326
+ super
327
+ write_action({ 'action' => 'ready' }) unless was_subscribed
328
+ end
329
+
330
+ # RunningScriptChannel batches events to reduce ActionCable frame and
331
+ # client-dispatch overhead. Preserve the public API's historical contract:
332
+ # callers still receive one script event from each read.
333
+ def read(ignore_protocol_messages: true, timeout: nil)
334
+ return @pending_events.shift unless @pending_events.empty?
335
+
336
+ loop do
337
+ message = super
338
+ return message unless message.is_a?(Array)
339
+
340
+ @pending_events.concat(message)
341
+ return @pending_events.shift unless @pending_events.empty?
342
+ end
343
+ end
344
+
345
+ def connect
346
+ @pending_events.clear
347
+ super
348
+ end
349
+
350
+ def unsubscribe
351
+ @pending_events.clear
352
+ super
353
+ end
354
+
355
+ def disconnect
356
+ @pending_events.clear
357
+ super
259
358
  end
260
359
  end
261
360
 
262
361
  # All Scripts WebSocket
263
362
  class AllScriptsWebSocketApi < ScriptWebSocketApi
264
- def initialize(url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
363
+ def initialize(**options)
265
364
  @identifier = {
266
365
  channel: "AllScriptsChannel",
267
366
  }
268
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
367
+ super(**options)
269
368
  end
270
369
  end
271
370
 
272
371
  # Log Messages WebSocket
273
372
  class MessagesWebSocketApi < CmdTlmWebSocketApi
274
- def initialize(history_count: 0, start_time: nil, end_time: nil, level: nil, types: nil, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
373
+ def initialize(history_count: 0, start_time: nil, end_time: nil, level: nil, types: nil, **options)
275
374
  @identifier = {
276
375
  channel: "MessagesChannel",
277
376
  history_count: history_count
@@ -280,94 +379,59 @@ module OpenC3
280
379
  @identifier['end_time'] = end_time if end_time
281
380
  @identifier['level'] = level if level
282
381
  @identifier['types'] = types if types
283
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
382
+ super(**options)
284
383
  end
285
384
  end
286
385
 
287
386
  # Autonomic Events WebSocket (Enterprise Only)
288
387
  class AutonomicEventsWebSocketApi < CmdTlmWebSocketApi
289
- def initialize(history_count: 0, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
290
- @identifier = {
291
- channel: "AutonomicEventsChannel",
292
- history_count: history_count
293
- }
294
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
295
- end
388
+ CHANNEL = 'AutonomicEventsChannel'.freeze
389
+ include HistoryCountIdentifier
296
390
  end
297
391
 
298
392
  # Calendar Events WebSocket (Enterprise Only)
299
393
  class CalendarEventsWebSocketApi < CmdTlmWebSocketApi
300
- def initialize(history_count: 0, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
301
- @identifier = {
302
- channel: "CalendarEventsChannel",
303
- history_count: history_count
304
- }
305
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
306
- end
394
+ CHANNEL = 'CalendarEventsChannel'.freeze
395
+ include HistoryCountIdentifier
307
396
  end
308
397
 
309
398
  # Config Events WebSocket
310
399
  class ConfigEventsWebSocketApi < CmdTlmWebSocketApi
311
- def initialize(history_count: 0, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
312
- @identifier = {
313
- channel: "ConfigEventsChannel",
314
- history_count: history_count
315
- }
316
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
317
- end
400
+ CHANNEL = 'ConfigEventsChannel'.freeze
401
+ include HistoryCountIdentifier
318
402
  end
319
403
 
320
404
  # Limits Events WebSocket
321
405
  class LimitsEventsWebSocketApi < CmdTlmWebSocketApi
322
- def initialize(history_count: 0, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
323
- @identifier = {
324
- channel: "LimitsEventsChannel",
325
- history_count: history_count
326
- }
327
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
328
- end
406
+ CHANNEL = 'LimitsEventsChannel'.freeze
407
+ include HistoryCountIdentifier
329
408
  end
330
409
 
331
410
  # System Events WebSocket
332
411
  class SystemEventsWebSocketApi < CmdTlmWebSocketApi
333
- def initialize(history_count: 0, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
334
- @identifier = {
335
- channel: "SystemEventsChannel",
336
- history_count: history_count
337
- }
338
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
339
- end
412
+ CHANNEL = 'SystemEventsChannel'.freeze
413
+ include HistoryCountIdentifier
340
414
  end
341
415
 
342
416
  # Timeline WebSocket
343
417
  class TimelineEventsWebSocketApi < CmdTlmWebSocketApi
344
- def initialize(history_count: 0, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
345
- @identifier = {
346
- channel: "TimelineEventsChannel",
347
- history_count: history_count
348
- }
349
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
350
- end
418
+ CHANNEL = 'TimelineEventsChannel'.freeze
419
+ include HistoryCountIdentifier
351
420
  end
352
421
 
353
422
  # Queue WebSocket
354
423
  class QueueEventsWebSocketApi < CmdTlmWebSocketApi
355
- def initialize(history_count: 0, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
356
- @identifier = {
357
- channel: "QueueEventsChannel",
358
- history_count: history_count
359
- }
360
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
361
- end
424
+ CHANNEL = 'QueueEventsChannel'.freeze
425
+ include HistoryCountIdentifier
362
426
  end
363
427
 
364
428
  # Streaming API WebSocket
365
429
  class StreamingWebSocketApi < CmdTlmWebSocketApi
366
- def initialize(url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
430
+ def initialize(**options)
367
431
  @identifier = {
368
432
  channel: "StreamingChannel"
369
433
  }
370
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
434
+ super(**options)
371
435
  end
372
436
 
373
437
  # Request to add data to the stream
@@ -393,26 +457,10 @@ module OpenC3
393
457
  # VALUETYPE - RAW, CONVERTED, FORMATTED, or PURE (pure means all types as stored in log)
394
458
  #
395
459
  def add(items: nil, packets: nil, start_time: nil, end_time: nil, scope: nil)
396
- scope ||= @scope
397
- data_hash = {}
398
- data_hash['action'] = 'add'
399
- if start_time
400
- if Time === start_time
401
- start_time = start_time.to_nsec_from_epoch
402
- end
403
- data_hash['start_time'] = start_time
404
- end
405
- if end_time
406
- if Time === end_time
407
- end_time = end_time.to_nsec_from_epoch
408
- end
409
- data_hash['end_time'] = end_time
410
- end
411
- data_hash['items'] = items if items
412
- data_hash['packets'] = packets if packets
413
- data_hash['scope'] = scope
414
- data_hash['token'] = @authentication.token(include_bearer: false)
415
- write_action(data_hash)
460
+ times = {}
461
+ times['start_time'] = to_nsec(start_time) if start_time
462
+ times['end_time'] = to_nsec(end_time) if end_time
463
+ stream_action('add', items: items, packets: packets, scope: scope, extra: times)
416
464
  end
417
465
 
418
466
  # Request to remove data from the stream
@@ -435,26 +483,31 @@ module OpenC3
435
483
  # VALUETYPE - RAW, CONVERTED, FORMATTED, or PURE (pure means all types as stored in log)
436
484
  #
437
485
  def remove(items: nil, packets: nil, scope: nil)
438
- scope ||= @scope
439
- data_hash = {}
440
- data_hash['action'] = 'remove'
441
- data_hash['items'] = items if items
442
- data_hash['packets'] = packets if packets
443
- data_hash['scope'] = scope
444
- data_hash['token'] = @authentication.token(include_bearer: false)
445
- write_action(data_hash)
486
+ stream_action('remove', items: items, packets: packets, scope: scope)
446
487
  end
447
488
 
448
489
  # Convenience method to read all data until end marker is received.
490
+ # Omitting end_time streams realtime and endlessly: no end marker is ever
491
+ # sent, so a timeout is the only way the collection ends on its own.
449
492
  # Warning: DATA IS STORED IN RAM. Do not use this with large queries
450
- def self.read_all(items: nil, packets: nil, start_time: nil, end_time:, scope: nil, timeout: nil)
493
+ def self.read_all(items: nil, packets: nil, start_time: nil, end_time: nil, scope: nil, timeout: nil)
451
494
  read_all_start_time = Time.now
452
495
  data = []
453
496
  self.new do |api|
454
497
  api.add(items: items, packets: packets, start_time: start_time, end_time: end_time, scope: scope)
455
498
  while true
456
499
  batch = api.read
457
- if batch.length == 0
500
+ if batch.nil?
501
+ # A bounded query must receive its end marker; a truncated result
502
+ # returned as if complete is worse than an error. A realtime query
503
+ # never gets one, so a close is an ordinary way for it to end.
504
+ raise "WebSocket closed before end marker" if end_time
505
+
506
+ return data
507
+ end
508
+ # An empty batch is the explicit end marker sent after a historical
509
+ # query is complete.
510
+ if batch.empty?
458
511
  return data
459
512
  else
460
513
  data.concat(batch)
@@ -467,6 +520,26 @@ module OpenC3
467
520
  end
468
521
  end
469
522
  end
523
+
524
+ # private
525
+
526
+ # Accept either a Time or an already converted 64-bit nanosecond value
527
+ def to_nsec(value)
528
+ return Time === value ? value.to_nsec_from_epoch : value
529
+ end
530
+
531
+ # Build and write a StreamingChannel action. extra carries action specific
532
+ # keys (the times for 'add') and is merged first to preserve wire ordering.
533
+ def stream_action(action, items:, packets:, scope:, extra: {})
534
+ data_hash = {}
535
+ data_hash['action'] = action
536
+ data_hash.merge!(extra)
537
+ data_hash['items'] = items if items
538
+ data_hash['packets'] = packets if packets
539
+ data_hash['scope'] = scope || @scope
540
+ data_hash['token'] = @authentication.token(include_bearer: false)
541
+ write_action(data_hash)
542
+ end
470
543
  end
471
544
  end
472
545
 
data/lib/openc3/script.rb CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
data/lib/openc3/system.rb CHANGED
File without changes
File without changes
@@ -253,6 +253,13 @@ module OpenC3
253
253
 
254
254
  def connect
255
255
  Logger.info "Connecting to #{@interface.name}..."
256
+ # Interface connect implementations typically overwrite their stream / socket
257
+ # so cleanly close any existing connection rather than leaking it
258
+ begin
259
+ @interface.disconnect if @interface.connected?
260
+ rescue => err
261
+ Logger.error "Disconnect: #{@interface.name}: #{err.formatted}"
262
+ end
256
263
  @interface.connect
257
264
  if @connection_success_callback
258
265
  @connection_success_callback.call
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -503,7 +503,7 @@ end
503
503
  # New plugins should only use openc3 paths and module OpenC3
504
504
  unless ENV['OPENC3_NO_COSMOS_COMPATIBILITY']
505
505
  Cosmos = OpenC3
506
- ENV['COSMOS_SCOPE'] = ENV['OPENC3_SCOPE']
506
+ ENV['COSMOS_SCOPE'] = ENV.fetch('OPENC3_SCOPE', 'DEFAULT')
507
507
 
508
508
  # Don't apply the compatibility layer in test environments to avoid conflicts with RSpec
509
509
  unless defined?(RSpec) || ENV['RAILS_ENV'] == 'test' || ENV['RACK_ENV'] == 'test'
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -46,7 +46,7 @@ module OpenC3
46
46
  raise "Timeout of #{timeout}s waiting for cmd ack. Does target '#{target_name}' exist?"
47
47
  end
48
48
 
49
- def self.inject_tlm(target_name, packet_name, item_hash = nil, type: :CONVERTED, stored: false, timeout: 5, scope:)
49
+ def self.inject_tlm(target_name, packet_name, item_hash = nil, type: :CONVERTED, stored: false, timeout: 5, received_time: nil, scope:)
50
50
  data = {}
51
51
  data['target_name'] = target_name.to_s.upcase
52
52
  data['packet_name'] = packet_name.to_s.upcase
@@ -55,6 +55,7 @@ module OpenC3
55
55
 
56
56
  db_shard = Store.db_shard_for_target(target_name, scope: scope)
57
57
  data['stored'] = stored
58
+ data['received_time'] = received_time unless received_time.nil?
58
59
  ack_topic = "{#{scope}__ACKCMD}TARGET__#{target_name}"
59
60
  Topic.update_topic_offsets([ack_topic], db_shard: db_shard)
60
61
  decom_id = Topic.write_topic("#{scope}__DECOMINTERFACE__{#{target_name}}",