openc3 5.0.11 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +3 -0
  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 +118 -0
  122. data/lib/openc3/logs/log_writer.rb +94 -41
  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 -20
  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 +5 -2
  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
@@ -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,118 @@
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
+ buffer_depth = 10
49
+ )
50
+ super(
51
+ remote_log_directory,
52
+ label,
53
+ logging_enabled,
54
+ cycle_time,
55
+ cycle_size,
56
+ cycle_hour,
57
+ cycle_minute
58
+ )
59
+ @buffer_depth = Integer(buffer_depth)
60
+ @buffer = []
61
+ end
62
+
63
+ # Write a packet to the log file.
64
+ #
65
+ # If no log file currently exists in the filesystem, a new file will be
66
+ # created.
67
+ #
68
+ # @param entry_type [Symbol] Type of entry to write. Must be one of
69
+ # :TARGET_DECLARATION, :PACKET_DECLARATION, :RAW_PACKET, :JSON_PACKET, :OFFSET_MARKER, :KEY_MAP
70
+ # @param cmd_or_tlm [Symbol] One of :CMD or :TLM
71
+ # @param target_name [String] Name of the target
72
+ # @param packet_name [String] Name of the packet
73
+ # @param time_nsec_since_epoch [Integer] 64 bit integer nsecs since EPOCH
74
+ # @param stored [Boolean] Whether this data is stored telemetry
75
+ # @param data [String] Binary string of data
76
+ # @param id [Integer] Target ID
77
+ # @param redis_offset [Integer] The offset of this packet in its Redis stream
78
+ 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')
79
+ case entry_type
80
+ when :RAW_PACKET, :JSON_PACKET
81
+ @buffer << [entry_type, cmd_or_tlm, target_name, packet_name, time_nsec_since_epoch, stored, data, id, redis_topic, redis_offset]
82
+ @buffer.sort! {|entry1, entry2| entry1[4] <=> entry2[4] }
83
+ if @buffer.length >= @buffer_depth
84
+ entry = @buffer.shift
85
+ write(*entry)
86
+ end
87
+ else
88
+ write(entry_type, cmd_or_tlm, target_name, packet_name, time_nsec_since_epoch, stored, data, id, redis_topic, redis_offset)
89
+ end
90
+ end
91
+
92
+ def buffered_first_time_nsec
93
+ time = first_time()
94
+ return time.to_nsec_from_epoch if time
95
+ return @buffer[0][4] if @buffer[0]
96
+ return nil
97
+ end
98
+
99
+ def start_new_file(empty_buffer = false)
100
+ write_buffer() if empty_buffer
101
+ super()
102
+ end
103
+
104
+ def write_buffer
105
+ @buffer.each do |entry|
106
+ write(*entry)
107
+ end
108
+ @buffer = []
109
+ end
110
+
111
+ # Need to write out all remaining buffer entries and then shutdown
112
+ # Returns thread that moves final log to bucket
113
+ def shutdown
114
+ write_buffer()
115
+ return super()
116
+ end
117
+ end
118
+ 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,16 +93,13 @@ 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,
89
99
  cycle_time = nil,
90
100
  cycle_size = 1000000000,
91
101
  cycle_hour = nil,
92
- cycle_minute = nil,
93
- redis_topic: nil
102
+ cycle_minute = nil
94
103
  )
95
104
  @remote_log_directory = remote_log_directory
96
105
  @logging_enabled = ConfigParser.handle_true_false(logging_enabled)
@@ -113,22 +122,22 @@ module OpenC3
113
122
  @first_time = nil
114
123
  @last_time = nil
115
124
  @cancel_threads = false
116
- @last_offset = nil
117
- @previous_file_redis_offset = nil
118
- @redis_topic = redis_topic
125
+ @last_offsets = {}
126
+ @cleanup_offsets = []
127
+ @cleanup_times = []
128
+ @previous_time_nsec_since_epoch = nil
119
129
 
120
130
  # This is an optimization to avoid creating a new entry object
121
131
  # each time we create an entry which we do a LOT!
122
132
  @entry = String.new
123
133
 
124
- if @cycle_time or @cycle_hour or @cycle_minute
125
- @@mutex.synchronize do
126
- @@instances << self
134
+ # Always make sure there is a cycle thread - (because it does trimming)
135
+ @@mutex.synchronize do
136
+ @@instances << self
127
137
 
128
- unless @@cycle_thread
129
- @@cycle_thread = OpenC3.safe_thread("Log cycle") do
130
- cycle_thread_body()
131
- end
138
+ unless @@cycle_thread
139
+ @@cycle_thread = OpenC3.safe_thread("Log cycle") do
140
+ cycle_thread_body()
132
141
  end
133
142
  end
134
143
  end
@@ -143,12 +152,14 @@ module OpenC3
143
152
 
144
153
  # Stops all logging and closes the current log file.
145
154
  def stop
146
- @mutex.synchronize { @logging_enabled = false; close_file(false) }
155
+ threads = nil
156
+ @mutex.synchronize { @logging_enabled = false; threads = close_file(false) }
157
+ return threads
147
158
  end
148
159
 
149
160
  # Stop all logging, close the current log file, and kill the logging threads.
150
161
  def shutdown
151
- stop()
162
+ threads = stop()
152
163
  @@mutex.synchronize do
153
164
  @@instances.delete(self)
154
165
  if @@instances.length <= 0
