openc3 7.3.0 → 7.4.1

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 +139 -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 +19 -14
  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 +12 -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 +24 -3
  172. data/lib/openc3/io/json_drb.rb +20 -4
  173. data/lib/openc3/io/json_drb_object.rb +3 -2
  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 +6 -3
  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 +548 -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 +36 -1
  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 +8 -1
  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 +5 -1
  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 +29 -46
  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 +6 -6
  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 +56 -9
@@ -27,6 +27,9 @@ module OpenC3
27
27
  class UdpReadWriteSocket
28
28
  HOST_0_0_0_0 = '0.0.0.0'
29
29
 
30
+ # MSG_DONTWAIT is not defined on Windows where sends are left blocking
31
+ WRITE_FLAGS = Socket.const_defined?('MSG_DONTWAIT') ? Socket::MSG_DONTWAIT : 0
32
+
30
33
  # @param bind_port [Integer[ Port to write data out from and receive data on (0 = randomly assigned)
31
34
  # @param bind_address [String] Local address to bind to (0.0.0.0 = All local addresses)
32
35
  # @param external_port [Integer] External port to write to
@@ -35,6 +38,8 @@ module OpenC3
35
38
  # @param ttl [Integer] Time To Live for outgoing multicast packets
36
39
  # @param read_multicast [Boolean] Whether or not to try to read from the external address as multicast
37
40
  # @param write_multicast [Boolean] Whether or not to write to the external address as multicast
41
+ # @param connect_socket [Boolean] Whether to connect the socket to the external address. If false,
42
+ # writes explicitly address each datagram so reads can accept datagrams from any source.
38
43
  def initialize(
39
44
  bind_port = 0,
40
45
  bind_address = HOST_0_0_0_0,
@@ -43,10 +48,23 @@ module OpenC3
43
48
  multicast_interface_address = nil,
44
49
  ttl = 1,
45
50
  read_multicast = true,
46
- write_multicast = true
51
+ write_multicast = true,
52
+ connect_socket = true
47
53
  )
48
54
 
49
55
  @socket = UDPSocket.new
56
+ @external_address = external_address
57
+ @external_port = external_port
58
+ @connect_socket = connect_socket
59
+ # Resolve the destination once at creation time so writes don't pay for a
60
+ # (potentially blocking) name lookup on every datagram
61
+ @external_sockaddr = nil
62
+ if !connect_socket and external_address and external_port
63
+ # Explicitly resolve IPv4 because UDPSocket is an AF_INET socket and
64
+ # sockaddr_in would otherwise hand back an IPv6 address for names like localhost
65
+ ip_address = Socket.getaddrinfo(external_address, nil, Socket::AF_INET, Socket::SOCK_DGRAM)[0][3]
66
+ @external_sockaddr = Socket.sockaddr_in(external_port, ip_address)
67
+ end
50
68
 
51
69
  # Basic setup to reuse address
52
70
  @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
@@ -55,10 +73,10 @@ module OpenC3
55
73
  @socket.bind(bind_address, bind_port) if bind_address and bind_port
56
74
 
57
75
  # Default send to the specified address and port
58
- @socket.connect(external_address, external_port) if external_address and external_port
76
+ @socket.connect(external_address, external_port) if connect_socket and external_address and external_port
59
77
 
60
78
  # Handle multicast
61
- if UdpReadWriteSocket.multicast?(external_address, external_port)
79
+ if UdpReadWriteSocket.multicast?(external_address)
62
80
  if write_multicast
63
81
  # Basic setup set time to live
64
82
  @socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_TTL, ttl.to_i)
@@ -90,7 +108,13 @@ module OpenC3
90
108
 
91
109
  loop do
92
110
  begin
93
- bytes_sent = @socket.write_nonblock(data_to_send)
111
+ if @external_sockaddr
112
+ # send is used rather than sendmsg_nonblock because sendmsg is not
113
+ # implemented on Windows
114
+ bytes_sent = @socket.send(data_to_send, WRITE_FLAGS, @external_sockaddr)
115
+ else
116
+ bytes_sent = @socket.write_nonblock(data_to_send)
117
+ end
94
118
  rescue Errno::EAGAIN, Errno::EWOULDBLOCK
95
119
  result = IO.fast_select(nil, [@socket], nil, write_timeout)
