openc3 5.0.11 → 5.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of openc3 might be problematic. Click here for more details.

Files changed (280) hide show
  1. checksums.yaml +4 -4
  2. data/Guardfile +3 -0
  3. data/LICENSE.txt +7 -5
  4. data/README.md +11 -9
  5. data/Rakefile +3 -0
  6. data/bin/cstol_converter +3 -0
  7. data/bin/openc3cli +29 -18
  8. data/bin/rubysloc +3 -0
  9. data/data/config/screen.yaml +10 -2
  10. data/data/config/target.yaml +1 -1
  11. data/data/config/widgets.yaml +6 -6
  12. data/ext/mkrf_conf.rb +3 -0
  13. data/ext/openc3/ext/array/array.c +3 -0
  14. data/ext/openc3/ext/buffered_file/buffered_file.c +3 -0
  15. data/ext/openc3/ext/config_parser/config_parser.c +3 -0
  16. data/ext/openc3/ext/crc/crc.c +3 -0
  17. data/ext/openc3/ext/openc3_io/openc3_io.c +3 -0
  18. data/ext/openc3/ext/packet/packet.c +3 -0
  19. data/ext/openc3/ext/platform/platform.c +3 -0
  20. data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +3 -0
  21. data/ext/openc3/ext/string/string.c +3 -0
  22. data/ext/openc3/ext/structure/structure.c +3 -0
  23. data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +3 -0
  24. data/ext/openc3/ext/telemetry/telemetry.c +3 -0
  25. data/lib/cosmos.rb +3 -0
  26. data/lib/cosmosc2.rb +3 -0
  27. data/lib/openc3/accessors/accessor.rb +3 -0
  28. data/lib/openc3/accessors/binary_accessor.rb +3 -0
  29. data/lib/openc3/accessors/cbor_accessor.rb +3 -0
  30. data/lib/openc3/accessors/html_accessor.rb +3 -0
  31. data/lib/openc3/accessors/json_accessor.rb +4 -1
  32. data/lib/openc3/accessors/xml_accessor.rb +3 -0
  33. data/lib/openc3/accessors.rb +3 -0
  34. data/lib/openc3/api/api.rb +3 -0
  35. data/lib/openc3/api/authorized_api.rb +3 -0
  36. data/lib/openc3/api/cmd_api.rb +6 -3
  37. data/lib/openc3/api/config_api.rb +3 -0
  38. data/lib/openc3/api/interface_api.rb +6 -2
  39. data/lib/openc3/api/limits_api.rb +54 -61
  40. data/lib/openc3/api/router_api.rb +6 -3
  41. data/lib/openc3/api/settings_api.rb +3 -0
  42. data/lib/openc3/api/target_api.rb +3 -0
  43. data/lib/openc3/api/tlm_api.rb +27 -32
  44. data/lib/openc3/bridge/bridge.rb +3 -0
  45. data/lib/openc3/bridge/bridge_config.rb +3 -0
  46. data/lib/openc3/bridge/bridge_interface_thread.rb +3 -0
  47. data/lib/openc3/bridge/bridge_router_thread.rb +3 -0
  48. data/lib/openc3/ccsds/ccsds_packet.rb +3 -0
  49. data/lib/openc3/ccsds/ccsds_parser.rb +3 -0
  50. data/lib/openc3/config/config_parser.rb +3 -0
  51. data/lib/openc3/config/meta_config_parser.rb +3 -0
  52. data/lib/openc3/conversions/conversion.rb +3 -0
  53. data/lib/openc3/conversions/generic_conversion.rb +3 -0
  54. data/lib/openc3/conversions/packet_time_formatted_conversion.rb +3 -0
  55. data/lib/openc3/conversions/packet_time_seconds_conversion.rb +3 -0
  56. data/lib/openc3/conversions/polynomial_conversion.rb +3 -0
  57. data/lib/openc3/conversions/processor_conversion.rb +3 -0
  58. data/lib/openc3/conversions/received_count_conversion.rb +3 -0
  59. data/lib/openc3/conversions/received_time_formatted_conversion.rb +3 -0
  60. data/lib/openc3/conversions/received_time_seconds_conversion.rb +3 -0
  61. data/lib/openc3/conversions/segmented_polynomial_conversion.rb +3 -0
  62. data/lib/openc3/conversions/unix_time_conversion.rb +3 -0
  63. data/lib/openc3/conversions/unix_time_formatted_conversion.rb +3 -0
  64. data/lib/openc3/conversions/unix_time_seconds_conversion.rb +3 -0
  65. data/lib/openc3/conversions.rb +3 -0
  66. data/lib/openc3/core_ext/array.rb +3 -0
  67. data/lib/openc3/core_ext/binding.rb +3 -0
  68. data/lib/openc3/core_ext/class.rb +3 -0
  69. data/lib/openc3/core_ext/exception.rb +3 -0
  70. data/lib/openc3/core_ext/file.rb +3 -0
  71. data/lib/openc3/core_ext/hash.rb +3 -0
  72. data/lib/openc3/core_ext/io.rb +3 -0
  73. data/lib/openc3/core_ext/kernel.rb +3 -0
  74. data/lib/openc3/core_ext/math.rb +3 -0
  75. data/lib/openc3/core_ext/matrix.rb +3 -0
  76. data/lib/openc3/core_ext/objectspace.rb +3 -0
  77. data/lib/openc3/core_ext/openc3_io.rb +3 -0
  78. data/lib/openc3/core_ext/range.rb +3 -0
  79. data/lib/openc3/core_ext/socket.rb +3 -0
  80. data/lib/openc3/core_ext/string.rb +3 -0
  81. data/lib/openc3/core_ext/stringio.rb +3 -0
  82. data/lib/openc3/core_ext/tempfile.rb +3 -0
  83. data/lib/openc3/core_ext/time.rb +3 -0
  84. data/lib/openc3/core_ext.rb +3 -0
  85. data/lib/openc3/interfaces/interface.rb +3 -0
  86. data/lib/openc3/interfaces/linc_interface.rb +3 -0
  87. data/lib/openc3/interfaces/protocols/burst_protocol.rb +3 -0
  88. data/lib/openc3/interfaces/protocols/crc_protocol.rb +3 -0
  89. data/lib/openc3/interfaces/protocols/fixed_protocol.rb +3 -0
  90. data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +3 -0
  91. data/lib/openc3/interfaces/protocols/length_protocol.rb +3 -0
  92. data/lib/openc3/interfaces/protocols/override_protocol.rb +3 -0
  93. data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +3 -0
  94. data/lib/openc3/interfaces/protocols/protocol.rb +3 -0
  95. data/lib/openc3/interfaces/protocols/template_protocol.rb +3 -0
  96. data/lib/openc3/interfaces/protocols/terminated_protocol.rb +3 -0
  97. data/lib/openc3/interfaces/serial_interface.rb +3 -0
  98. data/lib/openc3/interfaces/simulated_target_interface.rb +3 -0
  99. data/lib/openc3/interfaces/stream_interface.rb +3 -0
  100. data/lib/openc3/interfaces/tcpip_client_interface.rb +3 -0
  101. data/lib/openc3/interfaces/tcpip_server_interface.rb +3 -0
  102. data/lib/openc3/interfaces/udp_interface.rb +3 -0
  103. data/lib/openc3/interfaces.rb +3 -0
  104. data/lib/openc3/io/buffered_file.rb +3 -0
  105. data/lib/openc3/io/io_multiplexer.rb +8 -0
  106. data/lib/openc3/io/json_api_object.rb +5 -2
  107. data/lib/openc3/io/json_drb.rb +3 -0
  108. data/lib/openc3/io/json_drb_object.rb +5 -2
  109. data/lib/openc3/io/json_drb_rack.rb +3 -0
  110. data/lib/openc3/io/json_rpc.rb +8 -3
  111. data/lib/openc3/io/openc3_snmp.rb +3 -0
  112. data/lib/openc3/io/posix_serial_driver.rb +3 -0
  113. data/lib/openc3/io/raw_logger.rb +3 -0
  114. data/lib/openc3/io/raw_logger_pair.rb +3 -0
  115. data/lib/openc3/io/serial_driver.rb +3 -0
  116. data/lib/openc3/io/stderr.rb +3 -0
  117. data/lib/openc3/io/stdout.rb +3 -0
  118. data/lib/openc3/io/udp_sockets.rb +3 -0
  119. data/lib/openc3/io/win32_serial_driver.rb +3 -0
  120. data/lib/openc3/logs/buffered_packet_log_reader.rb +65 -0
  121. data/lib/openc3/logs/buffered_packet_log_writer.rb +120 -0
  122. data/lib/openc3/logs/log_writer.rb +95 -40
  123. data/lib/openc3/logs/packet_log_constants.rb +9 -0
  124. data/lib/openc3/logs/packet_log_reader.rb +34 -3
  125. data/lib/openc3/logs/packet_log_writer.rb +85 -18
  126. data/lib/openc3/logs/text_log_writer.rb +9 -5
  127. data/lib/openc3/logs.rb +8 -2
  128. data/lib/openc3/microservices/cleanup_microservice.rb +18 -18
  129. data/lib/openc3/microservices/decom_microservice.rb +30 -24
  130. data/lib/openc3/microservices/interface_microservice.rb +136 -91
  131. data/lib/openc3/microservices/log_microservice.rb +35 -13
  132. data/lib/openc3/microservices/microservice.rb +16 -14
  133. data/lib/openc3/microservices/plugin_microservice.rb +3 -1
  134. data/lib/openc3/microservices/reaction_microservice.rb +4 -1
  135. data/lib/openc3/microservices/reducer_microservice.rb +332 -149
  136. data/lib/openc3/microservices/router_microservice.rb +3 -0
  137. data/lib/openc3/microservices/text_log_microservice.rb +22 -7
  138. data/lib/openc3/microservices/timeline_microservice.rb +4 -1
  139. data/lib/openc3/microservices/trigger_group_microservice.rb +3 -0
  140. data/lib/openc3/models/activity_model.rb +3 -0
  141. data/lib/openc3/models/auth_model.rb +3 -0
  142. data/lib/openc3/models/cvt_model.rb +14 -5
  143. data/lib/openc3/models/environment_model.rb +3 -0
  144. data/lib/openc3/models/gem_model.rb +30 -51
  145. data/lib/openc3/models/info_model.rb +3 -0
  146. data/lib/openc3/models/interface_model.rb +3 -0
  147. data/lib/openc3/models/interface_status_model.rb +4 -1
  148. data/lib/openc3/models/metadata_model.rb +3 -0
  149. data/lib/openc3/models/metric_model.rb +3 -0
  150. data/lib/openc3/models/microservice_model.rb +9 -6
  151. data/lib/openc3/models/microservice_status_model.rb +4 -1
  152. data/lib/openc3/models/model.rb +3 -0
  153. data/lib/openc3/models/note_model.rb +3 -0
  154. data/lib/openc3/models/notification_model.rb +3 -0
  155. data/lib/openc3/models/ping_model.rb +3 -0
  156. data/lib/openc3/models/plugin_model.rb +20 -14
  157. data/lib/openc3/models/process_status_model.rb +4 -1
  158. data/lib/openc3/models/reaction_model.rb +3 -0
  159. data/lib/openc3/models/reducer_model.rb +31 -24
  160. data/lib/openc3/models/router_model.rb +3 -0
  161. data/lib/openc3/models/router_status_model.rb +3 -0
  162. data/lib/openc3/models/scope_model.rb +3 -4
  163. data/lib/openc3/models/settings_model.rb +3 -0
  164. data/lib/openc3/models/sorted_model.rb +3 -0
  165. data/lib/openc3/models/target_model.rb +61 -94
  166. data/lib/openc3/models/timeline_model.rb +4 -1
  167. data/lib/openc3/models/tool_config_model.rb +3 -0
  168. data/lib/openc3/models/tool_model.rb +11 -9
  169. data/lib/openc3/models/trigger_group_model.rb +3 -0
  170. data/lib/openc3/models/trigger_model.rb +3 -0
  171. data/lib/openc3/models/widget_model.rb +18 -11
  172. data/lib/openc3/operators/microservice_operator.rb +3 -0
  173. data/lib/openc3/operators/operator.rb +105 -34
  174. data/lib/openc3/packets/commands.rb +3 -0
  175. data/lib/openc3/packets/json_packet.rb +87 -14
  176. data/lib/openc3/packets/limits.rb +4 -1
  177. data/lib/openc3/packets/limits_response.rb +3 -0
  178. data/lib/openc3/packets/packet.rb +5 -1
  179. data/lib/openc3/packets/packet_config.rb +3 -0
  180. data/lib/openc3/packets/packet_item.rb +9 -3
  181. data/lib/openc3/packets/packet_item_limits.rb +3 -0
  182. data/lib/openc3/packets/parsers/format_string_parser.rb +3 -0
  183. data/lib/openc3/packets/parsers/limits_parser.rb +3 -0
  184. data/lib/openc3/packets/parsers/limits_response_parser.rb +3 -0
  185. data/lib/openc3/packets/parsers/packet_item_parser.rb +3 -0
  186. data/lib/openc3/packets/parsers/packet_parser.rb +3 -0
  187. data/lib/openc3/packets/parsers/processor_parser.rb +3 -0
  188. data/lib/openc3/packets/parsers/state_parser.rb +3 -0
  189. data/lib/openc3/packets/parsers/xtce_converter.rb +3 -0
  190. data/lib/openc3/packets/parsers/xtce_parser.rb +3 -0
  191. data/lib/openc3/packets/structure.rb +3 -0
  192. data/lib/openc3/packets/structure_item.rb +3 -0
  193. data/lib/openc3/packets/telemetry.rb +3 -0
  194. data/lib/openc3/processors/processor.rb +3 -0
  195. data/lib/openc3/processors/statistics_processor.rb +3 -0
  196. data/lib/openc3/processors/watermark_processor.rb +3 -0
  197. data/lib/openc3/processors.rb +3 -0
  198. data/lib/openc3/script/api_shared.rb +35 -6
  199. data/lib/openc3/script/calendar.rb +3 -0
  200. data/lib/openc3/script/commands.rb +3 -0
  201. data/lib/openc3/script/exceptions.rb +3 -0
  202. data/lib/openc3/script/extract.rb +3 -0
  203. data/lib/openc3/script/limits.rb +3 -24
  204. data/lib/openc3/script/script.rb +11 -7
  205. data/lib/openc3/script/script_runner.rb +3 -0
  206. data/lib/openc3/script/storage.rb +33 -16
  207. data/lib/openc3/script/suite.rb +3 -0
  208. data/lib/openc3/script/suite_results.rb +3 -0
  209. data/lib/openc3/script/suite_runner.rb +3 -0
  210. data/lib/openc3/script/telemetry.rb +43 -0
  211. data/lib/openc3/script.rb +3 -0
  212. data/lib/openc3/streams/serial_stream.rb +3 -0
  213. data/lib/openc3/streams/stream.rb +3 -0
  214. data/lib/openc3/streams/tcpip_client_stream.rb +3 -0
  215. data/lib/openc3/streams/tcpip_socket_stream.rb +3 -0
  216. data/lib/openc3/system/system.rb +23 -10
  217. data/lib/openc3/system/system_config.rb +3 -0
  218. data/lib/openc3/system/target.rb +3 -0
  219. data/lib/openc3/system.rb +3 -0
  220. data/lib/openc3/tools/cmd_tlm_server/api.rb +3 -0
  221. data/lib/openc3/tools/cmd_tlm_server/cmd_tlm_server_config.rb +3 -0
  222. data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +3 -0
  223. data/lib/openc3/tools/table_manager/table.rb +3 -0
  224. data/lib/openc3/tools/table_manager/table_config.rb +3 -0
  225. data/lib/openc3/tools/table_manager/table_item.rb +3 -0
  226. data/lib/openc3/tools/table_manager/table_item_parser.rb +3 -0
  227. data/lib/openc3/tools/table_manager/table_manager_core.rb +3 -0
  228. data/lib/openc3/tools/table_manager/table_parser.rb +3 -0
  229. data/lib/openc3/tools/test_runner/test.rb +3 -0
  230. data/lib/openc3/top_level.rb +3 -0
  231. data/lib/openc3/topics/autonomic_topic.rb +3 -0
  232. data/lib/openc3/topics/calendar_topic.rb +3 -0
  233. data/lib/openc3/topics/command_decom_topic.rb +4 -1
  234. data/lib/openc3/topics/command_topic.rb +6 -1
  235. data/lib/openc3/topics/config_topic.rb +3 -0
  236. data/lib/openc3/topics/interface_topic.rb +9 -2
  237. data/lib/openc3/topics/limits_event_topic.rb +144 -10
  238. data/lib/openc3/topics/notifications_topic.rb +3 -0
  239. data/lib/openc3/topics/router_topic.rb +10 -3
  240. data/lib/openc3/topics/telemetry_decom_topic.rb +26 -20
  241. data/lib/openc3/topics/telemetry_reduced_topics.rb +92 -0
  242. data/lib/openc3/topics/telemetry_topic.rb +5 -2
  243. data/lib/openc3/topics/timeline_topic.rb +3 -0
  244. data/lib/openc3/topics/topic.rb +3 -0
  245. data/lib/openc3/utilities/authentication.rb +3 -0
  246. data/lib/openc3/utilities/authorization.rb +3 -0
  247. data/lib/openc3/utilities/aws_bucket.rb +199 -0
  248. data/lib/openc3/utilities/bucket.rb +82 -0
  249. data/lib/openc3/utilities/bucket_file_cache.rb +264 -0
  250. data/lib/openc3/utilities/bucket_utilities.rb +109 -0
  251. data/lib/openc3/utilities/crc.rb +3 -0
  252. data/lib/openc3/utilities/csv.rb +3 -0
  253. data/lib/openc3/utilities/local_bucket.rb +28 -0
  254. data/lib/openc3/utilities/local_mode.rb +47 -61
  255. data/lib/openc3/utilities/logger.rb +7 -1
  256. data/lib/openc3/utilities/message_log.rb +7 -4
  257. data/lib/openc3/utilities/metric.rb +4 -1
  258. data/lib/openc3/utilities/open_telemetry.rb +96 -0
  259. data/lib/openc3/utilities/process_manager.rb +3 -0
  260. data/lib/openc3/utilities/quaternion.rb +3 -0
  261. data/lib/openc3/utilities/ruby_lex_utils.rb +3 -0
  262. data/lib/openc3/utilities/s3_autoload.rb +3 -3
  263. data/lib/openc3/utilities/simulated_target.rb +3 -0
  264. data/lib/openc3/utilities/sleeper.rb +3 -0
  265. data/lib/openc3/utilities/store.rb +3 -0
  266. data/lib/openc3/utilities/store_autoload.rb +30 -23
  267. data/lib/openc3/utilities/target_file.rb +70 -83
  268. data/lib/openc3/utilities/zip.rb +3 -0
  269. data/lib/openc3/utilities.rb +3 -0
  270. data/lib/openc3/version.rb +6 -6
  271. data/lib/openc3/win32/excel.rb +3 -0
  272. data/lib/openc3/win32/win32.rb +3 -0
  273. data/lib/openc3/win32/win32_main.rb +3 -0
  274. data/lib/openc3.rb +3 -0
  275. data/tasks/gemfile_stats.rake +3 -0
  276. data/tasks/spec.rake +3 -0
  277. data/templates/plugin-template/plugin.gemspec +1 -1
  278. metadata +112 -6
  279. data/lib/openc3/utilities/s3.rb +0 -220
  280. data/lib/openc3/utilities/s3_file_cache.rb +0 -274
