openc3 6.10.4 → 7.0.0.pre.rc2
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 +2 -1
- data/Guardfile +4 -9
- data/LICENSE.md +85 -0
- data/README.md +8 -8
- data/Rakefile +3 -9
- data/bin/cstol_converter +3 -8
- data/bin/openc3cli +64 -35
- data/data/config/command_modifiers.yaml +18 -1
- data/data/config/interface_modifiers.yaml +0 -2
- data/data/config/plugins.yaml +14 -18
- data/data/config/screen.yaml +1 -1
- data/data/config/target.yaml +26 -79
- data/data/config/telemetry_modifiers.yaml +15 -0
- data/data/config/widgets.yaml +32 -32
- data/ext/openc3/ext/array/array.c +4 -9
- data/ext/openc3/ext/buffered_file/buffered_file.c +4 -9
- data/ext/openc3/ext/burst_protocol/burst_protocol.c +3 -8
- data/ext/openc3/ext/config_parser/config_parser.c +2 -7
- data/ext/openc3/ext/crc/crc.c +3 -8
- data/ext/openc3/ext/openc3_io/openc3_io.c +4 -9
- data/ext/openc3/ext/packet/packet.c +7 -9
- data/ext/openc3/ext/platform/platform.c +3 -8
- data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +16 -12
- data/ext/openc3/ext/string/string.c +4 -9
- data/ext/openc3/ext/structure/structure.c +5 -9
- data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +4 -9
- data/ext/openc3/ext/telemetry/telemetry.c +8 -12
- data/lib/cosmos.rb +4 -9
- data/lib/cosmosc2.rb +4 -9
- data/lib/openc3/accessors/accessor.rb +10 -13
- data/lib/openc3/accessors/binary_accessor.rb +18 -17
- data/lib/openc3/accessors/cbor_accessor.rb +3 -8
- data/lib/openc3/accessors/form_accessor.rb +4 -9
- data/lib/openc3/accessors/html_accessor.rb +3 -8
- data/lib/openc3/accessors/http_accessor.rb +4 -9
- data/lib/openc3/accessors/json_accessor.rb +4 -9
- data/lib/openc3/accessors/template_accessor.rb +4 -9
- data/lib/openc3/accessors/xml_accessor.rb +4 -9
- data/lib/openc3/accessors.rb +3 -8
- data/lib/openc3/api/README.md +1 -1
- data/lib/openc3/api/api.rb +3 -8
- data/lib/openc3/api/authorized_api.rb +4 -9
- data/lib/openc3/api/cmd_api.rb +3 -8
- data/lib/openc3/api/config_api.rb +3 -8
- data/lib/openc3/api/interface_api.rb +4 -9
- data/lib/openc3/api/limits_api.rb +3 -8
- data/lib/openc3/api/metrics_api.rb +2 -19
- data/lib/openc3/api/offline_access_api.rb +2 -7
- data/lib/openc3/api/router_api.rb +5 -10
- data/lib/openc3/api/settings_api.rb +3 -8
- data/lib/openc3/api/stash_api.rb +2 -7
- data/lib/openc3/api/target_api.rb +3 -8
- data/lib/openc3/api/tlm_api.rb +15 -38
- data/lib/openc3/bridge/bridge.rb +3 -8
- data/lib/openc3/bridge/bridge_config.rb +5 -10
- data/lib/openc3/bridge/bridge_interface_thread.rb +4 -9
- data/lib/openc3/bridge/bridge_router_thread.rb +4 -9
- data/lib/openc3/ccsds/ccsds_packet.rb +4 -9
- data/lib/openc3/ccsds/ccsds_parser.rb +3 -8
- data/lib/openc3/config/config_parser.rb +3 -8
- data/lib/openc3/config/meta_config_parser.rb +3 -8
- data/lib/openc3/conversions/bit_reverse_conversion.rb +3 -8
- data/lib/openc3/conversions/conversion.rb +3 -8
- data/lib/openc3/conversions/generic_conversion.rb +3 -8
- data/lib/openc3/conversions/ip_read_conversion.rb +3 -8
- data/lib/openc3/conversions/ip_write_conversion.rb +3 -8
- data/lib/openc3/conversions/object_read_conversion.rb +3 -8
- data/lib/openc3/conversions/object_write_conversion.rb +3 -8
- data/lib/openc3/conversions/packet_time_formatted_conversion.rb +4 -9
- data/lib/openc3/conversions/packet_time_seconds_conversion.rb +4 -9
- data/lib/openc3/conversions/polynomial_conversion.rb +6 -8
- data/lib/openc3/conversions/processor_conversion.rb +3 -8
- data/lib/openc3/conversions/received_count_conversion.rb +4 -9
- data/lib/openc3/conversions/received_time_formatted_conversion.rb +4 -9
- data/lib/openc3/conversions/received_time_seconds_conversion.rb +4 -9
- data/lib/openc3/conversions/segmented_polynomial_conversion.rb +6 -8
- data/lib/openc3/conversions/unix_time_conversion.rb +3 -8
- data/lib/openc3/conversions/unix_time_formatted_conversion.rb +3 -8
- data/lib/openc3/conversions/unix_time_seconds_conversion.rb +3 -8
- data/lib/openc3/conversions.rb +3 -8
- data/lib/openc3/core_ext/array.rb +3 -8
- data/lib/openc3/core_ext/binding.rb +4 -9
- data/lib/openc3/core_ext/class.rb +4 -9
- data/lib/openc3/core_ext/exception.rb +3 -8
- data/lib/openc3/core_ext/file.rb +4 -9
- data/lib/openc3/core_ext/io.rb +4 -9
- data/lib/openc3/core_ext/kernel.rb +3 -8
- data/lib/openc3/core_ext/math.rb +4 -9
- data/lib/openc3/core_ext/matrix.rb +4 -9
- data/lib/openc3/core_ext/objectspace.rb +4 -9
- data/lib/openc3/core_ext/openc3_io.rb +4 -9
- data/lib/openc3/core_ext/range.rb +4 -9
- data/lib/openc3/core_ext/socket.rb +4 -9
- data/lib/openc3/core_ext/string.rb +3 -8
- data/lib/openc3/core_ext/stringio.rb +4 -9
- data/lib/openc3/core_ext/tempfile.rb +4 -9
- data/lib/openc3/core_ext/time.rb +3 -8
- data/lib/openc3/core_ext.rb +3 -8
- data/lib/openc3/interfaces/file_interface.rb +3 -8
- data/lib/openc3/interfaces/http_client_interface.rb +3 -8
- data/lib/openc3/interfaces/http_server_interface.rb +3 -8
- data/lib/openc3/interfaces/interface.rb +3 -8
- data/lib/openc3/interfaces/mqtt_interface.rb +3 -8
- data/lib/openc3/interfaces/mqtt_stream_interface.rb +3 -8
- data/lib/openc3/interfaces/protocols/burst_protocol.rb +3 -8
- data/lib/openc3/interfaces/protocols/cmd_response_protocol.rb +3 -8
- data/lib/openc3/interfaces/protocols/cobs_protocol.rb +3 -8
- data/lib/openc3/interfaces/protocols/crc_protocol.rb +3 -8
- data/lib/openc3/interfaces/protocols/fixed_protocol.rb +3 -8
- data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +3 -8
- data/lib/openc3/interfaces/protocols/length_protocol.rb +3 -8
- data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +3 -8
- data/lib/openc3/interfaces/protocols/protocol.rb +3 -8
- data/lib/openc3/interfaces/protocols/slip_protocol.rb +3 -8
- data/lib/openc3/interfaces/protocols/template_protocol.rb +3 -8
- data/lib/openc3/interfaces/protocols/terminated_protocol.rb +3 -8
- data/lib/openc3/interfaces/serial_interface.rb +3 -8
- data/lib/openc3/interfaces/simulated_target_interface.rb +3 -8
- data/lib/openc3/interfaces/stream_interface.rb +3 -8
- data/lib/openc3/interfaces/tcpip_client_interface.rb +3 -8
- data/lib/openc3/interfaces/tcpip_server_interface.rb +3 -8
- data/lib/openc3/interfaces/udp_interface.rb +3 -8
- data/lib/openc3/interfaces.rb +3 -8
- data/lib/openc3/io/buffered_file.rb +4 -9
- data/lib/openc3/io/io_multiplexer.rb +4 -9
- data/lib/openc3/io/json_api.rb +3 -8
- data/lib/openc3/io/json_api_object.rb +4 -9
- data/lib/openc3/io/json_drb.rb +3 -8
- data/lib/openc3/io/json_drb_object.rb +4 -9
- data/lib/openc3/io/json_drb_rack.rb +4 -9
- data/lib/openc3/io/json_rpc.rb +3 -8
- data/lib/openc3/io/posix_serial_driver.rb +3 -8
- data/lib/openc3/io/serial_driver.rb +3 -8
- data/lib/openc3/io/stderr.rb +4 -9
- data/lib/openc3/io/stdout.rb +4 -9
- data/lib/openc3/io/udp_sockets.rb +3 -8
- data/lib/openc3/io/win32_serial_driver.rb +4 -9
- data/lib/openc3/logs/buffered_packet_log_reader.rb +3 -8
- data/lib/openc3/logs/buffered_packet_log_writer.rb +3 -8
- data/lib/openc3/logs/log_writer.rb +3 -8
- data/lib/openc3/logs/packet_log_constants.rb +3 -8
- data/lib/openc3/logs/packet_log_reader.rb +3 -8
- data/lib/openc3/logs/packet_log_writer.rb +3 -8
- data/lib/openc3/logs/stream_log.rb +3 -8
- data/lib/openc3/logs/stream_log_pair.rb +3 -8
- data/lib/openc3/logs/text_log_writer.rb +3 -8
- data/lib/openc3/logs.rb +3 -8
- data/lib/openc3/microservices/cleanup_microservice.rb +4 -14
- data/lib/openc3/microservices/decom_microservice.rb +3 -8
- data/lib/openc3/microservices/interface_decom_common.rb +3 -8
- data/lib/openc3/microservices/interface_microservice.rb +5 -9
- data/lib/openc3/microservices/log_microservice.rb +3 -8
- data/lib/openc3/microservices/microservice.rb +24 -12
- data/lib/openc3/microservices/multi_microservice.rb +2 -7
- data/lib/openc3/microservices/periodic_microservice.rb +3 -8
- data/lib/openc3/microservices/plugin_microservice.rb +3 -8
- data/lib/openc3/microservices/queue_microservice.rb +3 -8
- data/lib/openc3/microservices/router_microservice.rb +3 -8
- data/lib/openc3/microservices/scope_cleanup_microservice.rb +3 -8
- data/lib/openc3/microservices/text_log_microservice.rb +3 -8
- data/lib/openc3/migrations/20251213120000_reinstall_plugins.rb +45 -0
- data/lib/openc3/migrations/20260204000000_remove_decom_reducer.rb +60 -0
- data/lib/openc3/models/activity_model.rb +4 -8
- data/lib/openc3/models/auth_model.rb +57 -38
- data/lib/openc3/models/cvt_model.rb +203 -62
- data/lib/openc3/models/environment_model.rb +4 -9
- data/lib/openc3/models/gem_model.rb +3 -8
- data/lib/openc3/models/info_model.rb +4 -9
- data/lib/openc3/models/interface_model.rb +6 -10
- data/lib/openc3/models/interface_status_model.rb +4 -9
- data/lib/openc3/models/metadata_model.rb +3 -8
- data/lib/openc3/models/metric_model.rb +3 -8
- data/lib/openc3/models/microservice_model.rb +24 -10
- data/lib/openc3/models/microservice_status_model.rb +3 -8
- data/lib/openc3/models/migration_model.rb +3 -8
- data/lib/openc3/models/model.rb +3 -8
- data/lib/openc3/models/news_model.rb +3 -8
- data/lib/openc3/models/note_model.rb +3 -8
- data/lib/openc3/models/offline_access_model.rb +3 -8
- data/lib/openc3/models/ping_model.rb +4 -9
- data/lib/openc3/models/plugin_model.rb +14 -9
- data/lib/openc3/models/plugin_store_model.rb +21 -17
- data/lib/openc3/models/process_status_model.rb +4 -9
- data/lib/openc3/models/python_package_model.rb +3 -8
- data/lib/openc3/models/queue_model.rb +3 -8
- data/lib/openc3/models/reaction_model.rb +9 -10
- data/lib/openc3/models/router_model.rb +4 -9
- data/lib/openc3/models/router_status_model.rb +4 -9
- data/lib/openc3/models/scope_model.rb +4 -9
- data/lib/openc3/models/script_engine_model.rb +3 -8
- data/lib/openc3/models/script_status_model.rb +3 -8
- data/lib/openc3/models/secret_model.rb +3 -8
- data/lib/openc3/models/setting_model.rb +3 -8
- data/lib/openc3/models/sorted_model.rb +3 -8
- data/lib/openc3/models/stash_model.rb +3 -8
- data/lib/openc3/models/target_model.rb +99 -229
- data/lib/openc3/models/timeline_model.rb +3 -8
- data/lib/openc3/models/tool_config_model.rb +3 -8
- data/lib/openc3/models/tool_model.rb +10 -10
- data/lib/openc3/models/trigger_group_model.rb +3 -8
- data/lib/openc3/models/trigger_model.rb +3 -8
- data/lib/openc3/models/widget_model.rb +3 -8
- data/lib/openc3/operators/microservice_operator.rb +7 -8
- data/lib/openc3/operators/operator.rb +3 -8
- data/lib/openc3/packets/command_validator.rb +3 -8
- data/lib/openc3/packets/commands.rb +32 -14
- data/lib/openc3/packets/json_packet.rb +7 -19
- data/lib/openc3/packets/limits.rb +3 -8
- data/lib/openc3/packets/limits_response.rb +3 -8
- data/lib/openc3/packets/packet.rb +38 -32
- data/lib/openc3/packets/packet_config.rb +23 -13
- data/lib/openc3/packets/packet_item.rb +3 -8
- data/lib/openc3/packets/packet_item_limits.rb +3 -8
- data/lib/openc3/packets/parsers/format_string_parser.rb +3 -8
- data/lib/openc3/packets/parsers/limits_parser.rb +3 -8
- data/lib/openc3/packets/parsers/limits_response_parser.rb +3 -8
- data/lib/openc3/packets/parsers/packet_item_parser.rb +7 -8
- data/lib/openc3/packets/parsers/packet_parser.rb +3 -8
- data/lib/openc3/packets/parsers/processor_parser.rb +3 -8
- data/lib/openc3/packets/parsers/state_parser.rb +3 -8
- data/lib/openc3/packets/parsers/xtce_converter.rb +12 -9
- data/lib/openc3/packets/parsers/xtce_parser.rb +3 -8
- data/lib/openc3/packets/structure.rb +14 -11
- data/lib/openc3/packets/structure_item.rb +4 -9
- data/lib/openc3/packets/telemetry.rb +7 -11
- data/lib/openc3/processors/processor.rb +5 -10
- data/lib/openc3/processors/statistics_processor.rb +4 -9
- data/lib/openc3/processors/watermark_processor.rb +4 -9
- data/lib/openc3/processors.rb +4 -9
- data/lib/openc3/script/api_shared.rb +8 -37
- data/lib/openc3/script/autonomic.rb +3 -8
- data/lib/openc3/script/calendar.rb +3 -8
- data/lib/openc3/script/commands.rb +3 -8
- data/lib/openc3/script/critical_cmd.rb +3 -8
- data/lib/openc3/script/exceptions.rb +4 -9
- data/lib/openc3/script/extract.rb +3 -8
- data/lib/openc3/script/limits.rb +3 -8
- data/lib/openc3/script/metadata.rb +3 -8
- data/lib/openc3/script/packages.rb +3 -8
- data/lib/openc3/script/plugins.rb +3 -8
- data/lib/openc3/script/queue.rb +3 -8
- data/lib/openc3/script/screen.rb +7 -8
- data/lib/openc3/script/script.rb +3 -8
- data/lib/openc3/script/script_runner.rb +3 -8
- data/lib/openc3/script/storage.rb +6 -10
- data/lib/openc3/script/suite.rb +3 -8
- data/lib/openc3/script/suite_results.rb +3 -8
- data/lib/openc3/script/suite_runner.rb +3 -8
- data/lib/openc3/script/tables.rb +3 -8
- data/lib/openc3/script/telemetry.rb +3 -8
- data/lib/openc3/script/web_socket_api.rb +8 -13
- data/lib/openc3/script.rb +4 -9
- data/lib/openc3/script_engines/script_engine.rb +3 -8
- data/lib/openc3/streams/mqtt_stream.rb +3 -8
- data/lib/openc3/streams/serial_stream.rb +3 -8
- data/lib/openc3/streams/stream.rb +3 -8
- data/lib/openc3/streams/tcpip_client_stream.rb +3 -8
- data/lib/openc3/streams/tcpip_socket_stream.rb +3 -8
- data/lib/openc3/streams/web_socket_client_stream.rb +3 -8
- data/lib/openc3/system/system.rb +3 -8
- data/lib/openc3/system/target.rb +3 -8
- data/lib/openc3/system.rb +3 -8
- data/lib/openc3/tools/cmd_tlm_server/api.rb +4 -9
- data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +3 -8
- data/lib/openc3/tools/table_manager/table.rb +3 -8
- data/lib/openc3/tools/table_manager/table_config.rb +3 -8
- data/lib/openc3/tools/table_manager/table_item.rb +4 -9
- data/lib/openc3/tools/table_manager/table_item_parser.rb +3 -8
- data/lib/openc3/tools/table_manager/table_manager_core.rb +3 -8
- data/lib/openc3/tools/table_manager/table_parser.rb +3 -8
- data/lib/openc3/tools/test_runner/test.rb +4 -9
- data/lib/openc3/top_level.rb +3 -8
- data/lib/openc3/topics/autonomic_topic.rb +4 -9
- data/lib/openc3/topics/calendar_topic.rb +4 -9
- data/lib/openc3/topics/command_decom_topic.rb +14 -17
- data/lib/openc3/topics/command_topic.rb +14 -10
- data/lib/openc3/topics/config_topic.rb +3 -8
- data/lib/openc3/topics/decom_interface_topic.rb +3 -8
- data/lib/openc3/topics/interface_topic.rb +3 -8
- data/lib/openc3/topics/limits_event_topic.rb +3 -8
- data/lib/openc3/topics/notebook_topic.rb +32 -0
- data/lib/openc3/topics/queue_topic.rb +3 -8
- data/lib/openc3/topics/router_topic.rb +3 -8
- data/lib/openc3/topics/system_events_topic.rb +3 -8
- data/lib/openc3/topics/telemetry_decom_topic.rb +12 -12
- data/lib/openc3/topics/telemetry_topic.rb +3 -8
- data/lib/openc3/topics/timeline_topic.rb +4 -9
- data/lib/openc3/topics/topic.rb +3 -8
- data/lib/openc3/utilities/authentication.rb +29 -10
- data/lib/openc3/utilities/authorization.rb +4 -9
- data/lib/openc3/utilities/aws_bucket.rb +126 -16
- data/lib/openc3/utilities/bucket.rb +9 -9
- data/lib/openc3/utilities/bucket_file_cache.rb +3 -13
- data/lib/openc3/utilities/bucket_require.rb +3 -8
- data/lib/openc3/utilities/bucket_utilities.rb +3 -10
- data/lib/openc3/utilities/cli_generator.rb +11 -16
- data/lib/openc3/utilities/cmd_log.rb +3 -8
- data/lib/openc3/utilities/crc.rb +3 -8
- data/lib/openc3/utilities/csv.rb +4 -9
- data/lib/openc3/utilities/local_bucket.rb +5 -10
- data/lib/openc3/utilities/local_mode.rb +14 -18
- data/lib/openc3/utilities/logger.rb +3 -8
- data/lib/openc3/utilities/message_log.rb +3 -8
- data/lib/openc3/utilities/metric.rb +3 -8
- data/lib/openc3/utilities/migration.rb +3 -8
- data/lib/openc3/utilities/open_telemetry.rb +3 -8
- data/lib/openc3/utilities/process_manager.rb +3 -8
- data/lib/openc3/utilities/python_proxy.rb +3 -8
- data/lib/openc3/utilities/quaternion.rb +3 -8
- data/lib/openc3/utilities/questdb_client.rb +210 -0
- data/lib/openc3/utilities/redis_secrets.rb +3 -8
- data/lib/openc3/utilities/ruby_lex_utils.rb +3 -8
- data/lib/openc3/utilities/running_script.rb +13 -11
- data/lib/openc3/utilities/s3_autoload.rb +9 -2
- data/lib/openc3/utilities/secrets.rb +8 -9
- data/lib/openc3/utilities/simulated_target.rb +4 -9
- data/lib/openc3/utilities/sleeper.rb +3 -8
- data/lib/openc3/utilities/store.rb +4 -9
- data/lib/openc3/utilities/store_autoload.rb +7 -14
- data/lib/openc3/utilities/store_queued.rb +6 -9
- data/lib/openc3/utilities/target_file.rb +3 -8
- data/lib/openc3/utilities/thread_manager.rb +3 -8
- data/lib/openc3/utilities/throttle.rb +3 -8
- data/lib/openc3/utilities/zip.rb +4 -9
- data/lib/openc3/utilities.rb +4 -9
- data/lib/openc3/version.rb +8 -8
- data/lib/openc3/win32/excel.rb +4 -9
- data/lib/openc3/win32/win32.rb +4 -9
- data/lib/openc3/win32/win32_main.rb +3 -8
- data/lib/openc3.rb +3 -12
- data/tasks/gemfile_stats.rake +4 -9
- data/tasks/spec.rake +4 -9
- data/templates/plugin/README.md +2 -2
- data/templates/plugin/plugin.gemspec +1 -1
- data/templates/tool_angular/package.json +1 -1
- data/templates/tool_vue/package.json +3 -3
- data/templates/tool_vue/vite.config.js +2 -1
- data/templates/widget/package.json +3 -3
- data/templates/widget/vite.config.js +1 -1
- metadata +49 -26
- data/LICENSE.txt +0 -729
- data/bin/rubysloc +0 -142
- data/ext/openc3/ext/reducer_microservice/extconf.rb +0 -13
- data/ext/openc3/ext/reducer_microservice/reducer_microservice.c +0 -165
- data/lib/openc3/microservices/reducer_microservice.rb +0 -640
- data/lib/openc3/models/reducer_model.rb +0 -72
- data/lib/openc3/topics/telemetry_reduced_topics.rb +0 -80
- /data/templates/plugin/{LICENSE.txt → LICENSE.md} +0 -0
- /data/templates/widget/{LICENSE.txt → LICENSE.md} +0 -0
|
@@ -1,640 +0,0 @@
|
|
|
1
|
-
# encoding: ascii-8bit
|
|
2
|
-
|
|
3
|
-
# Copyright 2022 Ball Aerospace & Technologies Corp.
|
|
4
|
-
# All Rights Reserved.
|
|
5
|
-
#
|
|
6
|
-
# This program is free software; you can modify and/or redistribute it
|
|
7
|
-
# under the terms of the GNU Affero General Public License
|
|
8
|
-
# as published by the Free Software Foundation; version 3 with
|
|
9
|
-
# attribution addendums as found in the LICENSE.txt
|
|
10
|
-
#
|
|
11
|
-
# This program is distributed in the hope that it will be useful,
|
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
-
# GNU Affero General Public License for more details.
|
|
15
|
-
|
|
16
|
-
# Modified by OpenC3, Inc.
|
|
17
|
-
# All changes Copyright 2022, OpenC3, Inc.
|
|
18
|
-
# All Rights Reserved
|
|
19
|
-
#
|
|
20
|
-
# This file may also be used under the terms of a commercial license
|
|
21
|
-
# if purchased from OpenC3, Inc.
|
|
22
|
-
|
|
23
|
-
require 'openc3/microservices/microservice'
|
|
24
|
-
require 'openc3/topics/topic'
|
|
25
|
-
require 'openc3/topics/telemetry_reduced_topics'
|
|
26
|
-
require 'openc3/packets/json_packet'
|
|
27
|
-
require 'openc3/utilities/bucket_file_cache'
|
|
28
|
-
require 'openc3/utilities/throttle'
|
|
29
|
-
require 'openc3/models/reducer_model'
|
|
30
|
-
require 'openc3/logs/buffered_packet_log_writer'
|
|
31
|
-
require 'openc3/ext/reducer_microservice' if RUBY_ENGINE == 'ruby' and !ENV['OPENC3_NO_EXT']
|
|
32
|
-
require 'rufus-scheduler'
|
|
33
|
-
require 'thread'
|
|
34
|
-
|
|
35
|
-
module OpenC3
|
|
36
|
-
class ReducerState
|
|
37
|
-
attr_accessor :reduced
|
|
38
|
-
attr_accessor :raw_keys
|
|
39
|
-
attr_accessor :converted_keys
|
|
40
|
-
attr_accessor :entry_time
|
|
41
|
-
attr_accessor :entry_samples
|
|
42
|
-
attr_accessor :current_time
|
|
43
|
-
attr_accessor :previous_time
|
|
44
|
-
attr_accessor :raw_values
|
|
45
|
-
attr_accessor :raw_max_values
|
|
46
|
-
attr_accessor :raw_min_values
|
|
47
|
-
attr_accessor :raw_avg_values
|
|
48
|
-
attr_accessor :raw_stddev_values
|
|
49
|
-
attr_accessor :converted_values
|
|
50
|
-
attr_accessor :converted_max_values
|
|
51
|
-
attr_accessor :converted_min_values
|
|
52
|
-
attr_accessor :converted_avg_values
|
|
53
|
-
attr_accessor :converted_stddev_values
|
|
54
|
-
attr_accessor :first
|
|
55
|
-
|
|
56
|
-
def initialize
|
|
57
|
-
@reduced = {}
|
|
58
|
-
@raw_keys = nil
|
|
59
|
-
@converted_keys = nil
|
|
60
|
-
@entry_time = nil
|
|
61
|
-
@entry_samples = nil
|
|
62
|
-
@current_time = nil
|
|
63
|
-
@previous_time = nil
|
|
64
|
-
@raw_values = nil
|
|
65
|
-
@raw_max_values = nil
|
|
66
|
-
@raw_min_values = nil
|
|
67
|
-
@raw_avg_values = nil
|
|
68
|
-
@raw_stddev_values = nil
|
|
69
|
-
@converted_values = nil
|
|
70
|
-
@converted_max_values = nil
|
|
71
|
-
@converted_min_values = nil
|
|
72
|
-
@converted_avg_values = nil
|
|
73
|
-
@converted_stddev_values = nil
|
|
74
|
-
@first = true
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
class ReducerMicroservice < Microservice
|
|
79
|
-
MINUTE_METRIC = 'reducer_minute_processing'
|
|
80
|
-
HOUR_METRIC = 'reducer_hour_processing'
|
|
81
|
-
DAY_METRIC = 'reducer_day_processing'
|
|
82
|
-
|
|
83
|
-
# How long to wait for any currently running jobs to complete before killing them
|
|
84
|
-
SHUTDOWN_DELAY_SECS = 5
|
|
85
|
-
MINUTE_ENTRY_NSECS = 60 * 1_000_000_000
|
|
86
|
-
MINUTE_FILE_NSECS = 3600 * 1_000_000_000
|
|
87
|
-
HOUR_ENTRY_NSECS = 3600 * 1_000_000_000
|
|
88
|
-
HOUR_FILE_NSECS = 3600 * 24 * 1_000_000_000
|
|
89
|
-
DAY_ENTRY_NSECS = 3600 * 24 * 1_000_000_000
|
|
90
|
-
DAY_FILE_NSECS = 3600 * 24 * 5 * 1_000_000_000
|
|
91
|
-
|
|
92
|
-
# @param name [String] Microservice name formatted as <SCOPE>__REDUCER__<TARGET>
|
|
93
|
-
# where <SCOPE> and <TARGET> are variables representing the scope name and target name
|
|
94
|
-
def initialize(name)
|
|
95
|
-
super(name, is_plugin: false)
|
|
96
|
-
|
|
97
|
-
if @config['options']
|
|
98
|
-
@config['options'].each do |option|
|
|
99
|
-
case option[0].upcase
|
|
100
|
-
when 'BUFFER_DEPTH' # Buffer depth to write in time order
|
|
101
|
-
@buffer_depth = option[1].to_i
|
|
102
|
-
when 'MAX_CPU_UTILIZATION'
|
|
103
|
-
@max_cpu_utilization = Float(option[1])
|
|
104
|
-
else
|
|
105
|
-
@logger.error("Unknown option passed to microservice #{@name}: #{option}")
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
@buffer_depth = 60 unless @buffer_depth
|
|
111
|
-
@max_cpu_utilization = 30.0 unless @max_cpu_utilization
|
|
112
|
-
@target_name = name.split('__')[-1]
|
|
113
|
-
@packet_logs = {}
|
|
114
|
-
@mutex = Mutex.new
|
|
115
|
-
@previous_metrics = {}
|
|
116
|
-
|
|
117
|
-
@error_count = 0
|
|
118
|
-
|
|
119
|
-
# Initialize metrics
|
|
120
|
-
@metric.set(name: 'reducer_minute_total', value: 0, type: 'counter')
|
|
121
|
-
@metric.set(name: 'reducer_hour_total', value: 0, type: 'counter')
|
|
122
|
-
@metric.set(name: 'reducer_day_total', value: 0, type: 'counter')
|
|
123
|
-
@metric.set(name: 'reducer_minute_error_total', value: 0, type: 'counter')
|
|
124
|
-
@metric.set(name: 'reducer_hour_error_total', value: 0, type: 'counter')
|
|
125
|
-
@metric.set(name: 'reducer_day_error_total', value: 0, type: 'counter')
|
|
126
|
-
@metric.set(name: 'reducer_minute_processing_sample_seconds', value: 0.0, type: 'gauge', unit: 'seconds')
|
|
127
|
-
@metric.set(name: 'reducer_hour_processing_sample_seconds', value: 0.0, type: 'gauge', unit: 'seconds')
|
|
128
|
-
@metric.set(name: 'reducer_day_processing_sample_seconds', value: 0.0, type: 'gauge', unit: 'seconds')
|
|
129
|
-
@metric.set(name: 'reducer_minute_processing_max_seconds', value: 0.0, type: 'gauge', unit: 'seconds')
|
|
130
|
-
@metric.set(name: 'reducer_hour_processing_max_seconds', value: 0.0, type: 'gauge', unit: 'seconds')
|
|
131
|
-
@metric.set(name: 'reducer_day_processing_max_seconds', value: 0.0, type: 'gauge', unit: 'seconds')
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def run
|
|
135
|
-
# Note it takes several seconds to create the scheduler
|
|
136
|
-
@scheduler = Rufus::Scheduler.new
|
|
137
|
-
# Run every minute
|
|
138
|
-
@scheduler.cron '* * * * *', first: :now do
|
|
139
|
-
reduce_minute
|
|
140
|
-
end
|
|
141
|
-
# Run every 15 minutes
|
|
142
|
-
@scheduler.cron '*/15 * * * *', first: :now do
|
|
143
|
-
reduce_hour
|
|
144
|
-
end
|
|
145
|
-
# Run hourly at minute 5 to allow the hour reducer to finish
|
|
146
|
-
@scheduler.cron '5 * * * *', first: :now do
|
|
147
|
-
reduce_day
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
# Let the current thread join the scheduler thread and
|
|
151
|
-
# block until shutdown is called
|
|
152
|
-
@scheduler.join
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def shutdown
|
|
156
|
-
@logger.info("Shutting down reducer microservice: #{@name}")
|
|
157
|
-
@scheduler.shutdown(wait: SHUTDOWN_DELAY_SECS) if @scheduler
|
|
158
|
-
|
|
159
|
-
# Make sure all the existing logs are properly closed down
|
|
160
|
-
threads = []
|
|
161
|
-
@packet_logs.each do |name, log|
|
|
162
|
-
threads.concat(log.shutdown)
|
|
163
|
-
end
|
|
164
|
-
# Wait for all the logging threads to move files to buckets
|
|
165
|
-
threads.flatten.compact.each do |thread|
|
|
166
|
-
thread.join
|
|
167
|
-
end
|
|
168
|
-
super()
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
def metric(name)
|
|
172
|
-
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
173
|
-
processed = yield
|
|
174
|
-
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
|
|
175
|
-
if processed
|
|
176
|
-
sample_name = name + '_sample_seconds'
|
|
177
|
-
@metric.set(name: sample_name, value: elapsed, type: 'gauge', unit: 'seconds')
|
|
178
|
-
max_name = name + '_max_seconds'
|
|
179
|
-
previous_max = @previous_metrics[max_name] || 0.0
|
|
180
|
-
if elapsed > previous_max
|
|
181
|
-
@metric.set(name: max_name, value: elapsed, type: 'gauge', unit: 'seconds')
|
|
182
|
-
@previous_metrics[max_name] = elapsed
|
|
183
|
-
end
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
def reduce_minute
|
|
188
|
-
@mutex.synchronize do
|
|
189
|
-
metric(MINUTE_METRIC) do
|
|
190
|
-
processed = false
|
|
191
|
-
ReducerModel
|
|
192
|
-
.all_files(type: :DECOM, target: @target_name, scope: @scope)
|
|
193
|
-
.each do |file|
|
|
194
|
-
process_file(file, 'minute', MINUTE_ENTRY_NSECS, MINUTE_FILE_NSECS)
|
|
195
|
-
ReducerModel.rm_file(file)
|
|
196
|
-
processed = true
|
|
197
|
-
end
|
|
198
|
-
processed # return to yield
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
def reduce_hour
|
|
204
|
-
@mutex.synchronize do
|
|
205
|
-
metric(HOUR_METRIC) do
|
|
206
|
-
processed = false
|
|
207
|
-
ReducerModel
|
|
208
|
-
.all_files(type: :MINUTE, target: @target_name, scope: @scope)
|
|
209
|
-
.each do |file|
|
|
210
|
-
process_file(file, 'hour', HOUR_ENTRY_NSECS, HOUR_FILE_NSECS)
|
|
211
|
-
ReducerModel.rm_file(file)
|
|
212
|
-
processed = true
|
|
213
|
-
end
|
|
214
|
-
processed # return to yield
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
def reduce_day
|
|
220
|
-
@mutex.synchronize do
|
|
221
|
-
metric(DAY_METRIC) do
|
|
222
|
-
processed = false
|
|
223
|
-
ReducerModel
|
|
224
|
-
.all_files(type: :HOUR, target: @target_name, scope: @scope)
|
|
225
|
-
.each do |file|
|
|
226
|
-
process_file(file, 'day', DAY_ENTRY_NSECS, DAY_FILE_NSECS)
|
|
227
|
-
ReducerModel.rm_file(file)
|
|
228
|
-
processed = true
|
|
229
|
-
end
|
|
230
|
-
processed # return to yield
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
def process_file(filename, type, entry_nanoseconds, file_nanoseconds)
|
|
236
|
-
throttle = OpenC3::Throttle.new(@max_cpu_utilization)
|
|
237
|
-
file = BucketFile.new(filename)
|
|
238
|
-
file.retrieve
|
|
239
|
-
unless File.exist?(file.local_path)
|
|
240
|
-
@logger.warn("Reducer Warning: #{file.local_path}: Does not exist")
|
|
241
|
-
return
|
|
242
|
-
end
|
|
243
|
-
unless File.size(file.local_path) > 0
|
|
244
|
-
@logger.warn("Reducer Warning: #{file.local_path}: Is zero bytes")
|
|
245
|
-
return
|
|
246
|
-
end
|
|
247
|
-
throttle.throttle_sleep
|
|
248
|
-
|
|
249
|
-
# Determine if we already have a PacketLogWriter created
|
|
250
|
-
_, _, scope, target_name, _, rt_or_stored, _ = File.basename(filename).split('__')
|
|
251
|
-
stored = (rt_or_stored == "stored")
|
|
252
|
-
|
|
253
|
-
if @target_name != target_name
|
|
254
|
-
raise "Target name in file #{filename} does not match microservice target name #{@target_name}"
|
|
255
|
-
end
|
|
256
|
-
plw = @packet_logs["#{scope}__#{target_name}__#{rt_or_stored}__#{type}"]
|
|
257
|
-
unless plw
|
|
258
|
-
# Create a new PacketLogWriter for this reduced data
|
|
259
|
-
# e.g. DEFAULT/reduced_minute_logs/tlm/INST/20220101/
|
|
260
|
-
# 20220101204857274290500__20220101205857276524900__DEFAULT__INST__ALL__rt__reduced_minute.bin
|
|
261
|
-
remote_log_directory = "#{scope}/reduced_#{type}_logs/tlm/#{target_name}"
|
|
262
|
-
label = "#{scope}__#{target_name}__ALL__#{rt_or_stored}__reduced_#{type}"
|
|
263
|
-
plw = BufferedPacketLogWriter.new(remote_log_directory, label, true, nil, 1_000_000_000, nil, nil, true, @buffer_depth)
|
|
264
|
-
@packet_logs["#{scope}__#{target_name}__#{rt_or_stored}__#{type}"] = plw
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
# The lifetime of all these variables is a single file - single target / multiple packets
|
|
268
|
-
reducer_state = {}
|
|
269
|
-
plr = OpenC3::PacketLogReader.new
|
|
270
|
-
throttle.throttle_sleep
|
|
271
|
-
plr.each(file.local_path) do |packet|
|
|
272
|
-
# Check to see if we should start a new log file before processing this packet
|
|
273
|
-
current_time = packet.packet_time.to_nsec_from_epoch
|
|
274
|
-
check_new_file(reducer_state, plw, type, target_name, stored, current_time, file_nanoseconds)
|
|
275
|
-
state = setup_state(reducer_state, packet, current_time)
|
|
276
|
-
|
|
277
|
-
# Determine if we've rolled over a entry boundary
|
|
278
|
-
# We have to use current % entry_nanoseconds < previous % entry_nanoseconds because
|
|
279
|
-
# we don't know the data rates. We also have to check for current - previous >= entry_nanoseconds
|
|
280
|
-
# in case the data rate is so slow we don't have multiple samples per entry
|
|
281
|
-
if state.previous_time &&
|
|
282
|
-
(
|
|
283
|
-
(state.current_time % entry_nanoseconds < state.previous_time % entry_nanoseconds) || # Try to create at perfect intervals
|
|
284
|
-
(state.current_time - state.previous_time >= entry_nanoseconds) # Handle big gaps
|
|
285
|
-
)
|
|
286
|
-
write_entry(state, plw, type, target_name, packet.packet_name, stored)
|
|
287
|
-
if check_new_file(reducer_state, plw, type, target_name, stored, current_time, file_nanoseconds)
|
|
288
|
-
state = setup_state(reducer_state, packet, current_time)
|
|
289
|
-
end
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
if type == 'minute'
|
|
293
|
-
get_min_samples(packet, state)
|
|
294
|
-
else
|
|
295
|
-
get_hour_day_samples(packet, state)
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
reduced = state.reduced
|
|
299
|
-
if type == 'minute'
|
|
300
|
-
update_min_stats(reduced, state)
|
|
301
|
-
else
|
|
302
|
-
update_raw_hour_day_stats(reduced, state)
|
|
303
|
-
update_converted_hour_day_stats(packet, reduced, state)
|
|
304
|
-
end
|
|
305
|
-
state.first = false
|
|
306
|
-
|
|
307
|
-
throttle.throttle_sleep
|
|
308
|
-
end
|
|
309
|
-
file.delete # Remove the local copy
|
|
310
|
-
|
|
311
|
-
write_all_entries(reducer_state, plw, type, target_name, stored, throttle)
|
|
312
|
-
|
|
313
|
-
@logger.debug("Reducer Throttle: #{filename}: total_time: #{Time.now - throttle.reset_time}, sleep_time: #{throttle.total_sleep_time}")
|
|
314
|
-
|
|
315
|
-
@count += 1
|
|
316
|
-
if type == 'minute'
|
|
317
|
-
metric_name = 'reducer_minute_total'
|
|
318
|
-
elsif type == 'hour'
|
|
319
|
-
metric_name = 'reducer_hour_total'
|
|
320
|
-
else
|
|
321
|
-
metric_name = 'reducer_day_total'
|
|
322
|
-
end
|
|
323
|
-
@previous_metrics[metric_name] ||= 0
|
|
324
|
-
@previous_metrics[metric_name] += 1
|
|
325
|
-
@metric.set(name: metric_name, value: @previous_metrics[metric_name], type: 'counter')
|
|
326
|
-
|
|
327
|
-
true
|
|
328
|
-
rescue => e
|
|
329
|
-
if file.local_path and File.exist?(file.local_path)
|
|
330
|
-
@logger.error("Reducer Error: #{file.local_path}: #{File.size(file.local_path)} bytes: \n#{e.formatted}")
|
|
331
|
-
else
|
|
332
|
-
@logger.error("Reducer Error: #{filename}: \n#{e.formatted}")
|
|
333
|
-
end
|
|
334
|
-
|
|
335
|
-
@error_count += 1
|
|
336
|
-
if type == 'minute'
|
|
337
|
-
metric_name = 'reducer_minute_error_total'
|
|
338
|
-
elsif type == 'hour'
|
|
339
|
-
metric_name = 'reducer_hour_error_total'
|
|
340
|
-
else
|
|
341
|
-
metric_name = 'reducer_day_error_total'
|
|
342
|
-
end
|
|
343
|
-
@previous_metrics[metric_name] ||= 0
|
|
344
|
-
@previous_metrics[metric_name] += 1
|
|
345
|
-
@metric.set(name: metric_name, value: @previous_metrics[metric_name], type: 'counter')
|
|
346
|
-
|
|
347
|
-
file.delete
|
|
348
|
-
false
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
def get_min_samples(packet, state)
|
|
352
|
-
state.entry_samples ||= packet.json_hash.dup # Grab all the samples from the first packet
|
|
353
|
-
if state.first
|
|
354
|
-
state.raw_values = packet.read_all(:RAW, nil, packet.read_all_names(:RAW)).select { |key, value| value.is_a?(Numeric) }
|
|
355
|
-
state.raw_keys ||= state.raw_values.keys
|
|
356
|
-
state.converted_values = packet.read_all(:CONVERTED, nil, packet.read_all_names(:CONVERTED)).select { |key, value| value.is_a?(Numeric) }
|
|
357
|
-
state.converted_keys ||= state.converted_values.keys
|
|
358
|
-
else
|
|
359
|
-
state.raw_values = packet.read_all(:RAW, nil, state.raw_keys).select { |key, value| value.is_a?(Numeric) }
|
|
360
|
-
state.converted_values = packet.read_all(:CONVERTED, nil, state.converted_keys).select { |key, value| value.is_a?(Numeric) }
|
|
361
|
-
end
|
|
362
|
-
end
|
|
363
|
-
|
|
364
|
-
def get_hour_day_samples(packet, state)
|
|
365
|
-
# Hour or Day
|
|
366
|
-
state.entry_samples ||= extract_entry_samples(packet)
|
|
367
|
-
if state.first
|
|
368
|
-
state.raw_max_values = packet.read_all(:RAW, :MAX, packet.read_all_names(:RAW, :MAX))
|
|
369
|
-
state.raw_keys = state.raw_max_values.keys
|
|
370
|
-
state.converted_max_values = packet.read_all(:CONVERTED, :MAX, packet.read_all_names(:CONVERTED, :MAX))
|
|
371
|
-
state.converted_keys = state.converted_max_values.keys
|
|
372
|
-
else
|
|
373
|
-
state.raw_max_values = packet.read_all(:RAW, :MAX, state.raw_keys)
|
|
374
|
-
state.converted_max_values = packet.read_all(:CONVERTED, :MAX, state.converted_keys)
|
|
375
|
-
end
|
|
376
|
-
state.raw_min_values = packet.read_all(:RAW, :MIN, state.raw_keys)
|
|
377
|
-
state.raw_avg_values = packet.read_all(:RAW, :AVG, state.raw_keys)
|
|
378
|
-
state.raw_stddev_values = packet.read_all(:RAW, :STDDEV, state.raw_keys)
|
|
379
|
-
state.converted_min_values = packet.read_all(:CONVERTED, :MIN, state.converted_keys)
|
|
380
|
-
state.converted_avg_values = packet.read_all(:CONVERTED, :AVG, state.converted_keys)
|
|
381
|
-
state.converted_stddev_values = packet.read_all(:CONVERTED, :STDDEV, state.converted_keys)
|
|
382
|
-
end
|
|
383
|
-
|
|
384
|
-
if RUBY_ENGINE != 'ruby' or ENV['OPENC3_NO_EXT']
|
|
385
|
-
def update_min_stats(reduced, state)
|
|
386
|
-
# Update statistics for this packet's raw values
|
|
387
|
-
state.raw_values.each do |key, value|
|
|
388
|
-
if value
|
|
389
|
-
vals_key = "#{key}__VALS"
|
|
390
|
-
reduced[vals_key] ||= []
|
|
391
|
-
reduced[vals_key] << value
|
|
392
|
-
n_key = "#{key}__N"
|
|
393
|
-
reduced[n_key] ||= value
|
|
394
|
-
reduced[n_key] = value if value < reduced[n_key]
|
|
395
|
-
x_key = "#{key}__X"
|
|
396
|
-
reduced[x_key] ||= value
|
|
397
|
-
reduced[x_key] = value if value > reduced[x_key]
|
|
398
|
-
end
|
|
399
|
-
end
|
|
400
|
-
|
|
401
|
-
# Update statistics for this packet's converted values
|
|
402
|
-
state.converted_values.each do |key, value|
|
|
403
|
-
if value
|
|
404
|
-
cvals_key = "#{key}__CVALS"
|
|
405
|
-
reduced[cvals_key] ||= []
|
|
406
|
-
reduced[cvals_key] << value
|
|
407
|
-
cn_key = "#{key}__CN"
|
|
408
|
-
reduced[cn_key] ||= value
|
|
409
|
-
reduced[cn_key] = value if value < reduced[cn_key]
|
|
410
|
-
cx_key = "#{key}__CX"
|
|
411
|
-
reduced[cx_key] ||= value
|
|
412
|
-
reduced[cx_key] = value if value > reduced[cx_key]
|
|
413
|
-
end
|
|
414
|
-
end
|
|
415
|
-
end
|
|
416
|
-
end
|
|
417
|
-
|
|
418
|
-
def update_raw_hour_day_stats(reduced, state)
|
|
419
|
-
# Update statistics for this packet's raw values
|
|
420
|
-
state.raw_max_values.each do |key, value|
|
|
421
|
-
if value
|
|
422
|
-
max_key = "#{key}__X"
|
|
423
|
-
reduced[max_key] ||= value
|
|
424
|
-
reduced[max_key] = value if value > reduced[max_key]
|
|
425
|
-
end
|
|
426
|
-
end
|
|
427
|
-
state.raw_min_values.each do |key, value|
|
|
428
|
-
if value
|
|
429
|
-
min_key = "#{key}__N"
|
|
430
|
-
reduced[min_key] ||= value
|
|
431
|
-
reduced[min_key] = value if value < reduced[min_key]
|
|
432
|
-
end
|
|
433
|
-
end
|
|
434
|
-
state.raw_avg_values.each do |key, value|
|
|
435
|
-
if value
|
|
436
|
-
avg_values_key = "#{key}__AVGVALS"
|
|
437
|
-
reduced[avg_values_key] ||= []
|
|
438
|
-
reduced[avg_values_key] << value
|
|
439
|
-
end
|
|
440
|
-
end
|
|
441
|
-
state.raw_stddev_values.each do |key, value|
|
|
442
|
-
if value
|
|
443
|
-
stddev_values_key = "#{key}__STDDEVVALS"
|
|
444
|
-
reduced[stddev_values_key] ||= []
|
|
445
|
-
reduced[stddev_values_key] << value
|
|
446
|
-
end
|
|
447
|
-
end
|
|
448
|
-
end
|
|
449
|
-
|
|
450
|
-
def update_converted_hour_day_stats(packet, reduced, state)
|
|
451
|
-
# Update statistics for this packet's converted values
|
|
452
|
-
state.converted_max_values.each do |key, value|
|
|
453
|
-
if value
|
|
454
|
-
max_key = "#{key}__CX"
|
|
455
|
-
reduced[max_key] ||= value
|
|
456
|
-
reduced[max_key] = value if value > reduced[max_key]
|
|
457
|
-
end
|
|
458
|
-
end
|
|
459
|
-
state.converted_min_values.each do |key, value|
|
|
460
|
-
if value
|
|
461
|
-
min_key = "#{key}__CN"
|
|
462
|
-
reduced[min_key] ||= value
|
|
463
|
-
reduced[min_key] = value if value < reduced[min_key]
|
|
464
|
-
end
|
|
465
|
-
end
|
|
466
|
-
state.converted_avg_values.each do |key, value|
|
|
467
|
-
if value
|
|
468
|
-
avg_values_key = "#{key}__CAVGVALS"
|
|
469
|
-
reduced[avg_values_key] ||= []
|
|
470
|
-
reduced[avg_values_key] << value
|
|
471
|
-
end
|
|
472
|
-
end
|
|
473
|
-
state.converted_stddev_values.each do |key, value|
|
|
474
|
-
if value
|
|
475
|
-
stddev_values_key = "#{key}__CSTDDEVVALS"
|
|
476
|
-
reduced[stddev_values_key] ||= []
|
|
477
|
-
reduced[stddev_values_key] << value
|
|
478
|
-
end
|
|
479
|
-
end
|
|
480
|
-
|
|
481
|
-
reduced["_NUM_SAMPLES__VALS"] ||= []
|
|
482
|
-
reduced["_NUM_SAMPLES__VALS"] << packet.read('_NUM_SAMPLES')
|
|
483
|
-
end
|
|
484
|
-
|
|
485
|
-
def check_new_file(reducer_state, plw, type, target_name, stored, current_time, file_nanoseconds)
|
|
486
|
-
plw_first_time_nsec = plw.buffered_first_time_nsec
|
|
487
|
-
if plw_first_time_nsec && ((current_time - plw_first_time_nsec) >= file_nanoseconds)
|
|
488
|
-
# Write out all entries in progress
|
|
489
|
-
write_all_entries(reducer_state, plw, type, target_name, stored)
|
|
490
|
-
reducer_state.clear
|
|
491
|
-
plw.close_file
|
|
492
|
-
return true
|
|
493
|
-
else
|
|
494
|
-
return false
|
|
495
|
-
end
|
|
496
|
-
end
|
|
497
|
-
|
|
498
|
-
def setup_state(reducer_state, packet, current_time)
|
|
499
|
-
# Get state for this packet
|
|
500
|
-
state = reducer_state[packet.packet_name]
|
|
501
|
-
unless state
|
|
502
|
-
state = ReducerState.new
|
|
503
|
-
reducer_state[packet.packet_name] = state
|
|
504
|
-
end
|
|
505
|
-
|
|
506
|
-
# Update state timestamps
|
|
507
|
-
state.previous_time = state.current_time # Will be nil first packet
|
|
508
|
-
state.current_time = current_time
|
|
509
|
-
state.entry_time ||= state.current_time # Sets the entry time from the first packet
|
|
510
|
-
return state
|
|
511
|
-
end
|
|
512
|
-
|
|
513
|
-
def write_all_entries(reducer_state, plw, type, target_name, stored, throttle = nil)
|
|
514
|
-
reducer_state.each do |packet_name, state|
|
|
515
|
-
write_entry(state, plw, type, target_name, packet_name, stored)
|
|
516
|
-
throttle.throttle_sleep if throttle
|
|
517
|
-
end
|
|
518
|
-
end
|
|
519
|
-
|
|
520
|
-
def write_entry(state, plw, type, target_name, packet_name, stored)
|
|
521
|
-
return unless state.reduced.length > 0
|
|
522
|
-
reduce(type, state.raw_keys, state.converted_keys, state.reduced)
|
|
523
|
-
state.reduced.merge!(state.entry_samples)
|
|
524
|
-
time = state.entry_time
|
|
525
|
-
data = JSON.generate(state.reduced.as_json, allow_nan: true)
|
|
526
|
-
if type == "minute"
|
|
527
|
-
redis_topic, redis_offset = TelemetryReducedMinuteTopic.write(target_name: target_name, packet_name: packet_name, stored: stored, time: time, data: data, scope: @scope)
|
|
528
|
-
elsif type == "hour"
|
|
529
|
-
redis_topic, redis_offset = TelemetryReducedHourTopic.write(target_name: target_name, packet_name: packet_name, stored: stored, time: time, data: data, scope: @scope)
|
|
530
|
-
else
|
|
531
|
-
redis_topic, redis_offset = TelemetryReducedDayTopic.write(target_name: target_name, packet_name: packet_name, stored: stored, time: time, data: data, scope: @scope)
|
|
532
|
-
end
|
|
533
|
-
plw.buffered_write(
|
|
534
|
-
:JSON_PACKET,
|
|
535
|
-
:TLM,
|
|
536
|
-
target_name,
|
|
537
|
-
packet_name,
|
|
538
|
-
time,
|
|
539
|
-
stored,
|
|
540
|
-
data,
|
|
541
|
-
nil,
|
|
542
|
-
redis_topic,
|
|
543
|
-
redis_offset
|
|
544
|
-
)
|
|
545
|
-
|
|
546
|
-
# Reset necessary state variables
|
|
547
|
-
state.entry_time = state.current_time # This packet starts the next entry
|
|
548
|
-
state.entry_samples = nil
|
|
549
|
-
state.reduced = {}
|
|
550
|
-
end
|
|
551
|
-
|
|
552
|
-
def reduce(type, raw_keys, converted_keys, reduced)
|
|
553
|
-
# We've collected all the values so calculate the AVG and STDDEV
|
|
554
|
-
if type == 'minute'
|
|
555
|
-
raw_keys.each do |key|
|
|
556
|
-
if reduced["#{key}__VALS"]
|
|
557
|
-
reduced["_NUM_SAMPLES"] ||= reduced["#{key}__VALS"].length # Keep a single sample count per packet
|
|
558
|
-
reduced["#{key}__A"], reduced["#{key}__S"] =
|
|
559
|
-
Math.stddev_population(reduced["#{key}__VALS"])
|
|
560
|
-
# Remove the raw values as they're only used for AVG / STDDEV calculation
|
|
561
|
-
reduced.delete("#{key}__VALS")
|
|
562
|
-
end
|
|
563
|
-
end
|
|
564
|
-
|
|
565
|
-
converted_keys.each do |key|
|
|
566
|
-
if reduced["#{key}__CVALS"]
|
|
567
|
-
reduced["_NUM_SAMPLES"] ||= reduced["#{key}__CVALS"].length # Keep a single sample count per packet
|
|
568
|
-
reduced["#{key}__CA"], reduced["#{key}__CS"] =
|
|
569
|
-
Math.stddev_population(reduced["#{key}__CVALS"])
|
|
570
|
-
|
|
571
|
-
# Remove the converted values as they're only used for AVG / STDDEV calculation
|
|
572
|
-
reduced.delete("#{key}__CVALS")
|
|
573
|
-
end
|
|
574
|
-
end
|
|
575
|
-
else
|
|
576
|
-
samples = reduced["_NUM_SAMPLES__VALS"]
|
|
577
|
-
samples_sum = samples.sum
|
|
578
|
-
reduced["_NUM_SAMPLES"] = samples_sum
|
|
579
|
-
reduced.delete("_NUM_SAMPLES__VALS")
|
|
580
|
-
|
|
581
|
-
raw_keys.each { |key| reduce_running(key, reduced, samples, samples_sum, "__A", "__S", "__AVGVALS", "__STDDEVVALS") }
|
|
582
|
-
converted_keys.each { |key| reduce_running(key, reduced, samples, samples_sum, "__CA", "__CS", "__CAVGVALS", "__CSTDDEVVALS") }
|
|
583
|
-
end
|
|
584
|
-
end
|
|
585
|
-
|
|
586
|
-
def reduce_running(key, reduced, samples, samples_sum, avg_key, stddev_key, avgvals_key, stddevvals_key)
|
|
587
|
-
# Calculate Average
|
|
588
|
-
weighted_sum = 0
|
|
589
|
-
avg = reduced["#{key}#{avgvals_key}"]
|
|
590
|
-
if avg
|
|
591
|
-
avg.each_with_index do |val, i|
|
|
592
|
-
weighted_sum += (val * samples[i])
|
|
593
|
-
end
|
|
594
|
-
reduced["#{key}#{avg_key}"] = weighted_sum / samples_sum
|
|
595
|
-
end
|
|
596
|
-
|
|
597
|
-
# Do the STDDEV calc last so we can use the previously calculated AVG
|
|
598
|
-
# See https://math.stackexchange.com/questions/1547141/aggregating-standard-deviation-to-a-summary-point
|
|
599
|
-
s2 = 0
|
|
600
|
-
stddev = reduced["#{key}#{stddevvals_key}"]
|
|
601
|
-
if stddev
|
|
602
|
-
stddev.each_with_index do |val, i|
|
|
603
|
-
# puts "i:#{i} val:#{val} samples[i]:#{samples[i]} avg[i]:#{avg[i]}"
|
|
604
|
-
s2 += (samples[i] * avg[i]**2 + val**2)
|
|
605
|
-
end
|
|
606
|
-
|
|
607
|
-
# Note: For very large numbers with very small deviations this sqrt can fail.
|
|
608
|
-
# If so then just set the stddev to 0.
|
|
609
|
-
begin
|
|
610
|
-
reduced["#{key}#{stddev_key}"] =
|
|
611
|
-
Math.sqrt(s2 / samples_sum - reduced["#{key}#{avg_key}"])
|
|
612
|
-
rescue Exception
|
|
613
|
-
reduced["#{key}#{stddev_key}"] = 0.0
|
|
614
|
-
end
|
|
615
|
-
end
|
|
616
|
-
|
|
617
|
-
reduced.delete("#{key}#{avgvals_key}")
|
|
618
|
-
reduced.delete("#{key}#{stddevvals_key}")
|
|
619
|
-
end
|
|
620
|
-
|
|
621
|
-
# Extract just the not reduced fields from a JsonPacket
|
|
622
|
-
def extract_entry_samples(packet)
|
|
623
|
-
result = {}
|
|
624
|
-
packet.json_hash.each do |key, value|
|
|
625
|
-
key_split = key.split('__')
|
|
626
|
-
if (not key_split[1] or not ['N', 'X', 'A', 'S'].include?(key_split[1][-1])) and key != '_NUM_SAMPLES'
|
|
627
|
-
result[key] = value
|
|
628
|
-
end
|
|
629
|
-
end
|
|
630
|
-
return result
|
|
631
|
-
end
|
|
632
|
-
|
|
633
|
-
end
|
|
634
|
-
end
|
|
635
|
-
|
|
636
|
-
if __FILE__ == $0
|
|
637
|
-
OpenC3::ReducerMicroservice.run
|
|
638
|
-
OpenC3::ThreadManager.instance.shutdown
|
|
639
|
-
OpenC3::ThreadManager.instance.join
|
|
640
|
-
end
|