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.
Files changed (307) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +18 -0
  3. data/Guardfile +35 -0
  4. data/LICENSE.txt +727 -0
  5. data/README.md +37 -0
  6. data/Rakefile +131 -0
  7. data/bin/cstol_converter +1178 -0
  8. data/bin/openc3cli +531 -0
  9. data/bin/rubysloc +139 -0
  10. data/data/config/_array_params.yaml +23 -0
  11. data/data/config/_id_items.yaml +24 -0
  12. data/data/config/_id_params.yaml +58 -0
  13. data/data/config/_interfaces.yaml +214 -0
  14. data/data/config/_interfaces.yaml.err +1017 -0
  15. data/data/config/_items.yaml +20 -0
  16. data/data/config/_params.yaml +60 -0
  17. data/data/config/cmd_tlm_server.yaml +136 -0
  18. data/data/config/command.yaml +44 -0
  19. data/data/config/command_modifiers.yaml +160 -0
  20. data/data/config/command_telemetry.yaml +3 -0
  21. data/data/config/interface_modifiers.yaml +104 -0
  22. data/data/config/item_modifiers.yaml +221 -0
  23. data/data/config/microservice.yaml +78 -0
  24. data/data/config/param_item_modifiers.yaml +52 -0
  25. data/data/config/parameter_modifiers.yaml +200 -0
  26. data/data/config/plugins.yaml +80 -0
  27. data/data/config/protocols.yaml +290 -0
  28. data/data/config/screen.yaml +147 -0
  29. data/data/config/table_manager.yaml +89 -0
  30. data/data/config/table_parameter_modifiers.yaml +9 -0
  31. data/data/config/target.yaml +142 -0
  32. data/data/config/target_config.yaml +94 -0
  33. data/data/config/telemetry.yaml +87 -0
  34. data/data/config/telemetry_modifiers.yaml +159 -0
  35. data/data/config/tool.yaml +63 -0
  36. data/data/config/unknown.yaml +3 -0
  37. data/data/config/widgets.yaml +1505 -0
  38. data/ext/mkrf_conf.rb +49 -0
  39. data/ext/openc3/ext/array/array.c +122 -0
  40. data/ext/openc3/ext/array/extconf.rb +13 -0
  41. data/ext/openc3/ext/buffered_file/buffered_file.c +198 -0
  42. data/ext/openc3/ext/buffered_file/extconf.rb +13 -0
  43. data/ext/openc3/ext/config_parser/config_parser.c +280 -0
  44. data/ext/openc3/ext/config_parser/extconf.rb +13 -0
  45. data/ext/openc3/ext/crc/crc.c +351 -0
  46. data/ext/openc3/ext/crc/extconf.rb +13 -0
  47. data/ext/openc3/ext/openc3_io/extconf.rb +13 -0
  48. data/ext/openc3/ext/openc3_io/openc3_io.c +158 -0
  49. data/ext/openc3/ext/packet/extconf.rb +13 -0
  50. data/ext/openc3/ext/packet/packet.c +318 -0
  51. data/ext/openc3/ext/platform/extconf.rb +13 -0
  52. data/ext/openc3/ext/platform/platform.c +134 -0
  53. data/ext/openc3/ext/polynomial_conversion/extconf.rb +13 -0
  54. data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +79 -0
  55. data/ext/openc3/ext/string/extconf.rb +13 -0
  56. data/ext/openc3/ext/string/string.c +63 -0
  57. data/ext/openc3/ext/structure/structure.c +1719 -0
  58. data/ext/openc3/ext/tabbed_plots_config/extconf.rb +13 -0
  59. data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +62 -0
  60. data/ext/openc3/ext/telemetry/extconf.rb +13 -0
  61. data/ext/openc3/ext/telemetry/telemetry.c +336 -0
  62. data/lib/cosmos.rb +20 -0
  63. data/lib/cosmosc2.rb +20 -0
  64. data/lib/openc3/api/api.rb +39 -0
  65. data/lib/openc3/api/authorized_api.rb +30 -0
  66. data/lib/openc3/api/cmd_api.rb +451 -0
  67. data/lib/openc3/api/config_api.rb +58 -0
  68. data/lib/openc3/api/interface_api.rb +117 -0
  69. data/lib/openc3/api/limits_api.rb +375 -0
  70. data/lib/openc3/api/router_api.rb +117 -0
  71. data/lib/openc3/api/settings_api.rb +70 -0
  72. data/lib/openc3/api/target_api.rb +78 -0
  73. data/lib/openc3/api/tlm_api.rb +455 -0
  74. data/lib/openc3/bridge/bridge.rb +54 -0
  75. data/lib/openc3/bridge/bridge_config.rb +167 -0
  76. data/lib/openc3/bridge/bridge_interface_thread.rb +42 -0
  77. data/lib/openc3/bridge/bridge_router_thread.rb +42 -0
  78. data/lib/openc3/ccsds/ccsds_packet.rb +68 -0
  79. data/lib/openc3/ccsds/ccsds_parser.rb +148 -0
  80. data/lib/openc3/config/config_parser.rb +549 -0
  81. data/lib/openc3/config/meta_config_parser.rb +74 -0
  82. data/lib/openc3/conversions/conversion.rb +70 -0
  83. data/lib/openc3/conversions/generic_conversion.rb +83 -0
  84. data/lib/openc3/conversions/packet_time_formatted_conversion.rb +43 -0
  85. data/lib/openc3/conversions/packet_time_seconds_conversion.rb +43 -0
  86. data/lib/openc3/conversions/polynomial_conversion.rb +87 -0
  87. data/lib/openc3/conversions/processor_conversion.rb +70 -0
  88. data/lib/openc3/conversions/received_count_conversion.rb +38 -0
  89. data/lib/openc3/conversions/received_time_formatted_conversion.rb +42 -0
  90. data/lib/openc3/conversions/received_time_seconds_conversion.rb +42 -0
  91. data/lib/openc3/conversions/segmented_polynomial_conversion.rb +171 -0
  92. data/lib/openc3/conversions/unix_time_conversion.rb +68 -0
  93. data/lib/openc3/conversions/unix_time_formatted_conversion.rb +49 -0
  94. data/lib/openc3/conversions/unix_time_seconds_conversion.rb +49 -0
  95. data/lib/openc3/conversions.rb +34 -0
  96. data/lib/openc3/core_ext/array.rb +416 -0
  97. data/lib/openc3/core_ext/binding.rb +29 -0
  98. data/lib/openc3/core_ext/class.rb +72 -0
  99. data/lib/openc3/core_ext/exception.rb +61 -0
  100. data/lib/openc3/core_ext/file.rb +83 -0
  101. data/lib/openc3/core_ext/hash.rb +37 -0
  102. data/lib/openc3/core_ext/io.rb +134 -0
  103. data/lib/openc3/core_ext/kernel.rb +42 -0
  104. data/lib/openc3/core_ext/math.rb +128 -0
  105. data/lib/openc3/core_ext/matrix.rb +156 -0
  106. data/lib/openc3/core_ext/objectspace.rb +36 -0
  107. data/lib/openc3/core_ext/openc3_io.rb +57 -0
  108. data/lib/openc3/core_ext/range.rb +27 -0
  109. data/lib/openc3/core_ext/socket.rb +38 -0
  110. data/lib/openc3/core_ext/string.rb +389 -0
  111. data/lib/openc3/core_ext/stringio.rb +33 -0
  112. data/lib/openc3/core_ext/time.rb +508 -0
  113. data/lib/openc3/core_ext.rb +36 -0
  114. data/lib/openc3/interfaces/interface.rb +498 -0
  115. data/lib/openc3/interfaces/linc_interface.rb +475 -0
  116. data/lib/openc3/interfaces/protocols/burst_protocol.rb +192 -0
  117. data/lib/openc3/interfaces/protocols/crc_protocol.rb +193 -0
  118. data/lib/openc3/interfaces/protocols/fixed_protocol.rb +155 -0
  119. data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +56 -0
  120. data/lib/openc3/interfaces/protocols/length_protocol.rb +165 -0
  121. data/lib/openc3/interfaces/protocols/override_protocol.rb +60 -0
  122. data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +206 -0
  123. data/lib/openc3/interfaces/protocols/protocol.rb +82 -0
  124. data/lib/openc3/interfaces/protocols/template_protocol.rb +261 -0
  125. data/lib/openc3/interfaces/protocols/terminated_protocol.rb +93 -0
  126. data/lib/openc3/interfaces/serial_interface.rb +94 -0
  127. data/lib/openc3/interfaces/simulated_target_interface.rb +168 -0
  128. data/lib/openc3/interfaces/stream_interface.rb +81 -0
  129. data/lib/openc3/interfaces/tcpip_client_interface.rb +69 -0
  130. data/lib/openc3/interfaces/tcpip_server_interface.rb +629 -0
  131. data/lib/openc3/interfaces/udp_interface.rb +169 -0
  132. data/lib/openc3/interfaces.rb +44 -0
  133. data/lib/openc3/io/buffered_file.rb +109 -0
  134. data/lib/openc3/io/io_multiplexer.rb +80 -0
  135. data/lib/openc3/io/json_api_object.rb +208 -0
  136. data/lib/openc3/io/json_drb.rb +335 -0
  137. data/lib/openc3/io/json_drb_object.rb +114 -0
  138. data/lib/openc3/io/json_drb_rack.rb +84 -0
  139. data/lib/openc3/io/json_rpc.rb +420 -0
  140. data/lib/openc3/io/openc3_snmp.rb +58 -0
  141. data/lib/openc3/io/posix_serial_driver.rb +156 -0
  142. data/lib/openc3/io/raw_logger.rb +167 -0
  143. data/lib/openc3/io/raw_logger_pair.rb +77 -0
  144. data/lib/openc3/io/serial_driver.rb +105 -0
  145. data/lib/openc3/io/stderr.rb +43 -0
  146. data/lib/openc3/io/stdout.rb +43 -0
  147. data/lib/openc3/io/udp_sockets.rb +194 -0
  148. data/lib/openc3/io/win32_serial_driver.rb +196 -0
  149. data/lib/openc3/logs/log_writer.rb +302 -0
  150. data/lib/openc3/logs/packet_log_constants.rb +62 -0
  151. data/lib/openc3/logs/packet_log_reader.rb +345 -0
  152. data/lib/openc3/logs/packet_log_writer.rb +299 -0
  153. data/lib/openc3/logs/text_log_writer.rb +68 -0
  154. data/lib/openc3/logs.rb +25 -0
  155. data/lib/openc3/microservices/cleanup_microservice.rb +68 -0
  156. data/lib/openc3/microservices/decom_microservice.rb +136 -0
  157. data/lib/openc3/microservices/interface_microservice.rb +532 -0
  158. data/lib/openc3/microservices/log_microservice.rb +108 -0
  159. data/lib/openc3/microservices/microservice.rb +204 -0
  160. data/lib/openc3/microservices/plugin_microservice.rb +43 -0
  161. data/lib/openc3/microservices/reaction_microservice.rb +541 -0
  162. data/lib/openc3/microservices/reducer_microservice.rb +313 -0
  163. data/lib/openc3/microservices/router_microservice.rb +44 -0
  164. data/lib/openc3/microservices/text_log_microservice.rb +84 -0
  165. data/lib/openc3/microservices/timeline_microservice.rb +363 -0
  166. data/lib/openc3/microservices/trigger_group_microservice.rb +638 -0
  167. data/lib/openc3/models/activity_model.rb +319 -0
  168. data/lib/openc3/models/auth_model.rb +65 -0
  169. data/lib/openc3/models/cvt_model.rb +185 -0
  170. data/lib/openc3/models/environment_model.rb +58 -0
  171. data/lib/openc3/models/gem_model.rb +137 -0
  172. data/lib/openc3/models/info_model.rb +31 -0
  173. data/lib/openc3/models/interface_model.rb +281 -0
  174. data/lib/openc3/models/interface_status_model.rb +117 -0
  175. data/lib/openc3/models/metadata_model.rb +139 -0
  176. data/lib/openc3/models/metric_model.rb +59 -0
  177. data/lib/openc3/models/microservice_model.rb +206 -0
  178. data/lib/openc3/models/microservice_status_model.rb +74 -0
  179. data/lib/openc3/models/model.rb +204 -0
  180. data/lib/openc3/models/note_model.rb +122 -0
  181. data/lib/openc3/models/notification_model.rb +40 -0
  182. data/lib/openc3/models/ping_model.rb +35 -0
  183. data/lib/openc3/models/plugin_model.rb +292 -0
  184. data/lib/openc3/models/process_status_model.rb +76 -0
  185. data/lib/openc3/models/reaction_model.rb +322 -0
  186. data/lib/openc3/models/reducer_model.rb +65 -0
  187. data/lib/openc3/models/router_model.rb +35 -0
  188. data/lib/openc3/models/router_status_model.rb +27 -0
  189. data/lib/openc3/models/scope_model.rb +153 -0
  190. data/lib/openc3/models/settings_model.rb +55 -0
  191. data/lib/openc3/models/sorted_model.rb +167 -0
  192. data/lib/openc3/models/target_model.rb +759 -0
  193. data/lib/openc3/models/timeline_model.rb +154 -0
  194. data/lib/openc3/models/tool_config_model.rb +38 -0
  195. data/lib/openc3/models/tool_model.rb +262 -0
  196. data/lib/openc3/models/trigger_group_model.rb +186 -0
  197. data/lib/openc3/models/trigger_model.rb +330 -0
  198. data/lib/openc3/models/widget_model.rb +138 -0
  199. data/lib/openc3/operators/microservice_operator.rb +128 -0
  200. data/lib/openc3/operators/operator.rb +277 -0
  201. data/lib/openc3/packets/binary_accessor.rb +1207 -0
  202. data/lib/openc3/packets/commands.rb +373 -0
  203. data/lib/openc3/packets/json_packet.rb +134 -0
  204. data/lib/openc3/packets/limits.rb +271 -0
  205. data/lib/openc3/packets/limits_response.rb +53 -0
  206. data/lib/openc3/packets/packet.rb +1168 -0
  207. data/lib/openc3/packets/packet_config.rb +625 -0
  208. data/lib/openc3/packets/packet_item.rb +586 -0
  209. data/lib/openc3/packets/packet_item_limits.rb +162 -0
  210. data/lib/openc3/packets/parsers/format_string_parser.rb +65 -0
  211. data/lib/openc3/packets/parsers/limits_parser.rb +159 -0
  212. data/lib/openc3/packets/parsers/limits_response_parser.rb +61 -0
  213. data/lib/openc3/packets/parsers/packet_item_parser.rb +272 -0
  214. data/lib/openc3/packets/parsers/packet_parser.rb +134 -0
  215. data/lib/openc3/packets/parsers/processor_parser.rb +73 -0
  216. data/lib/openc3/packets/parsers/state_parser.rb +127 -0
  217. data/lib/openc3/packets/parsers/xtce_converter.rb +442 -0
  218. data/lib/openc3/packets/parsers/xtce_parser.rb +722 -0
  219. data/lib/openc3/packets/structure.rb +553 -0
  220. data/lib/openc3/packets/structure_item.rb +365 -0
  221. data/lib/openc3/packets/telemetry.rb +487 -0
  222. data/lib/openc3/processors/processor.rb +86 -0
  223. data/lib/openc3/processors/statistics_processor.rb +82 -0
  224. data/lib/openc3/processors/watermark_processor.rb +58 -0
  225. data/lib/openc3/processors.rb +24 -0
  226. data/lib/openc3/script/api_shared.rb +828 -0
  227. data/lib/openc3/script/calendar.rb +89 -0
  228. data/lib/openc3/script/commands.rb +227 -0
  229. data/lib/openc3/script/exceptions.rb +29 -0
  230. data/lib/openc3/script/extract.rb +161 -0
  231. data/lib/openc3/script/limits.rb +60 -0
  232. data/lib/openc3/script/script.rb +299 -0
  233. data/lib/openc3/script/script_runner.rb +238 -0
  234. data/lib/openc3/script/storage.rb +146 -0
  235. data/lib/openc3/script/suite.rb +542 -0
  236. data/lib/openc3/script/suite_results.rb +196 -0
  237. data/lib/openc3/script/suite_runner.rb +217 -0
  238. data/lib/openc3/script.rb +21 -0
  239. data/lib/openc3/streams/serial_stream.rb +167 -0
  240. data/lib/openc3/streams/stream.rb +63 -0
  241. data/lib/openc3/streams/tcpip_client_stream.rb +116 -0
  242. data/lib/openc3/streams/tcpip_socket_stream.rb +195 -0
  243. data/lib/openc3/system/system.rb +127 -0
  244. data/lib/openc3/system/system_config.rb +411 -0
  245. data/lib/openc3/system/target.rb +269 -0
  246. data/lib/openc3/system.rb +24 -0
  247. data/lib/openc3/tools/cmd_tlm_server/api.rb +20 -0
  248. data/lib/openc3/tools/cmd_tlm_server/cmd_tlm_server_config.rb +320 -0
  249. data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +294 -0
  250. data/lib/openc3/tools/table_manager/table.rb +77 -0
  251. data/lib/openc3/tools/table_manager/table_config.rb +273 -0
  252. data/lib/openc3/tools/table_manager/table_item.rb +90 -0
  253. data/lib/openc3/tools/table_manager/table_item_parser.rb +66 -0
  254. data/lib/openc3/tools/table_manager/table_manager_core.rb +333 -0
  255. data/lib/openc3/tools/table_manager/table_parser.rb +93 -0
  256. data/lib/openc3/tools/test_runner/test.rb +67 -0
  257. data/lib/openc3/top_level.rb +595 -0
  258. data/lib/openc3/topics/autonomic_topic.rb +52 -0
  259. data/lib/openc3/topics/calendar_topic.rb +44 -0
  260. data/lib/openc3/topics/command_decom_topic.rb +76 -0
  261. data/lib/openc3/topics/command_topic.rb +83 -0
  262. data/lib/openc3/topics/config_topic.rb +68 -0
  263. data/lib/openc3/topics/interface_topic.rb +73 -0
  264. data/lib/openc3/topics/limits_event_topic.rb +109 -0
  265. data/lib/openc3/topics/notifications_topic.rb +28 -0
  266. data/lib/openc3/topics/router_topic.rb +85 -0
  267. data/lib/openc3/topics/telemetry_decom_topic.rb +54 -0
  268. data/lib/openc3/topics/telemetry_topic.rb +36 -0
  269. data/lib/openc3/topics/timeline_topic.rb +45 -0
  270. data/lib/openc3/topics/topic.rb +53 -0
  271. data/lib/openc3/utilities/authentication.rb +141 -0
  272. data/lib/openc3/utilities/authorization.rb +51 -0
  273. data/lib/openc3/utilities/crc.rb +278 -0
  274. data/lib/openc3/utilities/csv.rb +153 -0
  275. data/lib/openc3/utilities/logger.rb +187 -0
  276. data/lib/openc3/utilities/message_log.rb +91 -0
  277. data/lib/openc3/utilities/metric.rb +141 -0
  278. data/lib/openc3/utilities/process_manager.rb +139 -0
  279. data/lib/openc3/utilities/quaternion.rb +257 -0
  280. data/lib/openc3/utilities/ruby_lex_utils.rb +568 -0
  281. data/lib/openc3/utilities/s3.rb +202 -0
  282. data/lib/openc3/utilities/s3_autoload.rb +9 -0
  283. data/lib/openc3/utilities/s3_file_cache.rb +274 -0
  284. data/lib/openc3/utilities/simulated_target.rb +117 -0
  285. data/lib/openc3/utilities/sleeper.rb +51 -0
  286. data/lib/openc3/utilities/store.rb +23 -0
  287. data/lib/openc3/utilities/store_autoload.rb +237 -0
  288. data/lib/openc3/utilities/zip.rb +21 -0
  289. data/lib/openc3/utilities.rb +35 -0
  290. data/lib/openc3/version.rb +14 -0
  291. data/lib/openc3/win32/excel.rb +132 -0
  292. data/lib/openc3/win32/win32.rb +402 -0
  293. data/lib/openc3/win32/win32_main.rb +333 -0
  294. data/lib/openc3.rb +49 -0
  295. data/tasks/gemfile_stats.rake +113 -0
  296. data/tasks/spec.rake +30 -0
  297. data/templates/plugin-template/README.md +15 -0
  298. data/templates/plugin-template/Rakefile +12 -0
  299. data/templates/plugin-template/plugin.gemspec +23 -0
  300. data/templates/plugin-template/plugin.txt +9 -0
  301. data/templates/plugin-template/targets/TARGET/cmd_tlm/cmd.txt +8 -0
  302. data/templates/plugin-template/targets/TARGET/cmd_tlm/tlm.txt +8 -0
  303. data/templates/plugin-template/targets/TARGET/lib/target.rb +10 -0
  304. data/templates/plugin-template/targets/TARGET/procedures/procedure.rb +3 -0
  305. data/templates/plugin-template/targets/TARGET/screens/status.txt +9 -0
  306. data/templates/plugin-template/targets/TARGET/target.txt +5 -0
  307. 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