@@ -16,6 +16,9 @@
16
16
  # Modified by OpenC3, Inc.
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
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.
19
22
 
20
23
  require 'socket'
21
24
  require 'ipaddr'
@@ -16,6 +16,9 @@
16
16
  # Modified by OpenC3, Inc.
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
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.
19
22
 
20
23
  require 'openc3/win32/win32'
21
24
  require 'timeout' # For Timeout::Error
@@ -0,0 +1,65 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2022 OpenC3, Inc.
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
+ # This file may also be used under the terms of a commercial license
17
+ # if purchased from OpenC3, Inc.
18
+
19
+ require 'openc3/logs/packet_log_reader'
20
+ require 'openc3/logs/packet_log_writer'
21
+
22
+ module OpenC3
23
+ # Buffers files so small time differences can be read in time order
24
+ class BufferedPacketLogReader < PacketLogReader
25
+
26
+ attr_reader :bucket_file
27
+
28
+ def initialize(bucket_file = nil, buffer_depth = 10)
29
+ super()
30
+ @bucket_file = bucket_file
31
+ @buffer_depth = buffer_depth
32
+ end
33
+
34
+ def next_packet_time
35
+ fill_buffer()
36
+ packet = @buffer[0]
37
+ return packet.packet_time if packet
38
+ return nil
39
+ end
40
+
41
+ def buffered_read(identify_and_define = true)
42
+ fill_buffer(identify_and_define)
43
+ return @buffer.shift
44
+ end
45
+
46
+ protected
47
+
48
+ def fill_buffer(identify_and_define = true)
49
+ while true
50
+ break if @buffer.length >= @buffer_depth
51
+ packet = read(identify_and_define)
52
+ break unless packet
53
+ packet = packet.dup if identify_and_define
54
+ @buffer << packet
55
+ @buffer.sort! {|pkt1, pkt2| pkt1.packet_time <=> pkt2.packet_time }
56
+ end
57
+ end
58
+
59
+ def reset
60
+ super()
61
+ @buffer = []
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,120 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2022 OpenC3, Inc.
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
+ # This file may also be used under the terms of a commercial license
17
+ # if purchased from OpenC3, Inc.
18
+
19
+ require 'openc3/logs/packet_log_writer'
20
+
21
+ module OpenC3
22
+ # Creates a packet log. Can automatically cycle the log based on an elasped
23
+ # time period or when the log file reaches a predefined size.
24
+ class BufferedPacketLogWriter < PacketLogWriter
25
+ # @param remote_log_directory [String] The path to store the log files
26
+ # @param label [String] Label to apply to the log filename
27
+ # @param logging_enabled [Boolean] Whether to start with logging enabled
28
+ # @param cycle_time [Integer] The amount of time in seconds before creating
29
+ # a new log file. This can be combined with cycle_size but is better used
30
+ # independently.
31
+ # @param cycle_size [Integer] The size in bytes before creating a new log
32
+ # file. This can be combined with cycle_time but is better used
33
+ # independently.
34
+ # @param cycle_hour [Integer] The time at which to cycle the log. Combined with
35
+ # cycle_minute to cycle the log daily at the specified time. If nil, the log
36
+ # will be cycled hourly at the specified cycle_minute.
37
+ # @param cycle_minute [Integer] The time at which to cycle the log. See cycle_hour
38
+ # for more information.
39
+ # @param buffer_depth [Integer] Number of packets to buffer before writing to file
40
+ def initialize(
41
+ remote_log_directory,
42
+ label,
43
+ logging_enabled = true,
44
+ cycle_time = nil,
45
+ cycle_size = 1_000_000_000,
46
+ cycle_hour = nil,
47
+ cycle_minute = nil,
48
+ enforce_time_order = true,
49
+ buffer_depth = 10
50
+ )
51
+ super(
52
+ remote_log_directory,
53
+ label,
54
+ logging_enabled,
55
+ cycle_time,
56
+ cycle_size,
57
+ cycle_hour,
58
+ cycle_minute,
59
+ enforce_time_order
60
+ )
61
+ @buffer_depth = Integer(buffer_depth)
62
+ @buffer = []
63
+ end
64
+
65
+ # Write a packet to the log file.
66
+ #
67
+ # If no log file currently exists in the filesystem, a new file will be
68
+ # created.
69
+ #
70
+ # @param entry_type [Symbol] Type of entry to write. Must be one of
71
+ # :TARGET_DECLARATION, :PACKET_DECLARATION, :RAW_PACKET, :JSON_PACKET, :OFFSET_MARKER, :KEY_MAP
72
+ # @param cmd_or_tlm [Symbol] One of :CMD or :TLM
73
+ # @param target_name [String] Name of the target
74
+ # @param packet_name [String] Name of the packet
75
+ # @param time_nsec_since_epoch [Integer] 64 bit integer nsecs since EPOCH
76
+ # @param stored [Boolean] Whether this data is stored telemetry
77
+ # @param data [String] Binary string of data
78
+ # @param id [Integer] Target ID
79
+ # @param redis_offset [Integer] The offset of this packet in its Redis stream
80
+ def buffered_write(entry_type, cmd_or_tlm, target_name, packet_name, time_nsec_since_epoch, stored, data, id = nil, redis_topic = nil, redis_offset = '0-0')
81
+ case entry_type
82
+ when :RAW_PACKET, :JSON_PACKET
83
+ @buffer << [entry_type, cmd_or_tlm, target_name, packet_name, time_nsec_since_epoch, stored, data, id, redis_topic, redis_offset]
84
+ @buffer.sort! {|entry1, entry2| entry1[4] <=> entry2[4] }
85
+ if @buffer.length >= @buffer_depth
86
+ entry = @buffer.shift
87
+ write(*entry)
88
+ end
89
+ else
90
+ write(entry_type, cmd_or_tlm, target_name, packet_name, time_nsec_since_epoch, stored, data, id, redis_topic, redis_offset)
91
+ end
92
+ end
93
+
94
+ def buffered_first_time_nsec
95
+ time = first_time()
96
+ return time.to_nsec_from_epoch if time
97
+ return @buffer[0][4] if @buffer[0]
98
+ return nil
99
+ end
100
+
101
+ def start_new_file(empty_buffer = false)
102
+ write_buffer() if empty_buffer
103
+ super()
104
+ end
105
+
106
+ def write_buffer
107
+ @buffer.each do |entry|
108
+ write(*entry)
109
+ end
110
+ @buffer = []
111
+ end
112
+
113
+ # Need to write out all remaining buffer entries and then shutdown
114
+ # Returns thread that moves final log to bucket
115
+ def shutdown
116
+ write_buffer()
117
+ return super()
118
+ end
119
+ end
120
+ end
@@ -16,11 +16,14 @@
16
16
  # Modified by OpenC3, Inc.
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
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.
19
22
 
