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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Guardfile +0 -0
- data/LICENSE.md +0 -0
- data/README.md +0 -0
- data/Rakefile +0 -0
- data/bin/openc3cli +138 -0
- data/bin/pipuninstall +0 -0
- data/bin/uvinstall +10 -3
- data/data/config/_array_params.yaml +0 -0
- data/data/config/_canvas_values.yaml +0 -0
- data/data/config/_graph_params.yaml +0 -0
- data/data/config/_id_items.yaml +0 -0
- data/data/config/_id_params.yaml +0 -0
- data/data/config/_interfaces.yaml +0 -0
- data/data/config/_items.yaml +0 -0
- data/data/config/_params.yaml +0 -0
- data/data/config/command.yaml +0 -0
- data/data/config/command_modifiers.yaml +2 -0
- data/data/config/command_telemetry.yaml +0 -0
- data/data/config/conversions.yaml +0 -0
- data/data/config/graph_settings.yaml +0 -0
- data/data/config/interface_modifiers.yaml +103 -1
- data/data/config/item_modifiers.yaml +0 -0
- data/data/config/microservice.yaml +5 -2
- data/data/config/param_item_modifiers.yaml +0 -0
- data/data/config/parameter_modifiers.yaml +0 -0
- data/data/config/plugins.yaml +0 -0
- data/data/config/processors.yaml +0 -0
- data/data/config/protocols.yaml +0 -0
- data/data/config/screen.yaml +0 -0
- data/data/config/settings.yaml +0 -0
- data/data/config/table_manager.yaml +0 -0
- data/data/config/table_parameter_modifiers.yaml +0 -0
- data/data/config/target.yaml +0 -0
- data/data/config/target_config.yaml +0 -0
- data/data/config/telemetry.yaml +0 -0
- data/data/config/telemetry_modifiers.yaml +2 -0
- data/data/config/tool.yaml +0 -0
- data/data/config/unknown.yaml +0 -0
- data/data/config/widgets.yaml +6 -0
- data/data/xtce_schemas/SpaceSystem_20180204.xsd +0 -0
- data/data/xtce_schemas/xml.xsd +0 -0
- data/ext/openc3/ext/array/array.c +0 -0
- data/ext/openc3/ext/array/extconf.rb +0 -0
- data/ext/openc3/ext/buffered_file/buffered_file.c +0 -0
- data/ext/openc3/ext/buffered_file/extconf.rb +0 -0
- data/ext/openc3/ext/burst_protocol/burst_protocol.c +6 -0
- data/ext/openc3/ext/burst_protocol/extconf.rb +0 -0
- data/ext/openc3/ext/config_parser/config_parser.c +0 -0
- data/ext/openc3/ext/config_parser/extconf.rb +0 -0
- data/ext/openc3/ext/crc/crc.c +0 -0
- data/ext/openc3/ext/crc/extconf.rb +0 -0
- data/ext/openc3/ext/openc3_io/extconf.rb +0 -0
- data/ext/openc3/ext/openc3_io/openc3_io.c +0 -0
- data/ext/openc3/ext/packet/extconf.rb +0 -0
- data/ext/openc3/ext/packet/packet.c +0 -0
- data/ext/openc3/ext/platform/extconf.rb +0 -0
- data/ext/openc3/ext/platform/platform.c +4 -1
- data/ext/openc3/ext/polynomial_conversion/extconf.rb +0 -0
- data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +0 -0
- data/ext/openc3/ext/string/extconf.rb +0 -0
- data/ext/openc3/ext/string/string.c +0 -0
- data/ext/openc3/ext/structure/structure.c +49 -17
- data/ext/openc3/ext/tabbed_plots_config/extconf.rb +0 -0
- data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +0 -0
- data/ext/openc3/ext/telemetry/extconf.rb +0 -0
- data/ext/openc3/ext/telemetry/telemetry.c +0 -0
- data/lib/cosmos.rb +0 -0
- data/lib/cosmosc2.rb +0 -0
- data/lib/openc3/accessors/accessor.rb +0 -0
- data/lib/openc3/accessors/binary_accessor.rb +63 -9
- data/lib/openc3/accessors/cbor_accessor.rb +0 -0
- data/lib/openc3/accessors/form_accessor.rb +0 -0
- data/lib/openc3/accessors/html_accessor.rb +0 -0
- data/lib/openc3/accessors/http_accessor.rb +0 -0
- data/lib/openc3/accessors/json_accessor.rb +0 -0
- data/lib/openc3/accessors/template_accessor.rb +0 -0
- data/lib/openc3/accessors/xml_accessor.rb +0 -0
- data/lib/openc3/accessors.rb +0 -0
- data/lib/openc3/api/README.md +0 -0
- data/lib/openc3/api/api.rb +0 -0
- data/lib/openc3/api/authorized_api.rb +0 -0
- data/lib/openc3/api/calendar_api.rb +0 -0
- data/lib/openc3/api/cmd_api.rb +1 -1
- data/lib/openc3/api/config_api.rb +0 -0
- data/lib/openc3/api/interface_api.rb +0 -0
- data/lib/openc3/api/limits_api.rb +0 -0
- data/lib/openc3/api/metrics_api.rb +1 -1
- data/lib/openc3/api/offline_access_api.rb +1 -1
- data/lib/openc3/api/router_api.rb +0 -0
- data/lib/openc3/api/settings_api.rb +22 -18
- data/lib/openc3/api/stash_api.rb +1 -1
- data/lib/openc3/api/target_api.rb +0 -0
- data/lib/openc3/api/tlm_api.rb +4 -3
- data/lib/openc3/bridge/bridge.rb +0 -0
- data/lib/openc3/bridge/bridge_config.rb +0 -0
- data/lib/openc3/bridge/bridge_interface_thread.rb +0 -0
- data/lib/openc3/bridge/bridge_router_thread.rb +0 -0
- data/lib/openc3/ccsds/ccsds_packet.rb +0 -0
- data/lib/openc3/ccsds/ccsds_parser.rb +0 -0
- data/lib/openc3/config/config_parser.rb +78 -17
- data/lib/openc3/config/meta_config_parser.rb +0 -0
- data/lib/openc3/conversions/bit_reverse_conversion.rb +0 -0
- data/lib/openc3/conversions/conversion.rb +0 -0
- data/lib/openc3/conversions/generic_conversion.rb +0 -0
- data/lib/openc3/conversions/ip_read_conversion.rb +0 -0
- data/lib/openc3/conversions/ip_write_conversion.rb +0 -0
- data/lib/openc3/conversions/object_read_conversion.rb +0 -0
- data/lib/openc3/conversions/object_write_conversion.rb +0 -0
- data/lib/openc3/conversions/packet_time_formatted_conversion.rb +0 -0
- data/lib/openc3/conversions/packet_time_seconds_conversion.rb +0 -0
- data/lib/openc3/conversions/polynomial_conversion.rb +0 -0
- data/lib/openc3/conversions/processor_conversion.rb +0 -0
- data/lib/openc3/conversions/received_count_conversion.rb +0 -0
- data/lib/openc3/conversions/received_time_formatted_conversion.rb +0 -0
- data/lib/openc3/conversions/received_time_seconds_conversion.rb +0 -0
- data/lib/openc3/conversions/segmented_polynomial_conversion.rb +0 -0
- data/lib/openc3/conversions/unix_time_conversion.rb +0 -0
- data/lib/openc3/conversions/unix_time_formatted_conversion.rb +0 -0
- data/lib/openc3/conversions/unix_time_seconds_conversion.rb +0 -0
- data/lib/openc3/conversions.rb +0 -0
- data/lib/openc3/core_ext/array.rb +0 -0
- data/lib/openc3/core_ext/binding.rb +0 -0
- data/lib/openc3/core_ext/class.rb +0 -0
- data/lib/openc3/core_ext/exception.rb +0 -0
- data/lib/openc3/core_ext/faraday.rb +0 -0
- data/lib/openc3/core_ext/file.rb +0 -0
- data/lib/openc3/core_ext/io.rb +0 -0
- data/lib/openc3/core_ext/kernel.rb +0 -0
- data/lib/openc3/core_ext/math.rb +0 -0
- data/lib/openc3/core_ext/matrix.rb +0 -0
- data/lib/openc3/core_ext/objectspace.rb +0 -0
- data/lib/openc3/core_ext/openc3_io.rb +0 -0
- data/lib/openc3/core_ext/range.rb +0 -0
- data/lib/openc3/core_ext/socket.rb +0 -0
- data/lib/openc3/core_ext/string.rb +0 -0
- data/lib/openc3/core_ext/stringio.rb +0 -0
- data/lib/openc3/core_ext/tempfile.rb +0 -0
- data/lib/openc3/core_ext/time.rb +0 -0
- data/lib/openc3/core_ext.rb +0 -0
- data/lib/openc3/ext/.keep +0 -0
- data/lib/openc3/interfaces/file_interface.rb +0 -0
- data/lib/openc3/interfaces/http_client_interface.rb +0 -0
- data/lib/openc3/interfaces/http_server_interface.rb +0 -0
- data/lib/openc3/interfaces/interface.rb +5 -4
- data/lib/openc3/interfaces/mqtt_interface.rb +0 -0
- data/lib/openc3/interfaces/mqtt_stream_interface.rb +2 -0
- data/lib/openc3/interfaces/protocols/burst_protocol.rb +27 -0
- data/lib/openc3/interfaces/protocols/cmd_response_protocol.rb +0 -0
- data/lib/openc3/interfaces/protocols/cobs_protocol.rb +0 -0
- data/lib/openc3/interfaces/protocols/crc_protocol.rb +0 -0
- data/lib/openc3/interfaces/protocols/fixed_protocol.rb +0 -0
- data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +0 -0
- data/lib/openc3/interfaces/protocols/length_protocol.rb +7 -0
- data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +7 -0
- data/lib/openc3/interfaces/protocols/protocol.rb +4 -4
- data/lib/openc3/interfaces/protocols/slip_protocol.rb +0 -0
- data/lib/openc3/interfaces/protocols/template_protocol.rb +2 -2
- data/lib/openc3/interfaces/protocols/terminated_protocol.rb +0 -0
- data/lib/openc3/interfaces/serial_interface.rb +2 -0
- data/lib/openc3/interfaces/simulated_target_interface.rb +0 -0
- data/lib/openc3/interfaces/stream_interface.rb +0 -0
- data/lib/openc3/interfaces/tcpip_client_interface.rb +2 -0
- data/lib/openc3/interfaces/tcpip_server_interface.rb +0 -0
- data/lib/openc3/interfaces/udp_interface.rb +16 -5
- data/lib/openc3/interfaces.rb +0 -0
- data/lib/openc3/io/buffered_file.rb +0 -0
- data/lib/openc3/io/io_multiplexer.rb +0 -0
- data/lib/openc3/io/json_api.rb +3 -2
- data/lib/openc3/io/json_api_object.rb +0 -0
- data/lib/openc3/io/json_drb.rb +20 -4
- data/lib/openc3/io/json_drb_object.rb +0 -0
- data/lib/openc3/io/json_drb_rack.rb +0 -0
- data/lib/openc3/io/json_rpc.rb +0 -0
- data/lib/openc3/io/posix_serial_driver.rb +0 -0
- data/lib/openc3/io/serial_driver.rb +0 -0
- data/lib/openc3/io/stderr.rb +0 -0
- data/lib/openc3/io/stdout.rb +0 -0
- data/lib/openc3/io/udp_sockets.rb +38 -8
- data/lib/openc3/io/win32_serial_driver.rb +1 -0
- data/lib/openc3/logs/buffered_packet_log_reader.rb +0 -0
- data/lib/openc3/logs/buffered_packet_log_writer.rb +0 -0
- data/lib/openc3/logs/log_writer.rb +0 -0
- data/lib/openc3/logs/packet_log_constants.rb +0 -0
- data/lib/openc3/logs/packet_log_reader.rb +23 -2
- data/lib/openc3/logs/packet_log_writer.rb +5 -0
- data/lib/openc3/logs/stream_log.rb +1 -1
- data/lib/openc3/logs/stream_log_pair.rb +0 -0
- data/lib/openc3/logs/text_log_writer.rb +0 -0
- data/lib/openc3/logs.rb +0 -0
- data/lib/openc3/microservices/cleanup_microservice.rb +0 -0
- data/lib/openc3/microservices/decom_common.rb +0 -0
- data/lib/openc3/microservices/decom_microservice.rb +0 -0
- data/lib/openc3/microservices/interface_decom_common.rb +2 -1
- data/lib/openc3/microservices/interface_microservice.rb +72 -25
- data/lib/openc3/microservices/log_microservice.rb +0 -0
- data/lib/openc3/microservices/microservice.rb +3 -3
- data/lib/openc3/microservices/multi_microservice.rb +1 -1
- data/lib/openc3/microservices/periodic_microservice.rb +2 -2
- data/lib/openc3/microservices/plugin_microservice.rb +0 -0
- data/lib/openc3/microservices/queue_microservice.rb +0 -0
- data/lib/openc3/microservices/router_microservice.rb +0 -0
- data/lib/openc3/microservices/scope_cleanup_microservice.rb +0 -0
- data/lib/openc3/microservices/text_log_microservice.rb +0 -0
- data/lib/openc3/migrations/20220420190000_log_stuff.rb +0 -0
- data/lib/openc3/migrations/20221202214600_add_target_names.rb +0 -0
- data/lib/openc3/migrations/20221210174900_convert_to_multi.rb +0 -0
- data/lib/openc3/migrations/20230915000002_no_scope_log_messages.rb +0 -0
- data/lib/openc3/migrations/20231022000000_tlm_viewer_config.rb +0 -0
- data/lib/openc3/migrations/20241208080000_no_critical_cmd.rb +0 -0
- data/lib/openc3/migrations/20241208080001_no_trigger_group.rb +0 -0
- data/lib/openc3/migrations/20250108060000_news_feed.rb +0 -0
- data/lib/openc3/migrations/20250402000000_periodic_only_default.rb +0 -0
- data/lib/openc3/migrations/20260203000000_remove_store_id.rb +0 -0
- data/lib/openc3/migrations/20260204000000_remove_decom_reducer.rb +0 -0
- data/lib/openc3/migrations/20260701000000_updated_at_to_int.rb +0 -0
- data/lib/openc3/migrations/20260704000000_default_bridge.rb +38 -0
- data/lib/openc3/migrations/20260731000000_system_health_json.rb +11 -0
- data/lib/openc3/models/activity_model.rb +0 -0
- data/lib/openc3/models/auth_model.rb +35 -7
- data/lib/openc3/models/bridge_model.rb +133 -0
- data/lib/openc3/models/config_keyword_model.rb +63 -0
- data/lib/openc3/models/cvt_model.rb +0 -0
- data/lib/openc3/models/db_sharded_model.rb +0 -0
- data/lib/openc3/models/environment_model.rb +0 -0
- data/lib/openc3/models/gem_model.rb +12 -9
- data/lib/openc3/models/host_interface_microservice_model.rb +114 -0
- data/lib/openc3/models/info_model.rb +0 -0
- data/lib/openc3/models/interface_model.rb +178 -19
- data/lib/openc3/models/interface_status_model.rb +0 -0
- data/lib/openc3/models/metadata_model.rb +0 -0
- data/lib/openc3/models/metric_model.rb +0 -0
- data/lib/openc3/models/microservice_model.rb +9 -22
- data/lib/openc3/models/microservice_status_model.rb +0 -0
- data/lib/openc3/models/migration_model.rb +0 -0
- data/lib/openc3/models/model.rb +0 -0
- data/lib/openc3/models/news_model.rb +0 -0
- data/lib/openc3/models/note_model.rb +0 -0
- data/lib/openc3/models/offline_access_model.rb +0 -0
- data/lib/openc3/models/ping_model.rb +0 -0
- data/lib/openc3/models/plugin_model.rb +9 -2
- data/lib/openc3/models/plugin_store_model.rb +0 -0
- data/lib/openc3/models/process_status_model.rb +0 -0
- data/lib/openc3/models/python_package_model.rb +4 -4
- data/lib/openc3/models/queue_model.rb +0 -0
- data/lib/openc3/models/reaction_model.rb +0 -0
- data/lib/openc3/models/reingest_job_model.rb +0 -0
- data/lib/openc3/models/router_model.rb +0 -0
- data/lib/openc3/models/router_status_model.rb +0 -0
- data/lib/openc3/models/scope_model.rb +51 -26
- data/lib/openc3/models/script_engine_model.rb +0 -0
- data/lib/openc3/models/script_status_model.rb +0 -0
- data/lib/openc3/models/secret_model.rb +0 -0
- data/lib/openc3/models/setting_model.rb +546 -3
- data/lib/openc3/models/sorted_model.rb +0 -0
- data/lib/openc3/models/stash_model.rb +0 -0
- data/lib/openc3/models/target_model.rb +30 -25
- data/lib/openc3/models/timeline_model.rb +0 -0
- data/lib/openc3/models/tool_config_model.rb +0 -0
- data/lib/openc3/models/tool_model.rb +1 -0
- data/lib/openc3/models/trigger_group_model.rb +0 -0
- data/lib/openc3/models/trigger_model.rb +20 -0
- data/lib/openc3/models/widget_model.rb +0 -0
- data/lib/openc3/operators/microservice_operator.rb +64 -22
- data/lib/openc3/operators/operator.rb +4 -4
- data/lib/openc3/packets/binary_accessor.rb +0 -0
- data/lib/openc3/packets/command_validator.rb +0 -0
- data/lib/openc3/packets/commands.rb +0 -0
- data/lib/openc3/packets/json_packet.rb +0 -0
- data/lib/openc3/packets/limits.rb +0 -0
- data/lib/openc3/packets/limits_response.rb +0 -0
- data/lib/openc3/packets/packet.rb +4 -0
- data/lib/openc3/packets/packet_config.rb +0 -0
- data/lib/openc3/packets/packet_item.rb +0 -0
- data/lib/openc3/packets/packet_item_limits.rb +0 -0
- data/lib/openc3/packets/parsers/format_string_parser.rb +0 -0
- data/lib/openc3/packets/parsers/limits_parser.rb +0 -0
- data/lib/openc3/packets/parsers/limits_response_parser.rb +0 -0
- data/lib/openc3/packets/parsers/packet_item_parser.rb +0 -0
- data/lib/openc3/packets/parsers/packet_parser.rb +0 -0
- data/lib/openc3/packets/parsers/processor_parser.rb +0 -0
- data/lib/openc3/packets/parsers/state_parser.rb +0 -0
- data/lib/openc3/packets/parsers/xtce_converter.rb +0 -0
- data/lib/openc3/packets/parsers/xtce_parser.rb +0 -0
- data/lib/openc3/packets/structure.rb +7 -1
- data/lib/openc3/packets/structure_item.rb +0 -0
- data/lib/openc3/packets/telemetry.rb +0 -0
- data/lib/openc3/processors/processor.rb +2 -0
- data/lib/openc3/processors/statistics_processor.rb +0 -0
- data/lib/openc3/processors/watermark_processor.rb +0 -0
- data/lib/openc3/processors.rb +0 -0
- data/lib/openc3/script/api_shared.rb +0 -0
- data/lib/openc3/script/autonomic.rb +12 -12
- data/lib/openc3/script/calendar.rb +0 -0
- data/lib/openc3/script/commands.rb +0 -0
- data/lib/openc3/script/critical_cmd.rb +0 -0
- data/lib/openc3/script/exceptions.rb +0 -0
- data/lib/openc3/script/extract.rb +0 -0
- data/lib/openc3/script/limits.rb +0 -0
- data/lib/openc3/script/metadata.rb +0 -0
- data/lib/openc3/script/packages.rb +0 -0
- data/lib/openc3/script/plugins.rb +0 -0
- data/lib/openc3/script/queue.rb +0 -0
- data/lib/openc3/script/screen.rb +0 -0
- data/lib/openc3/script/script.rb +2 -2
- data/lib/openc3/script/script_runner.rb +0 -0
- data/lib/openc3/script/storage.rb +4 -4
- data/lib/openc3/script/suite.rb +0 -0
- data/lib/openc3/script/suite_results.rb +0 -0
- data/lib/openc3/script/suite_runner.rb +26 -0
- data/lib/openc3/script/tables.rb +0 -0
- data/lib/openc3/script/telemetry.rb +9 -3
- data/lib/openc3/script/web_socket_api.rb +218 -145
- data/lib/openc3/script.rb +0 -0
- data/lib/openc3/script_engines/script_engine.rb +0 -0
- data/lib/openc3/streams/mqtt_stream.rb +0 -0
- data/lib/openc3/streams/serial_stream.rb +0 -0
- data/lib/openc3/streams/stream.rb +0 -0
- data/lib/openc3/streams/tcpip_client_stream.rb +0 -0
- data/lib/openc3/streams/tcpip_socket_stream.rb +0 -0
- data/lib/openc3/streams/web_socket_client_stream.rb +0 -0
- data/lib/openc3/subpacketizers/subpacketizer.rb +0 -0
- data/lib/openc3/system/system.rb +0 -0
- data/lib/openc3/system/target.rb +0 -0
- data/lib/openc3/system.rb +0 -0
- data/lib/openc3/tools/cmd_tlm_server/api.rb +0 -0
- data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +7 -0
- data/lib/openc3/tools/table_manager/table.rb +0 -0
- data/lib/openc3/tools/table_manager/table_config.rb +0 -0
- data/lib/openc3/tools/table_manager/table_item.rb +0 -0
- data/lib/openc3/tools/table_manager/table_item_parser.rb +0 -0
- data/lib/openc3/tools/table_manager/table_manager_core.rb +0 -0
- data/lib/openc3/tools/table_manager/table_parser.rb +0 -0
- data/lib/openc3/tools/test_runner/test.rb +0 -0
- data/lib/openc3/top_level.rb +1 -1
- data/lib/openc3/topics/autonomic_topic.rb +0 -0
- data/lib/openc3/topics/calendar_topic.rb +0 -0
- data/lib/openc3/topics/command_decom_topic.rb +0 -0
- data/lib/openc3/topics/command_topic.rb +0 -0
- data/lib/openc3/topics/config_topic.rb +0 -0
- data/lib/openc3/topics/decom_interface_topic.rb +2 -1
- data/lib/openc3/topics/interface_topic.rb +8 -2
- data/lib/openc3/topics/limits_event_topic.rb +0 -0
- data/lib/openc3/topics/notebook_topic.rb +0 -0
- data/lib/openc3/topics/queue_topic.rb +0 -0
- data/lib/openc3/topics/router_topic.rb +6 -1
- data/lib/openc3/topics/system_events_topic.rb +0 -0
- data/lib/openc3/topics/telemetry_decom_topic.rb +0 -0
- data/lib/openc3/topics/telemetry_topic.rb +0 -0
- data/lib/openc3/topics/timeline_topic.rb +0 -0
- data/lib/openc3/topics/topic.rb +0 -0
- data/lib/openc3/utilities/authentication.rb +4 -4
- data/lib/openc3/utilities/authorization.rb +0 -0
- data/lib/openc3/utilities/aws_bucket.rb +2 -2
- data/lib/openc3/utilities/bucket.rb +1 -1
- data/lib/openc3/utilities/bucket_file_cache.rb +55 -22
- data/lib/openc3/utilities/bucket_require.rb +0 -0
- data/lib/openc3/utilities/bucket_utilities.rb +3 -4
- data/lib/openc3/utilities/cli_generator.rb +0 -0
- data/lib/openc3/utilities/cmd_log.rb +0 -0
- data/lib/openc3/utilities/config_overlay.rb +75 -0
- data/lib/openc3/utilities/cosmos_rails_formatter.rb +0 -0
- data/lib/openc3/utilities/crc.rb +59 -32
- data/lib/openc3/utilities/csv.rb +0 -0
- data/lib/openc3/utilities/ctrf.rb +0 -0
- data/lib/openc3/utilities/env_helper.rb +0 -0
- data/lib/openc3/utilities/local_bucket.rb +0 -0
- data/lib/openc3/utilities/local_mode.rb +32 -6
- data/lib/openc3/utilities/logger.rb +30 -8
- data/lib/openc3/utilities/message_log.rb +0 -0
- data/lib/openc3/utilities/metric.rb +0 -0
- data/lib/openc3/utilities/migration.rb +0 -0
- data/lib/openc3/utilities/open_telemetry.rb +0 -0
- data/lib/openc3/utilities/process_manager.rb +0 -0
- data/lib/openc3/utilities/pypi_url.rb +0 -0
- data/lib/openc3/utilities/python_proxy.rb +0 -0
- data/lib/openc3/utilities/python_venv.rb +135 -0
- data/lib/openc3/utilities/quaternion.rb +0 -0
- data/lib/openc3/utilities/questdb_client.rb +0 -0
- data/lib/openc3/utilities/redis_secrets.rb +0 -0
- data/lib/openc3/utilities/reingest_job.rb +0 -0
- data/lib/openc3/utilities/ruby_lex_utils.rb +0 -0
- data/lib/openc3/utilities/rubygems_url.rb +39 -0
- data/lib/openc3/utilities/running_script.rb +24 -55
- data/lib/openc3/utilities/s3_autoload.rb +5 -5
- data/lib/openc3/utilities/script.rb +12 -8
- data/lib/openc3/utilities/secrets.rb +48 -3
- data/lib/openc3/utilities/simulated_target.rb +0 -0
- data/lib/openc3/utilities/sleeper.rb +0 -0
- data/lib/openc3/utilities/store.rb +0 -0
- data/lib/openc3/utilities/store_autoload.rb +2 -2
- data/lib/openc3/utilities/store_queued.rb +0 -0
- data/lib/openc3/utilities/target_file.rb +18 -1
- data/lib/openc3/utilities/thread_manager.rb +0 -0
- data/lib/openc3/utilities/throttle.rb +0 -0
- data/lib/openc3/utilities/zip.rb +0 -0
- data/lib/openc3/utilities.rb +0 -0
- data/lib/openc3/version.rb +5 -5
- data/lib/openc3/win32/excel.rb +0 -0
- data/lib/openc3/win32/win32.rb +0 -0
- data/lib/openc3/win32/win32_main.rb +0 -0
- data/lib/openc3.rb +2 -2
- data/tasks/gemfile_stats.rake +0 -0
- data/tasks/spec.rake +0 -0
- data/templates/command_validator/command_validator.py +0 -0
- data/templates/command_validator/command_validator.rb +0 -0
- data/templates/conversion/conversion.py +0 -0
- data/templates/conversion/conversion.rb +0 -0
- data/templates/limits_response/response.py +0 -0
- data/templates/limits_response/response.rb +0 -0
- data/templates/microservice/microservices/TEMPLATE/microservice.py +0 -0
- data/templates/microservice/microservices/TEMPLATE/microservice.rb +0 -0
- data/templates/plugin/.gitignore +0 -0
- data/templates/plugin/LICENSE.md +0 -0
- data/templates/plugin/README.md +0 -0
- data/templates/plugin/Rakefile +0 -0
- data/templates/plugin/plugin.gemspec +0 -0
- data/templates/plugin/plugin.txt +0 -0
- data/templates/processor/processor.py +1 -1
- data/templates/processor/processor.rb +0 -0
- data/templates/target/targets/TARGET/cmd_tlm/cmd.txt +0 -0
- data/templates/target/targets/TARGET/cmd_tlm/tlm.txt +0 -0
- data/templates/target/targets/TARGET/lib/target.py +0 -0
- data/templates/target/targets/TARGET/lib/target.rb +0 -0
- data/templates/target/targets/TARGET/procedures/procedure.py +0 -0
- data/templates/target/targets/TARGET/procedures/procedure.rb +0 -0
- data/templates/target/targets/TARGET/public/README.txt +0 -0
- data/templates/target/targets/TARGET/screens/status.txt +0 -0
- data/templates/target/targets/TARGET/target.txt +0 -0
- data/templates/tool_angular/.editorconfig +0 -0
- data/templates/tool_angular/.gitignore +0 -0
- data/templates/tool_angular/.vscode/extensions.json +0 -0
- data/templates/tool_angular/.vscode/launch.json +0 -0
- data/templates/tool_angular/.vscode/tasks.json +0 -0
- data/templates/tool_angular/angular.json +0 -0
- data/templates/tool_angular/extra-webpack.config.js +0 -0
- data/templates/tool_angular/package.json +2 -2
- data/templates/tool_angular/src/app/app-routing.module.ts +0 -0
- data/templates/tool_angular/src/app/app.component.html +0 -0
- data/templates/tool_angular/src/app/app.component.scss +0 -0
- data/templates/tool_angular/src/app/app.component.spec.ts +0 -0
- data/templates/tool_angular/src/app/app.component.ts +0 -0
- data/templates/tool_angular/src/app/app.module.ts +0 -0
- data/templates/tool_angular/src/app/custom-overlay-container.ts +0 -0
- data/templates/tool_angular/src/app/empty-route/empty-route.component.ts +0 -0
- data/templates/tool_angular/src/app/openc3-api.d.ts +0 -0
- data/templates/tool_angular/src/assets/.gitkeep +0 -0
- data/templates/tool_angular/src/environments/environment.prod.ts +0 -0
- data/templates/tool_angular/src/environments/environment.ts +0 -0
- data/templates/tool_angular/src/favicon.ico +0 -0
- data/templates/tool_angular/src/index.html +0 -0
- data/templates/tool_angular/src/main.single-spa.ts +0 -0
- data/templates/tool_angular/src/single-spa/asset-url.ts +0 -0
- data/templates/tool_angular/src/single-spa/single-spa-props.ts +0 -0
- data/templates/tool_angular/src/styles.scss +0 -0
- data/templates/tool_angular/tsconfig.app.json +0 -0
- data/templates/tool_angular/tsconfig.json +0 -0
- data/templates/tool_angular/tsconfig.spec.json +0 -0
- data/templates/tool_react/.eslintrc +0 -0
- data/templates/tool_react/.gitignore +0 -0
- data/templates/tool_react/.prettierignore +0 -0
- data/templates/tool_react/babel.config.json +0 -0
- data/templates/tool_react/jest.config.js +0 -0
- data/templates/tool_react/package.json +1 -1
- data/templates/tool_react/src/openc3-tool_name.js +0 -0
- data/templates/tool_react/src/root.component.js +0 -0
- data/templates/tool_react/src/root.component.test.js +0 -0
- data/templates/tool_react/webpack.config.js +0 -0
- data/templates/tool_svelte/.gitignore +0 -0
- data/templates/tool_svelte/.prettierignore +0 -0
- data/templates/tool_svelte/.prettierrc.js +0 -0
- data/templates/tool_svelte/babel.config.js +0 -0
- data/templates/tool_svelte/build/smui.css +0 -0
- data/templates/tool_svelte/jest.config.js +0 -0
- data/templates/tool_svelte/package.json +1 -1
- data/templates/tool_svelte/rollup.config.js +0 -0
- data/templates/tool_svelte/src/App.svelte +0 -0
- data/templates/tool_svelte/src/App.test.js +0 -0
- data/templates/tool_svelte/src/theme/_smui-theme.scss +0 -0
- data/templates/tool_svelte/src/tool_name.js +0 -0
- data/templates/tool_vue/.env.standalone +0 -0
- data/templates/tool_vue/.gitignore +0 -0
- data/templates/tool_vue/.prettierrc.cjs +0 -0
- data/templates/tool_vue/eslint.config.mjs +0 -0
- data/templates/tool_vue/jsconfig.json +0 -0
- data/templates/tool_vue/package.json +3 -3
- data/templates/tool_vue/src/App.vue +0 -0
- data/templates/tool_vue/src/main.js +0 -0
- data/templates/tool_vue/src/router.js +0 -0
- data/templates/tool_vue/src/tools/tool_name/tool_name.vue +0 -0
- data/templates/tool_vue/vite.config.js +1 -1
- data/templates/widget/.prettierrc.cjs +0 -0
- data/templates/widget/LICENSE.md +0 -0
- data/templates/widget/Rakefile +0 -0
- data/templates/widget/package.json +2 -2
- data/templates/widget/src/Widget.vue +0 -0
- data/templates/widget/vite.config.js +0 -0
- metadata +36 -9
|
@@ -221,7 +221,12 @@ module OpenC3
|
|
|
221
221
|
next 'SUCCESS'
|
|
222
222
|
end
|
|
223
223
|
if msg_hash.key?('interface_details')
|
|
224
|
-
|
|
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
|
-
|
|
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
|
-
|
|
853
|
-
|
|
854
|
-
#
|
|
855
|
-
#
|
|
856
|
-
#
|
|
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
|
|
904
|
+
@interface.disconnect
|
|
860
905
|
rescue => e
|
|
861
906
|
@logger.error "Disconnect: #{@interface.name}: #{e.formatted}"
|
|
862
907
|
end
|
|
863
|
-
end
|
|
864
908
|
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
@
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
@@ -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
|
|
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
|
|
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
|
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 OpenC3, Inc.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is distributed in the hope that it will be useful,
|
|
7
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
8
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
9
|
+
# See LICENSE.md for more details.
|
|
10
|
+
#
|
|
11
|
+
# This file may also be used under the terms of a commercial license
|
|
12
|
+
# if purchased from OpenC3, Inc.
|
|
13
|
+
|
|
14
|
+
require 'openc3/models/model'
|
|
15
|
+
require 'openc3/models/microservice_model'
|
|
16
|
+
require 'base64'
|
|
17
|
+
require 'json'
|
|
18
|
+
require 'securerandom'
|
|
19
|
+
|
|
20
|
+
module OpenC3
|
|
21
|
+
# Stores the identity of a named Iroh bridge (the bridge_microservice hub).
|
|
22
|
+
#
|
|
23
|
+
# A bridge is the COSMOS-side Iroh server that openc3-app and host interfaces
|
|
24
|
+
# connect to. This model stores the bridge's Iroh public key (its EndpointId)
|
|
25
|
+
# and most recent connection ticket, plus the authorized openc3-app control
|
|
26
|
+
# identity (app_public_key) recorded during enrollment. The bridge's own
|
|
27
|
+
# private key lives in the secrets store, never here.
|
|
28
|
+
#
|
|
29
|
+
# This Ruby model mirrors the Python BridgeModel (same scoped primary key and
|
|
30
|
+
# JSON shape) so the openc3cli `bridgeenroll` command can read and update the
|
|
31
|
+
# same records the Python BridgeMicroservice maintains.
|
|
32
|
+
class BridgeModel < Model
|
|
33
|
+
PRIMARY_KEY = 'openc3_bridges'
|
|
34
|
+
ENROLLMENT_CODE_TTL_SECONDS = 10 * 60
|
|
35
|
+
|
|
36
|
+
attr_accessor :public_key
|
|
37
|
+
attr_accessor :ticket
|
|
38
|
+
attr_accessor :app_public_key
|
|
39
|
+
attr_accessor :enroll_code
|
|
40
|
+
attr_accessor :enroll_code_generated_at
|
|
41
|
+
attr_accessor :port
|
|
42
|
+
|
|
43
|
+
# The bridge stack (bridge_microservice.py) is Python and runs from the core
|
|
44
|
+
# library regardless of the interfaces bridged through it.
|
|
45
|
+
def self.bridge_python_bin
|
|
46
|
+
ENV['OPENC3_PYTHON_BIN'] || '/openc3/python/.venv/bin/python'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
BRIDGE_WORK_DIR = '/openc3/python/openc3/microservices'
|
|
50
|
+
|
|
51
|
+
# Build (but do not create) the MicroserviceModel for a bridge_microservice
|
|
52
|
+
# hub named `bridge_name` in `scope`. Centralizes the cmd/work_dir/options so
|
|
53
|
+
# ScopeModel, the DEFAULT-bridge migration, and InterfaceModel stay in sync.
|
|
54
|
+
def self.build_microservice(bridge_name:, scope:, parent: nil, shard: 0, plugin: nil)
|
|
55
|
+
microservice_name = "#{scope}__BRIDGE__#{bridge_name.to_s.upcase}"
|
|
56
|
+
MicroserviceModel.new(
|
|
57
|
+
name: microservice_name,
|
|
58
|
+
cmd: [bridge_python_bin, 'bridge_microservice.py', microservice_name],
|
|
59
|
+
work_dir: BRIDGE_WORK_DIR,
|
|
60
|
+
options: [['BRIDGE_NAME', bridge_name.to_s.upcase]],
|
|
61
|
+
parent: parent,
|
|
62
|
+
shard: shard.to_i,
|
|
63
|
+
plugin: plugin,
|
|
64
|
+
scope: scope
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# NOTE: The following three class methods are reimplemented (like other
|
|
69
|
+
# scoped models) so the ModelController and Model class methods work.
|
|
70
|
+
def self.get(name:, scope:)
|
|
71
|
+
super("#{scope}__#{PRIMARY_KEY}", name: name)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def self.names(scope:)
|
|
75
|
+
super("#{scope}__#{PRIMARY_KEY}")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def self.all(scope:)
|
|
79
|
+
super("#{scope}__#{PRIMARY_KEY}")
|
|
80
|
+
end
|
|
81
|
+
# END NOTE
|
|
82
|
+
|
|
83
|
+
def initialize(
|
|
84
|
+
name:,
|
|
85
|
+
scope:,
|
|
86
|
+
public_key: nil,
|
|
87
|
+
ticket: nil,
|
|
88
|
+
app_public_key: nil,
|
|
89
|
+
enroll_code: nil,
|
|
90
|
+
enroll_code_generated_at: nil,
|
|
91
|
+
port: nil,
|
|
92
|
+
updated_at: nil,
|
|
93
|
+
plugin: nil
|
|
94
|
+
)
|
|
95
|
+
super("#{scope}__#{PRIMARY_KEY}", name: name, updated_at: updated_at, plugin: plugin, scope: scope)
|
|
96
|
+
@public_key = public_key
|
|
97
|
+
@ticket = ticket
|
|
98
|
+
@app_public_key = app_public_key
|
|
99
|
+
@enroll_code = enroll_code
|
|
100
|
+
@enroll_code_generated_at = enroll_code_generated_at
|
|
101
|
+
@port = port
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def as_json(*_a)
|
|
105
|
+
{
|
|
106
|
+
'name' => @name,
|
|
107
|
+
'scope' => @scope,
|
|
108
|
+
'updated_at' => @updated_at,
|
|
109
|
+
'plugin' => @plugin,
|
|
110
|
+
'public_key' => @public_key,
|
|
111
|
+
'ticket' => @ticket,
|
|
112
|
+
'app_public_key' => @app_public_key,
|
|
113
|
+
'enroll_code' => @enroll_code,
|
|
114
|
+
'enroll_code_generated_at' => @enroll_code_generated_at,
|
|
115
|
+
'port' => @port
|
|
116
|
+
}
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Generate a one-time manual-enrollment code, store it on this bridge, and
|
|
120
|
+
# return a token (base64 JSON of bridge name + hub ticket + code) that a
|
|
121
|
+
# remote openc3-app pastes to enroll. Requires the bridge to be up (ticket
|
|
122
|
+
# present). The code is redeemed once over the api/enroll ALPN.
|
|
123
|
+
def generate_enrollment_token
|
|
124
|
+
raise "Bridge '#{@name}' has no ticket yet; is its bridge_microservice running?" if @ticket.nil? || @ticket.empty?
|
|
125
|
+
|
|
126
|
+
@enroll_code = SecureRandom.hex(16)
|
|
127
|
+
@enroll_code_generated_at = Time.now.to_i
|
|
128
|
+
update()
|
|
129
|
+
payload = { 'v' => 1, 'bridge' => @name, 'ticket' => @ticket, 'code' => @enroll_code }
|
|
130
|
+
Base64.urlsafe_encode64(JSON.generate(payload), padding: false)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 OpenC3, Inc.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is distributed in the hope that it will be useful,
|
|
7
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
8
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
9
|
+
# See LICENSE.md for more details.
|
|
10
|
+
#
|
|
11
|
+
# This file may also be used under the terms of a commercial license
|
|
12
|
+
# if purchased from OpenC3, Inc.
|
|
13
|
+
|
|
14
|
+
require 'openc3/utilities/secrets'
|
|
15
|
+
|
|
16
|
+
# Mixin providing plugin.txt keyword handling shared by the models the operator
|
|
17
|
+
# turns into running containers (InterfaceModel / RouterModel and
|
|
18
|
+
# MicroserviceModel). Including classes must initialize @ports to an Array.
|
|
19
|
+
module OpenC3
|
|
20
|
+
module ConfigKeywordModel
|
|
21
|
+
# Parse a PORT keyword, appending [number, protocol] to @ports.
|
|
22
|
+
def parse_port(parser, keyword, parameters)
|
|
23
|
+
usage = "PORT <Number> <Protocol (Optional)"
|
|
24
|
+
parser.verify_num_parameters(1, 2, usage)
|
|
25
|
+
begin
|
|
26
|
+
@ports << [Integer(parameters[0])]
|
|
27
|
+
rescue # In case Integer fails
|
|
28
|
+
raise ConfigParser::Error.new(parser, "Port must be an integer: #{parameters[0]}", usage)
|
|
29
|
+
end
|
|
30
|
+
protocol = ConfigParser.handle_nil(parameters[1])
|
|
31
|
+
if protocol
|
|
32
|
+
# Per https://kubernetes.io/docs/concepts/services-networking/service/#protocol-support
|
|
33
|
+
if %w(TCP UDP SCTP).include?(protocol.upcase)
|
|
34
|
+
@ports[-1] << protocol.upcase
|
|
35
|
+
else
|
|
36
|
+
raise ConfigParser::Error.new(parser, "Unknown port protocol: #{parameters[1]}", usage)
|
|
37
|
+
end
|
|
38
|
+
else
|
|
39
|
+
@ports[-1] << 'TCP'
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Validate a SECRET / BRIDGE_SECRET definition. FILE type paths are restricted
|
|
44
|
+
# to Secrets.secret_file_dir to prevent reading or overwriting arbitrary files.
|
|
45
|
+
def validate_secret(parser, keyword, parameters)
|
|
46
|
+
type = parameters[0].to_s.upcase
|
|
47
|
+
unless ['ENV', 'FILE'].include?(type)
|
|
48
|
+
raise ConfigParser::Error.new(parser, "Unknown secret type '#{parameters[0]}' for #{keyword}. Must be ENV or FILE.")
|
|
49
|
+
end
|
|
50
|
+
# Normalize in place so the stored secret matches what the operator and
|
|
51
|
+
# Secrets.setup match on, both of which compare against 'ENV' / 'FILE' and
|
|
52
|
+
# use the path exactly as given.
|
|
53
|
+
parameters[0] = type
|
|
54
|
+
if type == 'FILE'
|
|
55
|
+
begin
|
|
56
|
+
parameters[2] = Secrets.validate_file_path(parameters[2])
|
|
57
|
+
rescue ArgumentError => error
|
|
58
|
+
raise ConfigParser::Error.new(parser, "#{keyword} #{error.message}")
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -22,6 +22,7 @@ require 'rubygems'
|
|
|
22
22
|
require 'rubygems/uninstaller'
|
|
23
23
|
require 'tempfile'
|
|
24
24
|
require 'openc3/utilities/process_manager'
|
|
25
|
+
require 'openc3/utilities/rubygems_url'
|
|
25
26
|
require 'openc3/api/api'
|
|
26
27
|
require 'pathname'
|
|
27
28
|
|
|
@@ -34,8 +35,8 @@ module OpenC3
|
|
|
34
35
|
extend Api
|
|
35
36
|
|
|
36
37
|
def self.names
|
|
37
|
-
if Dir.exist?("#{ENV
|
|
38
|
-
result = Pathname.new("#{ENV
|
|
38
|
+
if Dir.exist?("#{ENV.fetch('GEM_HOME', nil)}/gems")
|
|
39
|
+
result = Pathname.new("#{ENV.fetch('GEM_HOME', nil)}/gems").children.select { |c| c.directory? }.collect { |p| File.basename(p) + '.gem' }
|
|
39
40
|
else
|
|
40
41
|
result = []
|
|
41
42
|
end
|
|
@@ -43,9 +44,9 @@ module OpenC3
|
|
|
43
44
|
end
|
|
44
45
|
|
|
45
46
|
def self.get(name)
|
|
46
|
-
path = "#{ENV
|
|
47
|
+
path = "#{ENV.fetch('GEM_HOME', nil)}/cosmoscache/#{name}"
|
|
47
48
|
return path if File.exist?(path)
|
|
48
|
-
path = "#{ENV
|
|
49
|
+
path = "#{ENV.fetch('GEM_HOME', nil)}/cache/#{name}"
|
|
49
50
|
return path if File.exist?(path)
|
|
50
51
|
raise "Gem '#{name}' not found"
|
|
51
52
|
end
|
|
@@ -54,8 +55,8 @@ module OpenC3
|
|
|
54
55
|
if File.file?(gem_file_path)
|
|
55
56
|
gem_filename = File.basename(gem_file_path)
|
|
56
57
|
# Put into cosmoscache folder that we control
|
|
57
|
-
FileUtils.mkdir_p("#{ENV
|
|
58
|
-
FileUtils.cp(gem_file_path, "#{ENV
|
|
58
|
+
FileUtils.mkdir_p("#{ENV.fetch('GEM_HOME', nil)}/cosmoscache") unless Dir.exist?("#{ENV.fetch('GEM_HOME', nil)}/cosmoscache")
|
|
59
|
+
FileUtils.cp(gem_file_path, "#{ENV.fetch('GEM_HOME', nil)}/cosmoscache/#{File.basename(gem_file_path)}")
|
|
59
60
|
if gem_install
|
|
60
61
|
Logger.info "Installing gem: #{gem_filename}"
|
|
61
62
|
result = OpenC3::ProcessManager.instance.spawn(["ruby", "/openc3/bin/openc3cli", "geminstall", gem_filename, scope], "package_install", gem_filename, Time.now + 3600.0, scope: scope)
|
|
@@ -79,9 +80,11 @@ module OpenC3
|
|
|
79
80
|
rubygems_url = get_setting('rubygems_url', scope: scope)
|
|
80
81
|
rescue
|
|
81
82
|
# If Redis isn't running try the ENV, then simply rubygems.org
|
|
82
|
-
rubygems_url = ENV
|
|
83
|
-
rubygems_url ||= 'https://rubygems.org'
|
|
83
|
+
rubygems_url = ENV.fetch('RUBYGEMS_URL', RubygemsUrl::DEFAULT)
|
|
84
84
|
end
|
|
85
|
+
# The url comes from a user-writable setting or ENV so validate it before
|
|
86
|
+
# using it as a Gem source
|
|
87
|
+
rubygems_url = RubygemsUrl.validate(rubygems_url) if rubygems_url
|
|
85
88
|
Gem.sources = [rubygems_url] if rubygems_url
|
|
86
89
|
Gem.done_installing_hooks.clear
|
|
87
90
|
begin
|
|
@@ -92,7 +95,7 @@ module OpenC3
|
|
|
92
95
|
Gem.install(gem_file_path, "> 0.pre", build_args: ['--no-document, --without development,test'], prerelease: true, domain: :both)
|
|
93
96
|
end
|
|
94
97
|
rescue => e
|
|
95
|
-
message = "Gem file #{gem_file_path} error installing to #{ENV
|
|
98
|
+
message = "Gem file #{gem_file_path} error installing to #{ENV.fetch('GEM_HOME', nil)}\n#{e.formatted}"
|
|
96
99
|
Logger.error message
|
|
97
100
|
raise e
|
|
98
101
|
end
|