openc3 5.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +18 -0
- data/Guardfile +35 -0
- data/LICENSE.txt +727 -0
- data/README.md +37 -0
- data/Rakefile +131 -0
- data/bin/cstol_converter +1178 -0
- data/bin/openc3cli +531 -0
- data/bin/rubysloc +139 -0
- data/data/config/_array_params.yaml +23 -0
- data/data/config/_id_items.yaml +24 -0
- data/data/config/_id_params.yaml +58 -0
- data/data/config/_interfaces.yaml +214 -0
- data/data/config/_interfaces.yaml.err +1017 -0
- data/data/config/_items.yaml +20 -0
- data/data/config/_params.yaml +60 -0
- data/data/config/cmd_tlm_server.yaml +136 -0
- data/data/config/command.yaml +44 -0
- data/data/config/command_modifiers.yaml +160 -0
- data/data/config/command_telemetry.yaml +3 -0
- data/data/config/interface_modifiers.yaml +104 -0
- data/data/config/item_modifiers.yaml +221 -0
- data/data/config/microservice.yaml +78 -0
- data/data/config/param_item_modifiers.yaml +52 -0
- data/data/config/parameter_modifiers.yaml +200 -0
- data/data/config/plugins.yaml +80 -0
- data/data/config/protocols.yaml +290 -0
- data/data/config/screen.yaml +147 -0
- data/data/config/table_manager.yaml +89 -0
- data/data/config/table_parameter_modifiers.yaml +9 -0
- data/data/config/target.yaml +142 -0
- data/data/config/target_config.yaml +94 -0
- data/data/config/telemetry.yaml +87 -0
- data/data/config/telemetry_modifiers.yaml +159 -0
- data/data/config/tool.yaml +63 -0
- data/data/config/unknown.yaml +3 -0
- data/data/config/widgets.yaml +1505 -0
- data/ext/mkrf_conf.rb +49 -0
- data/ext/openc3/ext/array/array.c +122 -0
- data/ext/openc3/ext/array/extconf.rb +13 -0
- data/ext/openc3/ext/buffered_file/buffered_file.c +198 -0
- data/ext/openc3/ext/buffered_file/extconf.rb +13 -0
- data/ext/openc3/ext/config_parser/config_parser.c +280 -0
- data/ext/openc3/ext/config_parser/extconf.rb +13 -0
- data/ext/openc3/ext/crc/crc.c +351 -0
- data/ext/openc3/ext/crc/extconf.rb +13 -0
- data/ext/openc3/ext/openc3_io/extconf.rb +13 -0
- data/ext/openc3/ext/openc3_io/openc3_io.c +158 -0
- data/ext/openc3/ext/packet/extconf.rb +13 -0
- data/ext/openc3/ext/packet/packet.c +318 -0
- data/ext/openc3/ext/platform/extconf.rb +13 -0
- data/ext/openc3/ext/platform/platform.c +134 -0
- data/ext/openc3/ext/polynomial_conversion/extconf.rb +13 -0
- data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +79 -0
- data/ext/openc3/ext/string/extconf.rb +13 -0
- data/ext/openc3/ext/string/string.c +63 -0
- data/ext/openc3/ext/structure/structure.c +1719 -0
- data/ext/openc3/ext/tabbed_plots_config/extconf.rb +13 -0
- data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +62 -0
- data/ext/openc3/ext/telemetry/extconf.rb +13 -0
- data/ext/openc3/ext/telemetry/telemetry.c +336 -0
- data/lib/cosmos.rb +20 -0
- data/lib/cosmosc2.rb +20 -0
- data/lib/openc3/api/api.rb +39 -0
- data/lib/openc3/api/authorized_api.rb +30 -0
- data/lib/openc3/api/cmd_api.rb +451 -0
- data/lib/openc3/api/config_api.rb +58 -0
- data/lib/openc3/api/interface_api.rb +117 -0
- data/lib/openc3/api/limits_api.rb +375 -0
- data/lib/openc3/api/router_api.rb +117 -0
- data/lib/openc3/api/settings_api.rb +70 -0
- data/lib/openc3/api/target_api.rb +78 -0
- data/lib/openc3/api/tlm_api.rb +455 -0
- data/lib/openc3/bridge/bridge.rb +54 -0
- data/lib/openc3/bridge/bridge_config.rb +167 -0
- data/lib/openc3/bridge/bridge_interface_thread.rb +42 -0
- data/lib/openc3/bridge/bridge_router_thread.rb +42 -0
- data/lib/openc3/ccsds/ccsds_packet.rb +68 -0
- data/lib/openc3/ccsds/ccsds_parser.rb +148 -0
- data/lib/openc3/config/config_parser.rb +549 -0
- data/lib/openc3/config/meta_config_parser.rb +74 -0
- data/lib/openc3/conversions/conversion.rb +70 -0
- data/lib/openc3/conversions/generic_conversion.rb +83 -0
- data/lib/openc3/conversions/packet_time_formatted_conversion.rb +43 -0
- data/lib/openc3/conversions/packet_time_seconds_conversion.rb +43 -0
- data/lib/openc3/conversions/polynomial_conversion.rb +87 -0
- data/lib/openc3/conversions/processor_conversion.rb +70 -0
- data/lib/openc3/conversions/received_count_conversion.rb +38 -0
- data/lib/openc3/conversions/received_time_formatted_conversion.rb +42 -0
- data/lib/openc3/conversions/received_time_seconds_conversion.rb +42 -0
- data/lib/openc3/conversions/segmented_polynomial_conversion.rb +171 -0
- data/lib/openc3/conversions/unix_time_conversion.rb +68 -0
- data/lib/openc3/conversions/unix_time_formatted_conversion.rb +49 -0
- data/lib/openc3/conversions/unix_time_seconds_conversion.rb +49 -0
- data/lib/openc3/conversions.rb +34 -0
- data/lib/openc3/core_ext/array.rb +416 -0
- data/lib/openc3/core_ext/binding.rb +29 -0
- data/lib/openc3/core_ext/class.rb +72 -0
- data/lib/openc3/core_ext/exception.rb +61 -0
- data/lib/openc3/core_ext/file.rb +83 -0
- data/lib/openc3/core_ext/hash.rb +37 -0
- data/lib/openc3/core_ext/io.rb +134 -0
- data/lib/openc3/core_ext/kernel.rb +42 -0
- data/lib/openc3/core_ext/math.rb +128 -0
- data/lib/openc3/core_ext/matrix.rb +156 -0
- data/lib/openc3/core_ext/objectspace.rb +36 -0
- data/lib/openc3/core_ext/openc3_io.rb +57 -0
- data/lib/openc3/core_ext/range.rb +27 -0
- data/lib/openc3/core_ext/socket.rb +38 -0
- data/lib/openc3/core_ext/string.rb +389 -0
- data/lib/openc3/core_ext/stringio.rb +33 -0
- data/lib/openc3/core_ext/time.rb +508 -0
- data/lib/openc3/core_ext.rb +36 -0
- data/lib/openc3/interfaces/interface.rb +498 -0
- data/lib/openc3/interfaces/linc_interface.rb +475 -0
- data/lib/openc3/interfaces/protocols/burst_protocol.rb +192 -0
- data/lib/openc3/interfaces/protocols/crc_protocol.rb +193 -0
- data/lib/openc3/interfaces/protocols/fixed_protocol.rb +155 -0
- data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +56 -0
- data/lib/openc3/interfaces/protocols/length_protocol.rb +165 -0
- data/lib/openc3/interfaces/protocols/override_protocol.rb +60 -0
- data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +206 -0
- data/lib/openc3/interfaces/protocols/protocol.rb +82 -0
- data/lib/openc3/interfaces/protocols/template_protocol.rb +261 -0
- data/lib/openc3/interfaces/protocols/terminated_protocol.rb +93 -0
- data/lib/openc3/interfaces/serial_interface.rb +94 -0
- data/lib/openc3/interfaces/simulated_target_interface.rb +168 -0
- data/lib/openc3/interfaces/stream_interface.rb +81 -0
- data/lib/openc3/interfaces/tcpip_client_interface.rb +69 -0
- data/lib/openc3/interfaces/tcpip_server_interface.rb +629 -0
- data/lib/openc3/interfaces/udp_interface.rb +169 -0
- data/lib/openc3/interfaces.rb +44 -0
- data/lib/openc3/io/buffered_file.rb +109 -0
- data/lib/openc3/io/io_multiplexer.rb +80 -0
- data/lib/openc3/io/json_api_object.rb +208 -0
- data/lib/openc3/io/json_drb.rb +335 -0
- data/lib/openc3/io/json_drb_object.rb +114 -0
- data/lib/openc3/io/json_drb_rack.rb +84 -0
- data/lib/openc3/io/json_rpc.rb +420 -0
- data/lib/openc3/io/openc3_snmp.rb +58 -0
- data/lib/openc3/io/posix_serial_driver.rb +156 -0
- data/lib/openc3/io/raw_logger.rb +167 -0
- data/lib/openc3/io/raw_logger_pair.rb +77 -0
- data/lib/openc3/io/serial_driver.rb +105 -0
- data/lib/openc3/io/stderr.rb +43 -0
- data/lib/openc3/io/stdout.rb +43 -0
- data/lib/openc3/io/udp_sockets.rb +194 -0
- data/lib/openc3/io/win32_serial_driver.rb +196 -0
- data/lib/openc3/logs/log_writer.rb +302 -0
- data/lib/openc3/logs/packet_log_constants.rb +62 -0
- data/lib/openc3/logs/packet_log_reader.rb +345 -0
- data/lib/openc3/logs/packet_log_writer.rb +299 -0
- data/lib/openc3/logs/text_log_writer.rb +68 -0
- data/lib/openc3/logs.rb +25 -0
- data/lib/openc3/microservices/cleanup_microservice.rb +68 -0
- data/lib/openc3/microservices/decom_microservice.rb +136 -0
- data/lib/openc3/microservices/interface_microservice.rb +532 -0
- data/lib/openc3/microservices/log_microservice.rb +108 -0
- data/lib/openc3/microservices/microservice.rb +204 -0
- data/lib/openc3/microservices/plugin_microservice.rb +43 -0
- data/lib/openc3/microservices/reaction_microservice.rb +541 -0
- data/lib/openc3/microservices/reducer_microservice.rb +313 -0
- data/lib/openc3/microservices/router_microservice.rb +44 -0
- data/lib/openc3/microservices/text_log_microservice.rb +84 -0
- data/lib/openc3/microservices/timeline_microservice.rb +363 -0
- data/lib/openc3/microservices/trigger_group_microservice.rb +638 -0
- data/lib/openc3/models/activity_model.rb +319 -0
- data/lib/openc3/models/auth_model.rb +65 -0
- data/lib/openc3/models/cvt_model.rb +185 -0
- data/lib/openc3/models/environment_model.rb +58 -0
- data/lib/openc3/models/gem_model.rb +137 -0
- data/lib/openc3/models/info_model.rb +31 -0
- data/lib/openc3/models/interface_model.rb +281 -0
- data/lib/openc3/models/interface_status_model.rb +117 -0
- data/lib/openc3/models/metadata_model.rb +139 -0
- data/lib/openc3/models/metric_model.rb +59 -0
- data/lib/openc3/models/microservice_model.rb +206 -0
- data/lib/openc3/models/microservice_status_model.rb +74 -0
- data/lib/openc3/models/model.rb +204 -0
- data/lib/openc3/models/note_model.rb +122 -0
- data/lib/openc3/models/notification_model.rb +40 -0
- data/lib/openc3/models/ping_model.rb +35 -0
- data/lib/openc3/models/plugin_model.rb +292 -0
- data/lib/openc3/models/process_status_model.rb +76 -0
- data/lib/openc3/models/reaction_model.rb +322 -0
- data/lib/openc3/models/reducer_model.rb +65 -0
- data/lib/openc3/models/router_model.rb +35 -0
- data/lib/openc3/models/router_status_model.rb +27 -0
- data/lib/openc3/models/scope_model.rb +153 -0
- data/lib/openc3/models/settings_model.rb +55 -0
- data/lib/openc3/models/sorted_model.rb +167 -0
- data/lib/openc3/models/target_model.rb +759 -0
- data/lib/openc3/models/timeline_model.rb +154 -0
- data/lib/openc3/models/tool_config_model.rb +38 -0
- data/lib/openc3/models/tool_model.rb +262 -0
- data/lib/openc3/models/trigger_group_model.rb +186 -0
- data/lib/openc3/models/trigger_model.rb +330 -0
- data/lib/openc3/models/widget_model.rb +138 -0
- data/lib/openc3/operators/microservice_operator.rb +128 -0
- data/lib/openc3/operators/operator.rb +277 -0
- data/lib/openc3/packets/binary_accessor.rb +1207 -0
- data/lib/openc3/packets/commands.rb +373 -0
- data/lib/openc3/packets/json_packet.rb +134 -0
- data/lib/openc3/packets/limits.rb +271 -0
- data/lib/openc3/packets/limits_response.rb +53 -0
- data/lib/openc3/packets/packet.rb +1168 -0
- data/lib/openc3/packets/packet_config.rb +625 -0
- data/lib/openc3/packets/packet_item.rb +586 -0
- data/lib/openc3/packets/packet_item_limits.rb +162 -0
- data/lib/openc3/packets/parsers/format_string_parser.rb +65 -0
- data/lib/openc3/packets/parsers/limits_parser.rb +159 -0
- data/lib/openc3/packets/parsers/limits_response_parser.rb +61 -0
- data/lib/openc3/packets/parsers/packet_item_parser.rb +272 -0
- data/lib/openc3/packets/parsers/packet_parser.rb +134 -0
- data/lib/openc3/packets/parsers/processor_parser.rb +73 -0
- data/lib/openc3/packets/parsers/state_parser.rb +127 -0
- data/lib/openc3/packets/parsers/xtce_converter.rb +442 -0
- data/lib/openc3/packets/parsers/xtce_parser.rb +722 -0
- data/lib/openc3/packets/structure.rb +553 -0
- data/lib/openc3/packets/structure_item.rb +365 -0
- data/lib/openc3/packets/telemetry.rb +487 -0
- data/lib/openc3/processors/processor.rb +86 -0
- data/lib/openc3/processors/statistics_processor.rb +82 -0
- data/lib/openc3/processors/watermark_processor.rb +58 -0
- data/lib/openc3/processors.rb +24 -0
- data/lib/openc3/script/api_shared.rb +828 -0
- data/lib/openc3/script/calendar.rb +89 -0
- data/lib/openc3/script/commands.rb +227 -0
- data/lib/openc3/script/exceptions.rb +29 -0
- data/lib/openc3/script/extract.rb +161 -0
- data/lib/openc3/script/limits.rb +60 -0
- data/lib/openc3/script/script.rb +299 -0
- data/lib/openc3/script/script_runner.rb +238 -0
- data/lib/openc3/script/storage.rb +146 -0
- data/lib/openc3/script/suite.rb +542 -0
- data/lib/openc3/script/suite_results.rb +196 -0
- data/lib/openc3/script/suite_runner.rb +217 -0
- data/lib/openc3/script.rb +21 -0
- data/lib/openc3/streams/serial_stream.rb +167 -0
- data/lib/openc3/streams/stream.rb +63 -0
- data/lib/openc3/streams/tcpip_client_stream.rb +116 -0
- data/lib/openc3/streams/tcpip_socket_stream.rb +195 -0
- data/lib/openc3/system/system.rb +127 -0
- data/lib/openc3/system/system_config.rb +411 -0
- data/lib/openc3/system/target.rb +269 -0
- data/lib/openc3/system.rb +24 -0
- data/lib/openc3/tools/cmd_tlm_server/api.rb +20 -0
- data/lib/openc3/tools/cmd_tlm_server/cmd_tlm_server_config.rb +320 -0
- data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +294 -0
- data/lib/openc3/tools/table_manager/table.rb +77 -0
- data/lib/openc3/tools/table_manager/table_config.rb +273 -0
- data/lib/openc3/tools/table_manager/table_item.rb +90 -0
- data/lib/openc3/tools/table_manager/table_item_parser.rb +66 -0
- data/lib/openc3/tools/table_manager/table_manager_core.rb +333 -0
- data/lib/openc3/tools/table_manager/table_parser.rb +93 -0
- data/lib/openc3/tools/test_runner/test.rb +67 -0
- data/lib/openc3/top_level.rb +595 -0
- data/lib/openc3/topics/autonomic_topic.rb +52 -0
- data/lib/openc3/topics/calendar_topic.rb +44 -0
- data/lib/openc3/topics/command_decom_topic.rb +76 -0
- data/lib/openc3/topics/command_topic.rb +83 -0
- data/lib/openc3/topics/config_topic.rb +68 -0
- data/lib/openc3/topics/interface_topic.rb +73 -0
- data/lib/openc3/topics/limits_event_topic.rb +109 -0
- data/lib/openc3/topics/notifications_topic.rb +28 -0
- data/lib/openc3/topics/router_topic.rb +85 -0
- data/lib/openc3/topics/telemetry_decom_topic.rb +54 -0
- data/lib/openc3/topics/telemetry_topic.rb +36 -0
- data/lib/openc3/topics/timeline_topic.rb +45 -0
- data/lib/openc3/topics/topic.rb +53 -0
- data/lib/openc3/utilities/authentication.rb +141 -0
- data/lib/openc3/utilities/authorization.rb +51 -0
- data/lib/openc3/utilities/crc.rb +278 -0
- data/lib/openc3/utilities/csv.rb +153 -0
- data/lib/openc3/utilities/logger.rb +187 -0
- data/lib/openc3/utilities/message_log.rb +91 -0
- data/lib/openc3/utilities/metric.rb +141 -0
- data/lib/openc3/utilities/process_manager.rb +139 -0
- data/lib/openc3/utilities/quaternion.rb +257 -0
- data/lib/openc3/utilities/ruby_lex_utils.rb +568 -0
- data/lib/openc3/utilities/s3.rb +202 -0
- data/lib/openc3/utilities/s3_autoload.rb +9 -0
- data/lib/openc3/utilities/s3_file_cache.rb +274 -0
- data/lib/openc3/utilities/simulated_target.rb +117 -0
- data/lib/openc3/utilities/sleeper.rb +51 -0
- data/lib/openc3/utilities/store.rb +23 -0
- data/lib/openc3/utilities/store_autoload.rb +237 -0
- data/lib/openc3/utilities/zip.rb +21 -0
- data/lib/openc3/utilities.rb +35 -0
- data/lib/openc3/version.rb +14 -0
- data/lib/openc3/win32/excel.rb +132 -0
- data/lib/openc3/win32/win32.rb +402 -0
- data/lib/openc3/win32/win32_main.rb +333 -0
- data/lib/openc3.rb +49 -0
- data/tasks/gemfile_stats.rake +113 -0
- data/tasks/spec.rake +30 -0
- data/templates/plugin-template/README.md +15 -0
- data/templates/plugin-template/Rakefile +12 -0
- data/templates/plugin-template/plugin.gemspec +23 -0
- data/templates/plugin-template/plugin.txt +9 -0
- data/templates/plugin-template/targets/TARGET/cmd_tlm/cmd.txt +8 -0
- data/templates/plugin-template/targets/TARGET/cmd_tlm/tlm.txt +8 -0
- data/templates/plugin-template/targets/TARGET/lib/target.rb +10 -0
- data/templates/plugin-template/targets/TARGET/procedures/procedure.rb +3 -0
- data/templates/plugin-template/targets/TARGET/screens/status.txt +9 -0
- data/templates/plugin-template/targets/TARGET/target.txt +5 -0
- metadata +849 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2022 Ball Aerospace & Technologies Corp.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
|
7
|
+
# under the terms of the GNU Affero General Public License
|
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU Affero General Public License for more details.
|
|
15
|
+
|
|
16
|
+
# Modified by OpenC3, Inc.
|
|
17
|
+
# All changes Copyright 2022, OpenC3, Inc.
|
|
18
|
+
# All Rights Reserved
|
|
19
|
+
|
|
20
|
+
require 'thread'
|
|
21
|
+
require 'socket'
|
|
22
|
+
require 'json'
|
|
23
|
+
# require 'drb/acl'
|
|
24
|
+
require 'drb/drb'
|
|
25
|
+
require 'set'
|
|
26
|
+
require 'openc3/io/json_rpc'
|
|
27
|
+
require 'openc3/io/json_drb_rack'
|
|
28
|
+
require 'rack/handler/puma'
|
|
29
|
+
|
|
30
|
+
# Add methods to the Puma::Launcher and Puma::Single class so we can tell
|
|
31
|
+
# if the server has been started.
|
|
32
|
+
module Puma
|
|
33
|
+
class Launcher
|
|
34
|
+
def running
|
|
35
|
+
@runner and @runner.running
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class Runner
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class Single < Runner
|
|
43
|
+
def running
|
|
44
|
+
@server and @server.running
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
module OpenC3
|
|
50
|
+
# JsonDRb implements the JSON-RPC 2.0 Specification to provide an interface
|
|
51
|
+
# for both internal and external tools to access the OpenC3 server. It
|
|
52
|
+
# provides methods to install an access control list to control access to the
|
|
53
|
+
# API. It also limits the available methods to a known list of allowable API
|
|
54
|
+
# methods.
|
|
55
|
+
class JsonDRb
|
|
56
|
+
# Minimum amount of time in seconds to receive the JSON request,
|
|
57
|
+
# process it, and send the response. Requests for less than this amount
|
|
58
|
+
# will be set to the minimum
|
|
59
|
+
MINIMUM_REQUEST_TIME = 0.0001
|
|
60
|
+
STOP_SERVICE_TIMEOUT = 10.0 # seconds to wait when stopping the service
|
|
61
|
+
PUMA_THREAD_TIMEOUT = 10.0 # seconds to wait for the puma threads to die
|
|
62
|
+
SERVER_START_TIMEOUT = 15.0 # seconds to wait for the server to start
|
|
63
|
+
|
|
64
|
+
@@debug = false
|
|
65
|
+
|
|
66
|
+
# @return [Integer] The number of JSON-RPC requests processed
|
|
67
|
+
attr_accessor :request_count
|
|
68
|
+
# @return [Array<String>] List of methods that should be allowed
|
|
69
|
+
attr_accessor :method_whitelist
|
|
70
|
+
# @return [ACL] The access control list
|
|
71
|
+
# attr_accessor :acl
|
|
72
|
+
|
|
73
|
+
attr_accessor :object
|
|
74
|
+
|
|
75
|
+
def initialize
|
|
76
|
+
@thread = nil
|
|
77
|
+
# @acl = nil
|
|
78
|
+
@object = nil
|
|
79
|
+
@method_whitelist = nil
|
|
80
|
+
@request_count = 0
|
|
81
|
+
@request_times = []
|
|
82
|
+
@request_times_index = 0
|
|
83
|
+
@request_mutex = Mutex.new
|
|
84
|
+
@server = nil
|
|
85
|
+
@server_mutex = Mutex.new
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Returns the number of connected clients
|
|
89
|
+
# @return [Integer] The number of connected clients
|
|
90
|
+
def num_clients
|
|
91
|
+
clients = 0
|
|
92
|
+
@server_mutex.synchronize do
|
|
93
|
+
if @server
|
|
94
|
+
# @server.stats() returns a string like: { "backlog": 0, "running": 0 }
|
|
95
|
+
# "running" indicates the number of server threads running, and
|
|
96
|
+
# therefore the number of clients connected.
|
|
97
|
+
stats = @server.stats()
|
|
98
|
+
stats =~ /"running": \d*/
|
|
99
|
+
clients = $&.split(":")[1].to_i
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
return clients
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Stops the DRb service by closing the socket and the processing thread
|
|
106
|
+
def stop_service
|
|
107
|
+
# Kill the server thread
|
|
108
|
+
# parameters are owner, thread, graceful_timeout, timeout_interval, hard_timeout
|
|
109
|
+
OpenC3.kill_thread(self, @thread, STOP_SERVICE_TIMEOUT, 0.1, STOP_SERVICE_TIMEOUT)
|
|
110
|
+
@thread = nil
|
|
111
|
+
@server_mutex.synchronize do
|
|
112
|
+
@server = nil
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Gracefully kill the thread
|
|
117
|
+
def graceful_kill
|
|
118
|
+
@server_mutex.synchronize do
|
|
119
|
+
@server.stop if @server and @server.running
|
|
120
|
+
rescue
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @param hostname [String] The host to start the service on
|
|
125
|
+
# @param port [Integer] The port number to listen for connections
|
|
126
|
+
# @param object [Object] The object to send the DRb requests to.
|
|
127
|
+
def start_service(hostname = nil, port = nil, object = nil, max_threads = 1000)
|
|
128
|
+
server_started = false
|
|
129
|
+
@server_mutex.synchronize do
|
|
130
|
+
server_started = true if @server
|
|
131
|
+
end
|
|
132
|
+
return if server_started
|
|
133
|
+
|
|
134
|
+
if hostname and port and object
|
|
135
|
+
@object = object
|
|
136
|
+
hostname = '127.0.0.1'.freeze if hostname.to_s.upcase == 'LOCALHOST'.freeze
|
|
137
|
+
|
|
138
|
+
@thread = Thread.new do
|
|
139
|
+
# Create an http server to accept requests from clients
|
|
140
|
+
|
|
141
|
+
server_config = {
|
|
142
|
+
:Host => hostname,
|
|
143
|
+
:Port => port,
|
|
144
|
+
:Silent => true,
|
|
145
|
+
:Verbose => false,
|
|
146
|
+
:Threads => "0:#{max_threads}",
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# The run call will block until the server is stopped.
|
|
150
|
+
Rack::Handler::Puma.run(JsonDrbRack.new(self), server_config) do |server|
|
|
151
|
+
@server_mutex.synchronize do
|
|
152
|
+
@server = server
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Wait for all puma threads to stop before trying to close
|
|
157
|
+
# the sockets
|
|
158
|
+
start_time = Time.now
|
|
159
|
+
while true
|
|
160
|
+
puma_threads = false
|
|
161
|
+
Thread.list.each { |thread| puma_threads = true if thread.inspect.match?(/puma/) }
|
|
162
|
+
break if !puma_threads
|
|
163
|
+
break if (Time.now - start_time) > PUMA_THREAD_TIMEOUT
|
|
164
|
+
|
|
165
|
+
sleep 0.25
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Puma doesn't clean up it's own sockets after shutting down,
|
|
169
|
+
# so we'll do that here.
|
|
170
|
+
@server_mutex.synchronize do
|
|
171
|
+
@server.binder.close() if @server
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# The address in use error is pretty typical if an existing
|
|
175
|
+
# server is running so explicitly rescue this
|
|
176
|
+
rescue Errno::EADDRINUSE
|
|
177
|
+
@server = nil
|
|
178
|
+
raise "Error binding to port #{port}.\n" +
|
|
179
|
+
"Either another application is using this port\n" +
|
|
180
|
+
"or the operating system is being slow cleaning up.\n" +
|
|
181
|
+
"Make sure all sockets/streams are closed in all applications,\n" +
|
|
182
|
+
"wait 1 minute and try again."
|
|
183
|
+
# Something else went wrong which is fatal
|
|
184
|
+
rescue => error
|
|
185
|
+
@server = nil
|
|
186
|
+
Logger.error "JsonDRb http server could not be started or unexpectedly died.\n#{error.formatted}"
|
|
187
|
+
OpenC3.handle_fatal_exception(error)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Wait for the server to be started in the thread before returning.
|
|
191
|
+
start_time = Time.now
|
|
192
|
+
while ((Time.now - start_time) < SERVER_START_TIMEOUT) and !server_started
|
|
193
|
+
sleep(0.1)
|
|
194
|
+
@server_mutex.synchronize do
|
|
195
|
+
server_started = true if @server and @server.running
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
raise "JsonDRb http server could not be started." unless server_started
|
|
199
|
+
|
|
200
|
+
elsif hostname or port or object
|
|
201
|
+
raise "0 or 3 parameters must be given"
|
|
202
|
+
else
|
|
203
|
+
# Client - Noop
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# @return [Thread] The server thread listening for incoming requests
|
|
208
|
+
attr_reader :thread
|
|
209
|
+
|
|
210
|
+
# Adds a request time to the list. A request time consists of the amount of
|
|
211
|
+
# time to receive the request, process it, and send the response. These
|
|
212
|
+
# times are used by the {#average_request_time} method to calculate an
|
|
213
|
+
# average request time.
|
|
214
|
+
#
|
|
215
|
+
# @param request_time [Float] Time in seconds for the data transmission
|
|
216
|
+
def add_request_time(request_time)
|
|
217
|
+
@request_mutex.synchronize do
|
|
218
|
+
request_time = MINIMUM_REQUEST_TIME if request_time < MINIMUM_REQUEST_TIME
|
|
219
|
+
@request_times[@request_times_index] = request_time
|
|
220
|
+
@request_times_index += 1
|
|
221
|
+
@request_times_index = 0 if @request_times_index >= 100
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# @return [Float] The average time in seconds for a JSON DRb request to be
|
|
226
|
+
# processed and the response sent.
|
|
227
|
+
def average_request_time
|
|
228
|
+
avg = 0
|
|
229
|
+
@request_mutex.synchronize do
|
|
230
|
+
avg = @request_times.mean
|
|
231
|
+
end
|
|
232
|
+
avg
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# @return [Boolean] Whether debug messages are enabled
|
|
236
|
+
def self.debug?
|
|
237
|
+
@@debug
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# @param value [Boolean] Whether to enable debug messages
|
|
241
|
+
def self.debug=(value)
|
|
242
|
+
@@debug = value
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Process the JSON request data, execute the method, and create a response.
|
|
246
|
+
#
|
|
247
|
+
# @param request_data [String] The JSON encoded request
|
|
248
|
+
# @param request_headers [Hash] The requests headers sent with the request
|
|
249
|
+
# @param start_time [Time] The time when the initial request was received
|
|
250
|
+
# @return response_data, error_code [String, Integer/nil] The JSON encoded
|
|
251
|
+
# response and error code
|
|
252
|
+
def process_request(request_data:, request_headers:, start_time:)
|
|
253
|
+
@request_count += 1
|
|
254
|
+
begin
|
|
255
|
+
request = JsonRpcRequest.from_json(request_data, request_headers)
|
|
256
|
+
response = nil
|
|
257
|
+
error_code = nil
|
|
258
|
+
response_data = nil
|
|
259
|
+
|
|
260
|
+
if (@method_whitelist and @method_whitelist.include?(request.method.downcase())) or
|
|
261
|
+
(!@method_whitelist and !JsonRpcRequest::DANGEROUS_METHODS.include?(request.method.downcase()))
|
|
262
|
+
begin
|
|
263
|
+
if request.keyword_params
|
|
264
|
+
result = @object.public_send(request.method.downcase().intern, *request.params, **request.keyword_params)
|
|
265
|
+
else
|
|
266
|
+
result = @object.public_send(request.method.downcase().intern, *request.params)
|
|
267
|
+
end
|
|
268
|
+
if request.id
|
|
269
|
+
response = JsonRpcSuccessResponse.new(result, request.id)
|
|
270
|
+
end
|
|
271
|
+
rescue Exception => error
|
|
272
|
+
# Filter out the framework stack trace (rails, rack, puma etc)
|
|
273
|
+
lines = error.formatted.split("\n")
|
|
274
|
+
i = lines.find_index { |row| row.include?('actionpack') || row.include?('activesupport') }
|
|
275
|
+
Logger.error lines[0...i].join("\n")
|
|
276
|
+
|
|
277
|
+
if request.id
|
|
278
|
+
if NoMethodError === error
|
|
279
|
+
error_code = JsonRpcError::ErrorCode::METHOD_NOT_FOUND
|
|
280
|
+
response = JsonRpcErrorResponse.new(
|
|
281
|
+
JsonRpcError.new(error_code, "Method not found", error), request.id
|
|
282
|
+
)
|
|
283
|
+
elsif ArgumentError === error
|
|
284
|
+
error_code = JsonRpcError::ErrorCode::INVALID_PARAMS
|
|
285
|
+
response = JsonRpcErrorResponse.new(
|
|
286
|
+
JsonRpcError.new(error_code, "Invalid params", error), request.id
|
|
287
|
+
)
|
|
288
|
+
elsif AuthError === error
|
|
289
|
+
error_code = JsonRpcError::ErrorCode::AUTH_ERROR
|
|
290
|
+
response = JsonRpcErrorResponse.new(
|
|
291
|
+
JsonRpcError.new(error_code, error.message, error), request.id
|
|
292
|
+
)
|
|
293
|
+
elsif ForbiddenError === error
|
|
294
|
+
error_code = JsonRpcError::ErrorCode::FORBIDDEN_ERROR
|
|
295
|
+
response = JsonRpcErrorResponse.new(
|
|
296
|
+
JsonRpcError.new(error_code, error.message, error), request.id
|
|
297
|
+
)
|
|
298
|
+
else
|
|
299
|
+
error_code = JsonRpcError::ErrorCode::OTHER_ERROR
|
|
300
|
+
response = JsonRpcErrorResponse.new(
|
|
301
|
+
JsonRpcError.new(error_code, error.message, error), request.id
|
|
302
|
+
)
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
else
|
|
307
|
+
if request.id
|
|
308
|
+
error_code = JsonRpcError::ErrorCode::OTHER_ERROR
|
|
309
|
+
response = JsonRpcErrorResponse.new(
|
|
310
|
+
JsonRpcError.new(error_code, "Cannot call unauthorized methods"), request.id
|
|
311
|
+
)
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
response_data = process_response(response, start_time) if response
|
|
315
|
+
return response_data, error_code
|
|
316
|
+
rescue => error
|
|
317
|
+
error_code = JsonRpcError::ErrorCode::INVALID_REQUEST
|
|
318
|
+
response = JsonRpcErrorResponse.new(JsonRpcError.new(error_code, "Invalid Request", error), nil)
|
|
319
|
+
response_data = process_response(response, start_time)
|
|
320
|
+
return response_data, error_code
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
protected
|
|
325
|
+
|
|
326
|
+
def process_response(response, start_time)
|
|
327
|
+
response_data = response.to_json(:allow_nan => true)
|
|
328
|
+
STDOUT.puts response_data if JsonDRb.debug?
|
|
329
|
+
end_time = Time.now.sys
|
|
330
|
+
request_time = end_time - start_time
|
|
331
|
+
add_request_time(request_time)
|
|
332
|
+
return response_data
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2022 Ball Aerospace & Technologies Corp.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
|
7
|
+
# under the terms of the GNU Affero General Public License
|
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU Affero General Public License for more details.
|
|
15
|
+
|
|
16
|
+
# Modified by OpenC3, Inc.
|
|
17
|
+
# All changes Copyright 2022, OpenC3, Inc.
|
|
18
|
+
# All Rights Reserved
|
|
19
|
+
|
|
20
|
+
require 'openc3'
|
|
21
|
+
require 'openc3/io/json_api_object'
|
|
22
|
+
|
|
23
|
+
module OpenC3
|
|
24
|
+
|
|
25
|
+
class JsonDRbError < JsonApiError; end
|
|
26
|
+
|
|
27
|
+
# Used to forward all method calls to the remote server object. Before using
|
|
28
|
+
# this class ensure the remote service has been started in the server class:
|
|
29
|
+
#
|
|
30
|
+
# json = JsonDrb.new
|
|
31
|
+
# json.start_service('127.0.0.1', 7777, self)
|
|
32
|
+
#
|
|
33
|
+
# Now the JsonDRbObject can be used to call server methods directly:
|
|
34
|
+
#
|
|
35
|
+
# server = JsonDRbObject('http://openc3-cmd-tlm-api:2901', 1.0)
|
|
36
|
+
# server.cmd(*args)
|
|
37
|
+
#
|
|
38
|
+
class JsonDRbObject < JsonApiObject
|
|
39
|
+
|
|
40
|
+
USER_AGENT = 'OpenC3 / v5 (ruby/openc3/lib/io/json_drb_object)'
|
|
41
|
+
|
|
42
|
+
# @param url [String] The url of openc3-cmd-tlm-api http://openc3-cmd-tlm-api:2901
|
|
43
|
+
# @param timeout [Float] The time to wait before disconnecting 1.0
|
|
44
|
+
# @param authentication [OpenC3Authentication] The authentication object if nill initialize will generate
|
|
45
|
+
def initialize(url: ENV['OPENC3_API_URL'], timeout: 1.0, authentication: nil)
|
|
46
|
+
super(url: url, timeout: timeout, authentication: authentication)
|
|
47
|
+
@uri = URI("#{url}/openc3-api/api")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Forwards all method calls to the remote service.
|
|
51
|
+
#
|
|
52
|
+
# @param method_name [Symbol] Name of the method to call
|
|
53
|
+
# @param method_params [Array] Array of parameters to pass to the method
|
|
54
|
+
# @param keyword_params [Hash<Symbol, Variable>] Hash of keyword parameters
|
|
55
|
+
# @return The result of the method call. If the method raises an exception
|
|
56
|
+
# the same exception is also raised. If something goes wrong with the
|
|
57
|
+
# protocol a JsonDRbError exception is raised.
|
|
58
|
+
def method_missing(method_name, *method_params, **keyword_params)
|
|
59
|
+
raise JsonDRbError, "Shutdown" if @shutdown
|
|
60
|
+
@mutex.synchronize do
|
|
61
|
+
@log = [nil, nil, nil]
|
|
62
|
+
connect() if !@http
|
|
63
|
+
json_rpc_request = JsonRpcRequest.new(method_name, method_params, keyword_params, @id)
|
|
64
|
+
data = json_rpc_request.to_json(:allow_nan => true)
|
|
65
|
+
response_body = make_request(data: data)
|
|
66
|
+
if !response_body or response_body.to_s.length < 1
|
|
67
|
+
disconnect()
|
|
68
|
+
else
|
|
69
|
+
response = JsonRpcResponse.from_json(response_body)
|
|
70
|
+
return handle_response(response: response)
|
|
71
|
+
end
|
|
72
|
+
error = "No response from server: #{@log[0]} ::: #{@log[1]} ::: #{@log[2]}"
|
|
73
|
+
raise JsonDRbError, error
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
#
|
|
80
|
+
def make_request(data:)
|
|
81
|
+
headers = {
|
|
82
|
+
'User-Agent' => USER_AGENT,
|
|
83
|
+
'Content-Type' => 'application/json-rpc',
|
|
84
|
+
'Authorization' => @authentication.token(),
|
|
85
|
+
}
|
|
86
|
+
begin
|
|
87
|
+
@log[0] = "Request: #{@uri.to_s} #{USER_AGENT} #{data.to_s}"
|
|
88
|
+
STDOUT.puts @log[0] if JsonDRb.debug?
|
|
89
|
+
resp = @http.post(@uri, :body => data, :header => headers)
|
|
90
|
+
@log[1] = "Response: #{resp.status} #{resp.headers} #{resp.body}"
|
|
91
|
+
@response_data = resp.body
|
|
92
|
+
STDOUT.puts @log[1] if JsonDRb.debug?
|
|
93
|
+
return resp.body
|
|
94
|
+
rescue StandardError => e
|
|
95
|
+
@log[2] = "Exception: #{e.class}, #{e.message}, #{e.backtrace}"
|
|
96
|
+
return nil
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
#
|
|
101
|
+
def handle_response(response:)
|
|
102
|
+
# The code below will always either raise or return breaking out of the loop
|
|
103
|
+
if JsonRpcErrorResponse === response
|
|
104
|
+
if response.error.data
|
|
105
|
+
raise Exception.from_hash(response.error.data)
|
|
106
|
+
else
|
|
107
|
+
raise "JsonDRb Error (#{response.error.code}): #{response.error.message}"
|
|
108
|
+
end
|
|
109
|
+
else
|
|
110
|
+
return response.result
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end # class JsonDRbObject
|
|
114
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2022 Ball Aerospace & Technologies Corp.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
|
7
|
+
# under the terms of the GNU Affero General Public License
|
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU Affero General Public License for more details.
|
|
15
|
+
|
|
16
|
+
# Modified by OpenC3, Inc.
|
|
17
|
+
# All changes Copyright 2022, OpenC3, Inc.
|
|
18
|
+
# All Rights Reserved
|
|
19
|
+
|
|
20
|
+
require 'rack'
|
|
21
|
+
|
|
22
|
+
module OpenC3
|
|
23
|
+
# JsonDrbRack implements a rack application that can be served by a
|
|
24
|
+
# webserver to process OpenC3 json_drb requests via http.
|
|
25
|
+
class JsonDrbRack
|
|
26
|
+
# @param drb [JsonDRb] - An instance of the JsonDRb class that'll be used
|
|
27
|
+
# to process the JSON request and generate a response
|
|
28
|
+
def initialize(drb)
|
|
29
|
+
@drb = drb
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Handles a request.
|
|
33
|
+
#
|
|
34
|
+
# @param env [Hash] - A rack env hash, can be turned into a Rack::Request
|
|
35
|
+
# @return [Integer, Hash, [String]] - Http response code, content headers,
|
|
36
|
+
# response body
|
|
37
|
+
def call(env)
|
|
38
|
+
request = Rack::Request.new(env)
|
|
39
|
+
|
|
40
|
+
if request.post?
|
|
41
|
+
request_headers = Hash[*request.env.select { |k, v| k.start_with? 'HTTP_' }.sort.flatten]
|
|
42
|
+
request_data = request.body.read
|
|
43
|
+
status, content_type, body = handle_post(request_data, request_headers)
|
|
44
|
+
else
|
|
45
|
+
status = 405
|
|
46
|
+
content_type = "text/plain"
|
|
47
|
+
body = "Request not allowed"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
return status, { 'Content-Type' => content_type }, [body]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Handles an http post.
|
|
54
|
+
#
|
|
55
|
+
# @param request_data [String] - A String of the post body from the request
|
|
56
|
+
# @param request_headers [Hash] - A Hash of the headers from the post request
|
|
57
|
+
# @return [Integer, String, String] - Http response code, content type,
|
|
58
|
+
# response body.
|
|
59
|
+
def handle_post(request_data, request_headers)
|
|
60
|
+
response_data, error_code = @drb.process_request(
|
|
61
|
+
request_data: request_data,
|
|
62
|
+
request_headers: request_headers,
|
|
63
|
+
start_time: Time.now.sys
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Convert json error code into html status code
|
|
67
|
+
# see http://www.jsonrpc.org/historical/json-rpc-over-http.html#errors
|
|
68
|
+
if error_code
|
|
69
|
+
case error_code
|
|
70
|
+
when JsonRpcError::ErrorCode::PARSE_ERROR then status = 500 # Internal server error
|
|
71
|
+
when JsonRpcError::ErrorCode::INVALID_REQUEST then status = 400 # Bad request
|
|
72
|
+
when JsonRpcError::ErrorCode::METHOD_NOT_FOUND then status = 404 # Not found
|
|
73
|
+
when JsonRpcError::ErrorCode::INVALID_PARAMS then status = 500 # Internal server error
|
|
74
|
+
when JsonRpcError::ErrorCode::INTERNAL_ERROR then status = 500 # Internal server error
|
|
75
|
+
else status = 500 # Internal server error
|
|
76
|
+
end
|
|
77
|
+
else
|
|
78
|
+
status = 200 # OK
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
return status, "application/json-rpc", response_data
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|