20
23
  require 'thread'
21
24
  require 'openc3/config/config_parser'
22
25
  require 'openc3/topics/topic'
23
- require 'openc3/utilities/s3'
26
+ require 'openc3/utilities/bucket_utilities'
24
27
 
25
28
  module OpenC3
26
29
  # Creates a log. Can automatically cycle the log based on an elasped
@@ -52,10 +55,19 @@ module OpenC3
52
55
  # @return [Mutex] Instance mutex protecting file
53
56
  attr_reader :mutex
54
57
 
58
+ # Redis offsets for each topic to cleanup
59
+ attr_accessor :cleanup_offsets
60
+
61
+ # Time at which to cleanup
62
+ attr_accessor :cleanup_times
63
+
55
64
  # The cycle time interval. Cycle times are only checked at this level of
56
65
  # granularity.
57
66
  CYCLE_TIME_INTERVAL = 10
58
67
 
68
+ # Delay in seconds before trimming Redis streams
69
+ CLEANUP_DELAY = 60
70
+
59
71
  # Mutex protecting class variables
60
72
  @@mutex = Mutex.new
61
73
 
@@ -68,7 +80,7 @@ module OpenC3
68
80
  # Sleeper used to delay cycle thread
69
81
  @@cycle_sleeper = nil
70
82
 