96
120
  if result
@@ -129,12 +153,18 @@ module OpenC3
129
153
  end
130
154
 
131
155
  # @param host [String] Machine name or IP address
132
- # @param port [String] Port
156
+ # @param port [String] Port (unused, kept for backwards compatibility)
133
157
  # @return [Boolean] Whether the hostname is multicast
134
- def self.multicast?(host, port)
135
- return false if host.nil? || port.nil?
158
+ def self.multicast?(host, port = nil)
159
+ return false if host.nil?
136
160
 
137
- Addrinfo.udp(host, port).ipv4_multicast?
161
+ begin
162
+ Addrinfo.udp(host, 0).ipv4_multicast?
163
+ rescue SocketError, ArgumentError
164
+ # Hostname isn't resolvable so it can't be a multicast address we handle.
165
+ # Reads don't need the hostname at all so don't fail creating the socket.
166
+ false
167
+ end
138
168
  end
139
169
  end
140
170
 
@@ -16,6 +16,7 @@
16
16
  # if purchased from OpenC3, Inc.
17
17
 
18
18
  require 'openc3/win32/win32'
19
+ require 'openc3/io/serial_driver'
19
20
  require 'timeout' # For Timeout::Error
20
21
 
21
22
  module OpenC3
File without changes
File without changes
File without changes
File without changes
@@ -142,7 +142,7 @@ module OpenC3
142
142
  end
143
143
  elsif flags & OPENC3_ENTRY_TYPE_MASK == OPENC3_RAW_PACKET_ENTRY_TYPE_MASK
144
144
  packet_index, time_nsec_since_epoch = entry[2..11].unpack('nQ>')
145
- received_time_nsec_since_epoch, _extra, packet_data = handle_received_time_extra_and_data(entry, time_nsec_since_epoch, includes_received_time, includes_extra, cbor)
145
+ received_time_nsec_since_epoch, extra, packet_data = handle_received_time_extra_and_data(entry, time_nsec_since_epoch, includes_received_time, includes_extra, cbor)
146
146
  lookup_cmd_or_tlm, target_name, packet_name, _id = @packets[packet_index]
147
147
  if cmd_or_tlm != lookup_cmd_or_tlm
148
148
  raise "Packet type mismatch, packet:#{cmd_or_tlm}, lookup:#{lookup_cmd_or_tlm}"
@@ -159,6 +159,10 @@ module OpenC3
159
159
  packet.set_received_time_fast(received_time)
160
160
  packet.cmd_or_tlm = cmd_or_tlm
161
161
  packet.stored = stored
162
+ # Assigned unconditionally because identify_and_define_packet_data
163
+ # returns the shared System packet, so a nil extra here must clear
164
+ # the extra left over from a previous read of the same packet
165
+ packet.extra = extra
162
166
  packet.received_count += 1
163
167
  return packet
164
168
  elsif flags & OPENC3_ENTRY_TYPE_MASK == OPENC3_TARGET_DECLARATION_ENTRY_TYPE_MASK
@@ -304,7 +308,24 @@ module OpenC3
304
308
  if cbor
305
309
  extra = CBOR.decode(extra_encoded)
306
310
  else
307
- extra = JSON.parse(extra_encoded, allow_nan: true, create_additions: true)
311
+ begin
312
+ extra = JSON.parse(extra_encoded, allow_nan: true, create_additions: true)
313
+ rescue JSON::ParserError => e
314
+ # PacketLogWriter up to version 7.3.0 CBOR encoded the extra on
315
+ # RAW_PACKET entries without setting OPENC3_CBOR_FLAG_MASK, so the
316
+ # flag claims JSON while the bytes are CBOR. Retry as CBOR so those
317
+ # existing files can still be read. extra is always a Hash, so a
318
+ # decode to anything else means these bytes aren't the legacy
319
+ # encoding either and the original JSON error is the useful one.
320
+ decoded = begin
321
+ CBOR.decode(extra_encoded)
322
+ rescue StandardError
323
+ raise e
324
+ end
325
+ raise e unless Hash === decoded
326
+
327
+ extra = decoded
328
+ end
308
329
  end
309
330
  end
310
331
  data = entry[next_offset..-1]