@@ -157,6 +168,7 @@ module OpenC3
157
168
  @@cycle_thread = nil
158
169
  end
159
170
  end
171
+ return threads
160
172
  end
161
173
 
162
174
  def graceful_kill
@@ -192,18 +204,41 @@ module OpenC3
192
204
  instance.mutex.synchronize do
193
205
  utc_now = Time.now.utc
194
206
  # 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)
207
+ if instance.logging_enabled and instance.filename # Logging and file opened
208
+ # Cycle based on total time logging
209
+ if (instance.cycle_time and (utc_now - instance.start_time) > instance.cycle_time)
210
+ Logger.debug("Log writer start new file due to cycle time")
211
+ instance.close_file(false)
212
+ # Cycle daily at a specific time
213
+ 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)
214
+ Logger.debug("Log writer start new file daily")
215
+ instance.close_file(false)
216
+ # Cycle hourly at a specific time
217
+ elsif (instance.cycle_minute and not instance.cycle_hour and utc_now.min == instance.cycle_minute and instance.start_time.hour != utc_now.hour)
218
+ Logger.debug("Log writer start new file hourly")
219
+ instance.close_file(false)
220
+ end
221
+ end
222
+
223
+ # Check for cleanup time
224
+ indexes_to_clear = []
225
+ instance.cleanup_times.each_with_index do |cleanup_time, index|
226
+ if cleanup_time <= utc_now
227
+ # Now that the file is in S3, trim the Redis stream up until the previous file.
228
+ # This keeps one minute of data in Redis
229
+ instance.cleanup_offsets[index].each do |redis_topic, cleanup_offset|
230
+ Topic.trim_topic(redis_topic, cleanup_offset)
231
+ end
232
+ indexes_to_clear << index
233
+ end
234
+ end
235
+ if indexes_to_clear.length > 0
236
+ indexes_to_clear.each do |index|
237
+ instance.cleanup_offsets[index] = nil
238
+ instance.cleanup_times[index] = nil
239
+ end
240
+ instance.cleanup_offsets.compact!
241
+ instance.cleanup_times.compact!
207
242
  end
208
243
  end
209
244
  end
@@ -231,6 +266,7 @@ module OpenC3
231
266
  @start_time = Time.now.utc
232
267
  @first_time = nil
233
268
  @last_time = nil
269
+ @previous_time_nsec_since_epoch = nil
234
270
  Logger.debug "Log File Opened : #{@filename}"
235
271
  rescue => err
236
272
  Logger.error "Error starting new log file: #{err.formatted}"
@@ -238,17 +274,30 @@ module OpenC3
238
274
  OpenC3.handle_critical_exception(err)
239
275
  end
240
276
 
241
- def prepare_write(time_nsec_since_epoch, data_length, redis_offset)
277
+ def prepare_write(time_nsec_since_epoch, data_length, redis_topic, redis_offset)
242
278
  # 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()
279
+ # Ensures new files based on size, and ensures always increasing time order in files
280
+ if @logging_enabled
281
+ if !@file
282
+ Logger.debug("Log writer start new file because no file opened")
283
+ start_new_file()
284
+ elsif @cycle_size and ((@file_size + data_length) > @cycle_size)
285
+ Logger.debug("Log writer start new file due to cycle size #{@cycle_size}")
286
+ start_new_file()
287
+ elsif @previous_time_nsec_since_epoch and (@previous_time_nsec_since_epoch > time_nsec_since_epoch)
288
+ 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)}")
289
+ start_new_file()
290
+ end
245
291
  end
246
- @last_offset = redis_offset # This is needed for the redis offset marker entry at the end of the log file
292
+ @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
293
+ @previous_time_nsec_since_epoch = time_nsec_since_epoch
247
294
  end
248
295
 
249
296
  # Closing a log file isn't critical so we just log an error. NOTE: This also trims the Redis stream
250
297
  # to keep a full file's worth of data in the stream. This is what prevents continuous stream growth.
298
+ # Returns thread that moves log to bucket
251
299
  def close_file(take_mutex = true)
300
+ thread = nil
252
301
  @mutex.lock if take_mutex
253
302
  begin
254
303
  if @file
@@ -256,12 +305,15 @@ module OpenC3
256
305
  @file.close unless @file.closed?
257
306
  Logger.debug "Log File Closed : #{@filename}"
258
307
  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
308
+ bucket_key = File.join(@remote_log_directory, date, bucket_filename())
309
+ thread = BucketUtilities.move_log_file_to_bucket(@filename, bucket_key)
310
+ # Now that the file is in storage, trim the Redis stream after a delay
311
+ @cleanup_offsets << {}
312
+ @last_offsets.each do |redis_topic, last_offset|
313
+ @cleanup_offsets[-1][redis_topic] = last_offset
314
+ end
315
+ @cleanup_times << Time.now + CLEANUP_DELAY
316
+ @last_offsets.clear
265
317
  rescue Exception => err
266
318
  Logger.instance.error "Error closing #{@filename} : #{err.formatted}"
267
319
  end
@@ -273,9 +325,10 @@ module OpenC3
273
325
  ensure
274
326
  @mutex.unlock if take_mutex
275
327
  end
328
+ return thread
276
329
  end
277
330
 
278
- def s3_filename
331
+ def bucket_filename
279
332
  "#{first_timestamp}__#{last_timestamp}" + extension
280
333
  end
281
334
 
@@ -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