71
- # @param remote_log_directory [String] The s3 path to store the log files
83
+ # @param remote_log_directory [String] The path to store the log files
72
84
  # @param logging_enabled [Boolean] Whether to start with logging enabled
73
85
  # @param cycle_time [Integer] The amount of time in seconds before creating
74
86
  # a new log file. This can be combined with cycle_size but is better used
@@ -81,8 +93,6 @@ module OpenC3
81
93
  # will be cycled hourly at the specified cycle_minute.
82
94
  # @param cycle_minute [Integer] The time at which to cycle the log. See cycle_hour
83
95
  # for more information.
84
- # @param redis_topic [String] The key of the Redis stream to trim when files are
85
- # moved to S3
86
96
  def initialize(
87
97
  remote_log_directory,
88
98
  logging_enabled = true,
@@ -90,7 +100,7 @@ module OpenC3
90
100
  cycle_size = 1000000000,
91
101
  cycle_hour = nil,
92
102
  cycle_minute = nil,
93
- redis_topic: nil
103
+ enforce_time_order = true
94
104
  )
95
105
  @remote_log_directory = remote_log_directory
96
106
  @logging_enabled = ConfigParser.handle_true_false(logging_enabled)
@@ -105,6 +115,7 @@ module OpenC3
105
115
  @cycle_hour = Integer(@cycle_hour) if @cycle_hour