@@ -311,6 +311,11 @@ module OpenC3
311
311
  extra = JSON.parse(extra, allow_nan: true, create_additions: true) if String === extra
312
312
  length += OPENC3_EXTRA_LENGTH_FIXED_SIZE
313
313
  if @data_format == :CBOR
314
+ # The reader uses this same flag to pick the extra decoder, so it
315
+ # must be set here as well as in the JSON_PACKET data branch above.
316
+ # RAW_PACKET entries never reach that branch and would otherwise
317
+ # write CBOR extra that the reader tries to JSON.parse.
318
+ flags |= OPENC3_CBOR_FLAG_MASK
314
319
  extra_encoded = extra.as_json.to_cbor
315
320
  else
316
321
  extra_encoded = JSON.generate(extra.as_json, allow_nan: true)
@@ -47,7 +47,7 @@ module OpenC3
47
47
  raise "log_type must be :READ or :WRITE" unless LOG_TYPES.include? log_type
48
48
 
49
49
  super(
50
- "#{ENV['OPENC3_SCOPE']}/stream_logs/",
50
+ "#{ENV.fetch('OPENC3_SCOPE', 'DEFAULT')}/stream_logs/",
51
51
  true, # Start with logging enabled
52
52
  cycle_time,
53
53
  cycle_size,
File without changes
File without changes
data/lib/openc3/logs.rb CHANGED
File without changes
File without changes
File without changes
File without changes
@@ -33,7 +33,8 @@ module OpenC3
33
33
  end
34
34
  stored = inject_tlm_hash.fetch('stored', false)
35
35
  packet.stored = stored.to_s.downcase == 'true'
36
- packet.received_time = Time.now.sys
36
+ received_time = inject_tlm_hash['received_time']
37
+ packet.received_time = received_time.nil? ? Time.now.sys : Time.from_nsec_from_epoch(received_time).sys
37
38
  packet.received_count = TargetModel.increment_telemetry_count(packet.target_name, packet.packet_name, 1, scope: @scope)
38
39
  TelemetryTopic.write_packet(packet, scope: @scope)
39
40
  end
@@ -221,7 +221,12 @@ module OpenC3
221
221
  next 'SUCCESS'
222
222
  end
223
223
  if msg_hash.key?('interface_details')
224
- next @interface.details.as_json.to_json(allow_nan: true)
224
+ begin
225
+ next @interface.details.as_json.to_json(allow_nan: true)
226
+ rescue => e
227
+ @logger.error "#{@interface.name}: interface_details: #{e.formatted}"
228
+ next e.message
229
+ end
225
230
  end
226
231
  end
227
232
 
@@ -508,7 +513,12 @@ module OpenC3
508
513
  next 'SUCCESS'
509
514
  end
510
515
  if msg_hash.key?('router_details')
511
- next @router.details.as_json.to_json(allow_nan: true)
516
+ begin
517
+ next @router.details.as_json.to_json(allow_nan: true)
518
+ rescue => e
519
+ @logger.error "#{@router.name}: router_details: #{e.formatted}"
520
+ next e.message
521
+ end
512
522
  end
513
523
  next 'SUCCESS'
514
524
  end
@@ -610,7 +620,26 @@ module OpenC3
610
620
  # Called to connect the interface/router. It takes optional parameters to
611
621
  # rebuilt the interface/router. Once we set the state to 'ATTEMPTING' the
612
622
  # run method handles the actual connection.
623
+ # Connecting an interface/router which is already CONNECTED is a no-op.
624
+ # Without this the existing (working) connection would be torn down and
625
+ # rebuilt which can take up to the read_timeout to detect. Callers who want
626
+ # to force a reconnect should disconnect first or pass new parameters.
613
627
  def attempting(*params)
628
+ if params.empty? and @interface.state == 'CONNECTED' and @interface.connected?
629
+ @logger.info "#{@interface.name}: Connect ignored, already connected"
630
+ return @interface
631
+ end
632
+
633
+ attempt_connection(*params)
634
+ end
635
+
636
+ # Sets the state to 'ATTEMPTING', first rebuilding the interface/router if
637
+ # parameters are given, so the run method performs the actual connection.
638
+ # Unlike attempting() this always transitions. The reconnect path in
639
+ # disconnect() requires that, since @interface.disconnect may have raised or
640
+ # left connected? true, which would make attempting() ignore the request and
641
+ # leave the interface stuck in 'CONNECTED' with no way back to a connection.
642
+ def attempt_connection(*params)
614
643
  unless params.empty?
615
644
  @interface.disconnect()
616
645
  # Build New Interface, this can fail if passed bad parameters
@@ -828,6 +857,13 @@ module OpenC3
828
857
 
829
858
  def connect
830
859
  @logger.info "#{@interface.name}: Connect #{@interface.connection_string}"
860
+ # Interface connect implementations typically overwrite their stream / socket
861
+ # so cleanly close any existing connection rather than leaking it
862
+ begin
863
+ @interface.disconnect if @interface.connected?
864
+ rescue => e
865
+ @logger.error "Disconnect: #{@interface.name}: #{e.formatted}"
866
+ end
831
867
  begin
832
868
  @interface.connect
833
869
  @interface.post_connect
@@ -849,38 +885,49 @@ module OpenC3
849
885
  end
850
886
 
851
887
  def disconnect(allow_reconnect = true)
852
- return if @interface.state == 'DISCONNECTED' && !@interface.connected?
853
-
854
- # Synchronize the calls to @interface.disconnect since it takes an unknown
855
- # amount of time. If two calls to disconnect stack up, the if statement
856
- # should avoid multiple calls to disconnect.
888
+ reconnect = false
889
+
890
+ # Two threads reach here for a single connection loss: the cmd handler
891
+ # thread servicing a disconnect directive, and the run thread coming back
892
+ # out of read (or out of the connection maintenance sleep). The redundant
893
+ # check below and the state change that records the disconnect must be in
894
+ # the same critical section, otherwise the second thread reads the state
895
+ # before the first has updated it and disconnects the interface twice.
857
896
  @mutex.synchronize do
897
+ # A disconnect has already been performed so there is nothing left to do
898
+ return if @interface.state == 'DISCONNECTED' && !@interface.connected?
899
+
900
+ # Call disconnect without consulting connected? so any resources the
901
+ # interface is still holding are cleaned up. It takes an unknown amount
902
+ # of time which is the other reason for the mutex.
858
903
  begin
859
- @interface.disconnect if @interface.connected?
904
+ @interface.disconnect
860
905
  rescue => e
861
906
  @logger.error "Disconnect: #{@interface.name}: #{e.formatted}"
862
907
  end
863
- end
864
908
 
865
- # If the interface is set to auto_reconnect then delay so the thread
866
- # can come back around and allow the interface a chance to reconnect.
867
- # Skip reconnect if stop() has been called to avoid re-creating the status model
868
- if allow_reconnect and @interface.auto_reconnect and @interface.state != 'DISCONNECTED' and !@cancel_thread
869
- attempting()
870
- if !@cancel_thread
871
- # @logger.debug "reconnect delay: #{@interface.reconnect_delay}"
872
- @interface_thread_sleeper.sleep(@interface.reconnect_delay)
873
- end
874
- else
875
- @interface.state = 'DISCONNECTED'
876
- unless @cancel_thread
877
- if @interface_or_router == 'INTERFACE'
878
- InterfaceStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
879
- else
880
- RouterStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
909
+ # If the interface is set to auto_reconnect then delay so the thread
910
+ # can come back around and allow the interface a chance to reconnect.
911
+ # Skip reconnect if stop() has been called to avoid re-creating the status model
912
+ reconnect = allow_reconnect && @interface.auto_reconnect && @interface.state != 'DISCONNECTED' && !@cancel_thread
913
+ if reconnect
914
+ attempt_connection()
915
+ else
916
+ @interface.state = 'DISCONNECTED'
917
+ unless @cancel_thread
918
+ if @interface_or_router == 'INTERFACE'
919
+ InterfaceStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
920
+ else
921
+ RouterStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
922
+ end
881
923
  end
882
924
  end
883
925
  end
926
+
927
+ # Sleep outside the mutex so stop() and connect() are not blocked for the
928
+ # whole reconnect delay
929
+ # @logger.debug "reconnect delay: #{@interface.reconnect_delay}"
930
+ @interface_thread_sleeper.sleep(@interface.reconnect_delay) if reconnect && !@cancel_thread
884
931
  end
885
932
 
886
933
  # Disconnect from the interface and stop the thread
File without changes
@@ -43,7 +43,7 @@ module OpenC3
43
43
  attr_accessor :secrets
44
44
 
45
45
  def self.run(name = nil)
46
- name = ENV['OPENC3_MICROSERVICE_NAME'] unless name
46
+ name = ENV.fetch('OPENC3_MICROSERVICE_NAME', nil) unless name
47
47
  microservice = self.new(name)
48
48
  thread = Thread.new do
49
49
  begin
@@ -150,7 +150,7 @@ module OpenC3
150
150
  cmd_array = @config["cmd"]
151
151
 
152
152
  # Get Microservice files from bucket storage
153
- bucket = ENV['OPENC3_CONFIG_BUCKET']
153
+ bucket = ENV.fetch('OPENC3_CONFIG_BUCKET') { raise 'OPENC3_CONFIG_BUCKET environment variable is required' }
154
154
  client = Bucket.getClient()
155
155
 
156
156
  prefix = "#{@scope}/microservices/#{@name}/"
@@ -160,7 +160,7 @@ module OpenC3
160
160
  # unreachable while many microservices start at once. Rather than crash
161
161
  # and CrashLoopBackOff (which can outlast deploy timeouts), retry for a
162
162
  # bounded time before giving up.
163
- startup_timeout = (ENV['OPENC3_MICROSERVICE_STARTUP_BUCKET_TIMEOUT'] || 60).to_f
163
+ startup_timeout = (ENV.fetch('OPENC3_MICROSERVICE_STARTUP_BUCKET_TIMEOUT', 60)).to_f
164
164
  startup_deadline = Time.now + startup_timeout
165
165
  begin
166
166
  file_count = 0
@@ -1,6 +1,6 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- # Copyright 2024 OpenC3 Inc.
3
+ # Copyright 2026 OpenC3, Inc.
4
4
  # All Rights Reserved.
5
5
  #
6
6
  # This program is distributed in the hope that it will be useful,
@@ -46,8 +46,8 @@ module OpenC3
46
46
  NewsModel.news_error("Error contacting OpenC3 news feed (status: #{response.status})")
47
47
  end
48
48
  end
49
- rescue Exception => e
50
- NewsModel.news_error("Error contacting OpenC3 news feed. #{e.message})")
49
+ rescue StandardError => e
50
+ NewsModel.news_error("Error contacting OpenC3 news feed. #{e.message}")
51
51
  end
52
52
 
53
53
  def run
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,38 @@
1
+ # Copyright 2026 OpenC3, Inc.
2
+ # All Rights Reserved.
3
+ #
4
+ # This program is distributed in the hope that it will be useful,
5
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
6
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7
+ # See LICENSE.md for more details.
8
+
9
+ # This file may also be used under the terms of a commercial license
10
+ # if purchased from OpenC3, Inc.
11
+
12
+ require 'openc3/utilities/migration'
13
+ require 'openc3/models/scope_model'
14
+ require 'openc3/models/microservice_model'
15
+ require 'openc3/models/bridge_model'
16
+
17
+ module OpenC3
18
+ # Ensure every existing scope has a DEFAULT bridge_microservice (the Iroh hub
19
+ # that lets openc3-app run COSMOS interfaces on the host). New scopes get one
20
+ # via ScopeModel#deploy; this backfills any scope created before that.
21
+ class DefaultBridge < Migration
22
+ def self.run
23
+ ScopeModel.get_all_models(scope: nil).each do |scope, scope_model|
24
+ name = "#{scope}__BRIDGE__DEFAULT"
25
+ next if MicroserviceModel.get_model(name: name, scope: scope)
26
+
27
+ microservice = BridgeModel.build_microservice(bridge_name: "DEFAULT", scope: scope, shard: scope_model.shard)
28
+ microservice.create
29
+ microservice.deploy
30
+ Logger.info("Added DEFAULT bridge_microservice to scope #{scope}")
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ unless ENV['OPENC3_NO_MIGRATE']
37
+ OpenC3::DefaultBridge.run
38
+ end
@@ -1,3 +1,14 @@
1
+ # Copyright 2026 OpenC3, Inc.
2
+ # All Rights Reserved.
3
+ #
4
+ # This program is distributed in the hope that it will be useful,
5
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
6
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7
+ # See LICENSE.md for more details.
8
+ #
9
+ # This file may also be used under the terms of a commercial license
10
+ # if purchased from OpenC3, Inc.
11
+
1
12
  require 'json'
2
13
  require 'openc3/utilities/local_mode'
3
14
  require 'openc3/utilities/migration'
File without changes
@@ -27,7 +27,7 @@ module OpenC3
27
27
  PRIMARY_KEY = 'OPENC3__TOKEN' # for argon2 password hash
28
28
  SESSIONS_KEY = 'OPENC3__SESSIONS' # for hash containing session tokens
29
29
 
30
- # The length of time in minutes to keep redis values in memory
30
+ # The length of time in seconds to keep redis values in memory
31
31
  PW_HASH_CACHE_TIMEOUT = 5
32
32
  SESSION_CACHE_TIMEOUT = 5
33
33
 
@@ -44,6 +44,21 @@ module OpenC3
44
44
  SESSION_PREFIX = "ses_"
45
45
  OTP_PREFIX = "otp_"
46
46
 
47
+ # A session token is SESSION_PREFIX followed by the unpadded urlsafe base64
48
+ # encoding of 16 random bytes, i.e. exactly 22 characters of [A-Za-z0-9_-].
49
+ # Keep this in sync with generate_session.
50
+ SESSION_TOKEN_REGEX = /\A#{SESSION_PREFIX}[A-Za-z0-9_-]{22}\z/
51
+
52
+ # Whether the given value could have been produced by generate_session.
53
+ # Callers handling a token from an unauthenticated request use this to
54
+ # reject garbage before doing any Redis work. Checking only the prefix is
55
+ # not enough: something like "ses_AAA" would pass and still cost us a read.
56
+ # @param token [String] the value to check
57
+ # @return [Boolean] whether the value is shaped like a session token
58
+ def self.session_token?(token)
59
+ SESSION_TOKEN_REGEX.match?(token.to_s)
60
+ end
61
+
47
62
  def self.set?(key = PRIMARY_KEY)
48
63
  Store.exists(key) == 1
49
64
  end
@@ -56,7 +71,7 @@ module OpenC3
56
71
  def self.verify(token, no_password: true, service_only: false)
57
72
  # Handle a service password - Generally only used by ScriptRunner
58
73
  # TODO: Replace this with temporary service tokens
59
- service_password = ENV['OPENC3_SERVICE_PASSWORD']
74
+ service_password = ENV.fetch('OPENC3_SERVICE_PASSWORD', nil)
60
75
  return true if service_password and service_password == token
61
76
 
62
77
  return false if service_only
@@ -78,15 +93,28 @@ module OpenC3
78
93
  # Check cached session tokens and password hash
79
94
  time = Time.now
80
95
  unless mode == :password
81
- if @@session_cache and (time - @@session_cache_time) < SESSION_CACHE_TIMEOUT and @@session_cache[token]
96
+ # Drop the whole cache once it ages out rather than tracking per token
97
+ # times. This bounds how long a terminated token keeps working to
98
+ # SESSION_CACHE_TIMEOUT, same as before.
99
+ if @@session_cache.nil? or (time - @@session_cache_time) >= SESSION_CACHE_TIMEOUT
100
+ @@session_cache = {}
101
+ @@session_cache_time = time
102
+ end
103
+
104
+ if @@session_cache[token]
82
105
  terminate_otp(token)
83
106
  return true
84
107
  end
85
108
 
86
- # Check stored session tokens
87
- @@session_cache = Store.hgetall(SESSIONS_KEY)
88
- @@session_cache_time = time
89
- if @@session_cache[token]
109
+ # Check the stored session tokens for just this token. Deliberately not
110
+ # HGETALL: verify_token is unauthenticated, so reading the entire
111
+ # session hash here lets any caller make us pull every session ever
112
+ # created on every request, and that hash only grows. HGET is O(1) and
113
+ # can't be amplified. The cache then fills with the tokens actually in
114
+ # use instead of all of them.
115
+ stored = Store.hget(SESSIONS_KEY, token)
116
+ if stored
117
+ @@session_cache[token] = stored
90
118
  terminate_otp(token)
91
119
  return true
92
120
  end