106
116
  @cycle_minute = ConfigParser.handle_nil(cycle_minute)
107
117
  @cycle_minute = Integer(@cycle_minute) if @cycle_minute
118
+ @enforce_time_order = ConfigParser.handle_true_false(enforce_time_order)
108
119
  @mutex = Mutex.new
109
120
  @file = nil
110
121
  @file_size = 0
@@ -113,22 +124,22 @@ module OpenC3
113
124
  @first_time = nil
114
125
  @last_time = nil
115
126
  @cancel_threads = false
116
- @last_offset = nil
117
- @previous_file_redis_offset = nil
118
- @redis_topic = redis_topic
127
+ @last_offsets = {}
128
+ @cleanup_offsets = []
129
+ @cleanup_times = []
130
+ @previous_time_nsec_since_epoch = nil
119
131
 
120
132
  # This is an optimization to avoid creating a new entry object
121
133
  # each time we create an entry which we do a LOT!
122
134
  @entry = String.new
123
135
 
124
- if @cycle_time or @cycle_hour or @cycle_minute
125
- @@mutex.synchronize do
126
- @@instances << self
136
+ # Always make sure there is a cycle thread - (because it does trimming)
137
+ @@mutex.synchronize do
138
+ @@instances << self
127
139
 
128
- unless @@cycle_thread
129
- @@cycle_thread = OpenC3.safe_thread("Log cycle") do
130
- cycle_thread_body()
131
- end
140
+ unless @@cycle_thread
141
+ @@cycle_thread = OpenC3.safe_thread("Log cycle") do
142
+ cycle_thread_body()
132
143
  end
133
144
  end
134
145
  end
@@ -143,12 +154,14 @@ module OpenC3
143
154
 
144
155
  # Stops all logging and closes the current log file.
145
156
  def stop
146
- @mutex.synchronize { @logging_enabled = false; close_file(false) }
157
+ threads = nil
158
+ @mutex.synchronize { @logging_enabled = false; threads = close_file(false) }
159
+ return threads
147
160
  end
148
161
 
149
162
  # Stop all logging, close the current log file, and kill the logging threads.
150
163
  def shutdown
151
- stop()
164
+ threads = stop()
152
165
  @@mutex.synchronize do
153
166
  @@instances.delete(self)
154
167
  if @@instances.length <= 0
@@ -157,6 +170,7 @@ module OpenC3
157
170
  @@cycle_thread = nil
158
171
  end
159
172
  end
173
+ return threads
160
174
  end
161
175
 
162
176
  def graceful_kill
@@ -192,18 +206,41 @@ module OpenC3
192
206
  instance.mutex.synchronize do
193
207
  utc_now = Time.now.utc
194
208
  # Logger.debug("start:#{@start_time.to_f} now:#{utc_now.to_f} cycle:#{@cycle_time} new:#{(utc_now - @start_time) > @cycle_time}")
195
- if instance.logging_enabled and
196
- (
197
- # Cycle based on total time logging
198
- (instance.cycle_time and (utc_now - instance.start_time) > instance.cycle_time) or
199
-
200
- # Cycle daily at a specific time
201
- (instance.cycle_hour and instance.cycle_minute and utc_now.hour == instance.cycle_hour and utc_now.min == instance.cycle_minute and instance.start_time.yday != utc_now.yday) or
202
-
203
- # Cycle hourly at a specific time
204
- (instance.cycle_minute and not instance.cycle_hour and utc_now.min == instance.cycle_minute and instance.start_time.hour != utc_now.hour)
205
- )
206
- instance.close_file(false)
209
+ if instance.logging_enabled and instance.filename # Logging and file opened
210
+ # Cycle based on total time logging
211
+ if (instance.cycle_time and (utc_now - instance.start_time) > instance.cycle_time)
212
+ Logger.debug("Log writer start new file due to cycle time")
213
+ instance.close_file(false)
214
+ # Cycle daily at a specific time
215
+ elsif (instance.cycle_hour and instance.cycle_minute and utc_now.hour == instance.cycle_hour and utc_now.min == instance.cycle_minute and instance.start_time.yday != utc_now.yday)
216
+ Logger.debug("Log writer start new file daily")
217
+ instance.close_file(false)
218
+ # Cycle hourly at a specific time
219
+ elsif (instance.cycle_minute and not instance.cycle_hour and utc_now.min == instance.cycle_minute and instance.start_time.hour != utc_now.hour)
220
+ Logger.debug("Log writer start new file hourly")
221
+ instance.close_file(false)
222
+ end
223
+ end
224
+
225
+ # Check for cleanup time
226
+ indexes_to_clear = []
227
+ instance.cleanup_times.each_with_index do |cleanup_time, index|
228
+ if cleanup_time <= utc_now
229
+ # Now that the file is in S3, trim the Redis stream up until the previous file.
230
+ # This keeps one minute of data in Redis
231
+ instance.cleanup_offsets[index].each do |redis_topic, cleanup_offset|
232
+ Topic.trim_topic(redis_topic, cleanup_offset)
233
+ end
234
+ indexes_to_clear << index
235
+ end
236
+ end
237
+ if indexes_to_clear.length > 0
238
+ indexes_to_clear.each do |index|
239
+ instance.cleanup_offsets[index] = nil
240
+ instance.cleanup_times[index] = nil
241
+ end
242
+ instance.cleanup_offsets.compact!
243
+ instance.cleanup_times.compact!
207
244
  end
208
245
  end
209
246
  end
@@ -231,6 +268,7 @@ module OpenC3
231
268
  @start_time = Time.now.utc
232
269
  @first_time = nil
233
270
  @last_time = nil
271
+ @previous_time_nsec_since_epoch = nil
234
272
  Logger.debug "Log File Opened : #{@filename}"
235
273
  rescue => err
236
274
  Logger.error "Error starting new log file: #{err.formatted}"
@@ -238,17 +276,30 @@ module OpenC3
238
276
  OpenC3.handle_critical_exception(err)
239
277
  end
240
278
 
241
- def prepare_write(time_nsec_since_epoch, data_length, redis_offset)
279
+ def prepare_write(time_nsec_since_epoch, data_length, redis_topic, redis_offset)
242
280
  # This check includes logging_enabled again because it might have changed since we acquired the mutex
243
- if @logging_enabled and (!@file or (@cycle_size and (@file_size + data_length) > @cycle_size))
244
- start_new_file()
281
+ # Ensures new files based on size, and ensures always increasing time order in files
282
+ if @logging_enabled
283
+ if !@file
284
+ Logger.debug("Log writer start new file because no file opened")
285
+ start_new_file()
286
+ elsif @cycle_size and ((@file_size + data_length) > @cycle_size)
287
+ Logger.debug("Log writer start new file due to cycle size #{@cycle_size}")
288
+ start_new_file()
289
+ elsif @enforce_time_order and @previous_time_nsec_since_epoch and (@previous_time_nsec_since_epoch > time_nsec_since_epoch)
290
+ Logger.debug("Log writer start new file due to out of order time: #{Time.from_nsec_from_epoch(@previous_time_nsec_since_epoch)} #{Time.from_nsec_from_epoch(time_nsec_since_epoch)}")
291
+ start_new_file()
292
+ end
245
293
  end
246
- @last_offset = redis_offset # This is needed for the redis offset marker entry at the end of the log file
294
+ @last_offsets[redis_topic] = redis_offset if redis_topic and redis_offset # This is needed for the redis offset marker entry at the end of the log file
295
+ @previous_time_nsec_since_epoch = time_nsec_since_epoch
247
296
  end
248
297
 
249
298
  # Closing a log file isn't critical so we just log an error. NOTE: This also trims the Redis stream
250
299
  # to keep a full file's worth of data in the stream. This is what prevents continuous stream growth.
300
+ # Returns thread that moves log to bucket
251
301
  def close_file(take_mutex = true)
302
+ threads = []
252
303
  @mutex.lock if take_mutex
253
304
  begin
254
305
  if @file
@@ -256,12 +307,15 @@ module OpenC3
256
307
  @file.close unless @file.closed?
257
308
  Logger.debug "Log File Closed : #{@filename}"
258
309
  date = first_timestamp[0..7] # YYYYMMDD
259
- s3_key = File.join(@remote_log_directory, date, s3_filename)
260
- S3Utilities.move_log_file_to_s3(@filename, s3_key)
261
- # Now that the file is in S3, trim the Redis stream up until the previous file.
262
- # This keeps one file worth of data in Redis as a safety buffer
263
- Topic.trim_topic(@redis_topic, @previous_file_redis_offset) if @redis_topic and @previous_file_redis_offset
264
- @previous_file_redis_offset = @last_offset
310
+ bucket_key = File.join(@remote_log_directory, date, bucket_filename())
311
+ threads << BucketUtilities.move_log_file_to_bucket(@filename, bucket_key)
312
+ # Now that the file is in storage, trim the Redis stream after a delay
313
+ @cleanup_offsets << {}
314
+ @last_offsets.each do |redis_topic, last_offset|
315
+ @cleanup_offsets[-1][redis_topic] = last_offset
316
+ end
317
+ @cleanup_times << Time.now + CLEANUP_DELAY
318
+ @last_offsets.clear
265
319
  rescue Exception => err
266
320
  Logger.instance.error "Error closing #{@filename} : #{err.formatted}"
267
321
  end
@@ -273,9 +327,10 @@ module OpenC3
273
327
  ensure
274
328
  @mutex.unlock if take_mutex
275
329
  end
330
+ return threads
276
331
  end
277
332
 
278
- def s3_filename
333
+ def bucket_filename
279
334
  "#{first_timestamp}__#{last_timestamp}" + extension
280
335
  end
281
336
 
@@ -16,6 +16,9 @@
16
16
  # Modified by OpenC3, Inc.
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
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.
19
22
 
20
23
  module OpenC3
21
24
  module PacketLogConstants
@@ -34,6 +37,8 @@ module OpenC3
34
37
  OPENC3_RAW_PACKET_ENTRY_TYPE_MASK = 0x3000
35
38
  OPENC3_JSON_PACKET_ENTRY_TYPE_MASK = 0x4000
36
39
  OPENC3_OFFSET_MARKER_ENTRY_TYPE_MASK = 0x5000
40
+ OPENC3_KEY_MAP_ENTRY_TYPE_MASK = 0x6000
41
+ OPENC3_CBOR_FLAG_MASK = 0x0100
37
42
  OPENC3_ID_FLAG_MASK = 0x0200
38
43
  OPENC3_STORED_FLAG_MASK = 0x0400
39
44
  OPENC3_CMD_FLAG_MASK = 0x0800
@@ -55,6 +60,10 @@ module OpenC3
55
60
  OPENC3_OFFSET_MARKER_PACK_DIRECTIVE = 'Nn'.freeze
56
61
  OPENC3_OFFSET_MARKER_PACK_ITEMS = 2 # Useful for testing
57
62
 
63
+ OPENC3_KEY_MAP_SECONDARY_FIXED_SIZE = 2
64
+ OPENC3_KEY_MAP_PACK_DIRECTIVE = 'Nnn'.freeze
65
+ OPENC3_KEY_MAP_PACK_ITEMS = 3 # Useful for testing
66
+
58
67
  OPENC3_PACKET_SECONDARY_FIXED_SIZE = 10
59
68
  OPENC3_PACKET_PACK_DIRECTIVE = 'NnnQ>'.freeze
60
69
  OPENC3_PACKET_PACK_ITEMS = 4 # Useful for testing
@@ -16,12 +16,16 @@
16
16
  # Modified by OpenC3, Inc.
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
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.
19
22
 
20
23
  require 'openc3/core_ext/io'
21
24
  require 'openc3/packets/packet'
22
25
  require 'openc3/packets/json_packet'
23
26
  require 'openc3/io/buffered_file'
24
27
  require 'openc3/logs/packet_log_constants'
28
+ require 'cbor'
25
29
 
26
30
  module OpenC3
27
31
  # Reads a packet log of either commands or telemetry.
@@ -29,6 +33,8 @@ module OpenC3
29
33
  include PacketLogConstants
30
34
 
31
35
  attr_reader :redis_offset
36
+ attr_reader :last_offsets
37
+ attr_reader :filename
32
38
 
33
39
  MAX_READ_SIZE = 1000000000
34
40
 
@@ -119,16 +125,22 @@ module OpenC3
119
125
  stored = true if flags & OPENC3_STORED_FLAG_MASK == OPENC3_STORED_FLAG_MASK
120
126
  id = false
121
127
  id = true if flags & OPENC3_ID_FLAG_MASK == OPENC3_ID_FLAG_MASK
128
+ cbor = false
129
+ cbor = true if flags & OPENC3_CBOR_FLAG_MASK == OPENC3_CBOR_FLAG_MASK
122
130
 
123
131
  if flags & OPENC3_ENTRY_TYPE_MASK == OPENC3_JSON_PACKET_ENTRY_TYPE_MASK
124
132
  packet_index, time_nsec_since_epoch = entry[2..11].unpack('nQ>')
125
133
  json_data = entry[12..-1]
126
- lookup_cmd_or_tlm, target_name, packet_name, id = @packets[packet_index]
134
+ lookup_cmd_or_tlm, target_name, packet_name, id, key_map = @packets[packet_index]
127
135
  if cmd_or_tlm != lookup_cmd_or_tlm
128
136
  raise "Packet type mismatch, packet:#{cmd_or_tlm}, lookup:#{lookup_cmd_or_tlm}"
129
137
  end
130
138
 
131
- return JsonPacket.new(cmd_or_tlm, target_name, packet_name, time_nsec_since_epoch, stored, json_data)
139
+ if cbor
140
+ return JsonPacket.new(cmd_or_tlm, target_name, packet_name, time_nsec_since_epoch, stored, CBOR.decode(json_data), key_map)
141
+ else
142
+ return JsonPacket.new(cmd_or_tlm, target_name, packet_name, time_nsec_since_epoch, stored, json_data, key_map)
143
+ end
132
144
  elsif flags & OPENC3_ENTRY_TYPE_MASK == OPENC3_RAW_PACKET_ENTRY_TYPE_MASK
133
145
  packet_index, time_nsec_since_epoch = entry[2..11].unpack('nQ>')
134
146
  packet_data = entry[12..-1]
@@ -171,8 +183,26 @@ module OpenC3
171
183
  end
172
184
  @packets << [cmd_or_tlm, target_name, packet_name, id]
173
185
  return read(identify_and_define)
186
+ elsif flags & OPENC3_ENTRY_TYPE_MASK == OPENC3_KEY_MAP_ENTRY_TYPE_MASK
187
+ packet_index = entry[2..3].unpack('n')[0]
188
+ key_map_length = length - OPENC3_PRIMARY_FIXED_SIZE - OPENC3_KEY_MAP_SECONDARY_FIXED_SIZE
189
+ if cbor
190
+ key_map = CBOR.decode(entry[4..(key_map_length + 3)])
191
+ else
192
+ key_map = JSON.parse(entry[4..(key_map_length + 3)], :allow_nan => true, :create_additions => true)
193
+ end
194
+ @packets[packet_index] << key_map
195
+ return read(identify_and_define)
174
196
  elsif flags & OPENC3_ENTRY_TYPE_MASK == OPENC3_OFFSET_MARKER_ENTRY_TYPE_MASK
175
- @redis_offset = entry[2..-1]
197
+ data = entry[2..-1]
198
+ split_data = data.split(',')
199
+ redis_offset = split_data[0]
200
+ redis_topic = split_data[1]
201
+ if redis_topic
202
+ @last_offsets[redis_topic] = redis_offset
203
+ else
204
+ @redis_offset = redis_offset
205
+ end
176
206
  return read(identify_and_define)
177
207
  else
178
208
  raise "Invalid Entry Flags: #{flags}"
@@ -292,6 +322,7 @@ module OpenC3
292
322
  @packets = []
293
323
  @packet_ids = []
294
324
  @redis_offset = nil
325
+ @last_offsets = {}
295
326
  end
296
327
 
297
328
  # This is best effort. May return unidentified/undefined packets