cosmos 4.0.3 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -5
  3. data/Manifest.txt +11 -1
  4. data/README.md +3 -2
  5. data/Rakefile +18 -4
  6. data/appveyor.yml +19 -0
  7. data/cosmos.gemspec +14 -3
  8. data/data/config/cmd_tlm_server.yaml +3 -0
  9. data/data/crc.txt +63 -60
  10. data/demo/config/targets/INST/cmd_tlm_server.txt +1 -0
  11. data/demo/config/targets/INST/cmd_tlm_server2.txt +7 -0
  12. data/demo/config/tools/cmd_sequence/cmd_sequence.txt +2 -0
  13. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +8 -12
  14. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +7 -9
  15. data/demo/lib/cmd_sequence_exporter.rb +52 -0
  16. data/demo/lib/example_background_task.rb +1 -0
  17. data/demo/procedures/replay_test.rb +32 -0
  18. data/ext/cosmos/ext/structure/structure.c +39 -3
  19. data/install/config/tools/cmd_tlm_server/cmd_tlm_server.txt +1 -0
  20. data/install/config/tools/launcher/launcher.txt +2 -0
  21. data/lib/cosmos/config/config_parser.rb +2 -0
  22. data/lib/cosmos/core_ext/io.rb +89 -60
  23. data/lib/cosmos/gui/qt.rb +5 -8
  24. data/lib/cosmos/gui/qt_tool.rb +8 -8
  25. data/lib/cosmos/gui/text/ruby_editor.rb +12 -12
  26. data/lib/cosmos/gui/utilities/script_module_gui.rb +9 -9
  27. data/lib/cosmos/gui/widgets/realtime_button_bar.rb +18 -17
  28. data/lib/cosmos/interfaces/protocols/fixed_protocol.rb +2 -2
  29. data/lib/cosmos/interfaces/protocols/template_protocol.rb +3 -0
  30. data/lib/cosmos/interfaces/udp_interface.rb +27 -14
  31. data/lib/cosmos/io/buffered_file.rb +0 -1
  32. data/lib/cosmos/io/json_drb.rb +134 -214
  33. data/lib/cosmos/io/json_drb_object.rb +22 -61
  34. data/lib/cosmos/io/json_drb_rack.rb +79 -0
  35. data/lib/cosmos/io/json_rpc.rb +27 -0
  36. data/lib/cosmos/io/udp_sockets.rb +102 -58
  37. data/lib/cosmos/packets/commands.rb +1 -1
  38. data/lib/cosmos/packets/structure.rb +1 -1
  39. data/lib/cosmos/packets/structure_item.rb +37 -5
  40. data/lib/cosmos/script/cmd_tlm_server.rb +76 -2
  41. data/lib/cosmos/script/replay.rb +60 -0
  42. data/lib/cosmos/script/script.rb +20 -2
  43. data/lib/cosmos/script/scripting.rb +9 -9
  44. data/lib/cosmos/script/tools.rb +14 -0
  45. data/lib/cosmos/system/system.rb +185 -92
  46. data/lib/cosmos/system/target.rb +1 -1
  47. data/lib/cosmos/tools/cmd_sequence/cmd_sequence.rb +44 -4
  48. data/lib/cosmos/tools/cmd_sequence/sequence_item.rb +4 -0
  49. data/lib/cosmos/tools/cmd_sequence/sequence_list.rb +7 -0
  50. data/lib/cosmos/tools/cmd_tlm_server/api.rb +347 -20
  51. data/lib/cosmos/tools/cmd_tlm_server/background_tasks.rb +3 -0
  52. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +329 -111
  53. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +13 -0
  54. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +261 -95
  55. data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +46 -35
  56. data/lib/cosmos/tools/cmd_tlm_server/gui/logging_tab.rb +18 -8
  57. data/lib/cosmos/tools/cmd_tlm_server/gui/packets_tab.rb +39 -28
  58. data/lib/cosmos/tools/cmd_tlm_server/gui/replay_tab.rb +242 -0
  59. data/lib/cosmos/tools/cmd_tlm_server/gui/status_tab.rb +24 -8
  60. data/lib/cosmos/tools/cmd_tlm_server/gui/targets_tab.rb +18 -6
  61. data/lib/cosmos/tools/cmd_tlm_server/limits_groups_background_task.rb +5 -4
  62. data/lib/cosmos/tools/cmd_tlm_server/replay_backend.rb +375 -0
  63. data/lib/cosmos/tools/cmd_tlm_server/routers.rb +10 -2
  64. data/lib/cosmos/tools/data_viewer/data_viewer.rb +40 -5
  65. data/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +18 -20
  66. data/lib/cosmos/tools/launcher/launcher_config.rb +5 -16
  67. data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +65 -39
  68. data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +19 -0
  69. data/lib/cosmos/tools/replay/replay.rb +5 -505
  70. data/lib/cosmos/tools/script_runner/script_audit.rb +1 -0
  71. data/lib/cosmos/tools/script_runner/script_runner.rb +3 -4
  72. data/lib/cosmos/tools/script_runner/script_runner_config.rb +3 -4
  73. data/lib/cosmos/tools/script_runner/script_runner_frame.rb +44 -23
  74. data/lib/cosmos/tools/test_runner/results_writer.rb +4 -0
  75. data/lib/cosmos/tools/test_runner/test_runner.rb +0 -3
  76. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +6 -2
  77. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tool.rb +26 -1
  78. data/lib/cosmos/tools/tlm_viewer/screen.rb +24 -1
  79. data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +25 -0
  80. data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +24 -14
  81. data/lib/cosmos/top_level.rb +34 -24
  82. data/lib/cosmos/utilities/csv.rb +60 -8
  83. data/lib/cosmos/version.rb +5 -5
  84. data/spec/config/config_parser_spec.rb +10 -1
  85. data/spec/core_ext/socket_spec.rb +4 -2
  86. data/spec/gui/utilities/script_module_gui_spec.rb +102 -0
  87. data/spec/install/config/data/data.txt +1 -0
  88. data/spec/install/config/targets/INST/cmd_tlm/inst_cmds.txt +2 -0
  89. data/spec/interfaces/cmd_tlm_server_interface_spec.rb +1 -2
  90. data/spec/interfaces/protocols/template_protocol_spec.rb +72 -2
  91. data/spec/interfaces/serial_interface_spec.rb +1 -1
  92. data/spec/interfaces/udp_interface_spec.rb +14 -0
  93. data/spec/io/buffered_file_spec.rb +37 -0
  94. data/spec/io/json_drb_object_spec.rb +2 -15
  95. data/spec/io/json_drb_spec.rb +61 -121
  96. data/spec/io/udp_sockets_spec.rb +42 -2
  97. data/spec/packet_logs/packet_log_reader_spec.rb +5 -2
  98. data/spec/packets/binary_accessor_spec.rb +1 -1
  99. data/spec/packets/packet_item_spec.rb +1 -1
  100. data/spec/packets/structure_item_spec.rb +5 -6
  101. data/spec/script/cmd_tlm_server_spec.rb +39 -4
  102. data/spec/script/commands_disconnect_spec.rb +1 -1
  103. data/spec/script/commands_spec.rb +2 -1
  104. data/spec/script/scripting_spec.rb +18 -3
  105. data/spec/script/telemetry_spec.rb +5 -0
  106. data/spec/spec_helper.rb +43 -26
  107. data/spec/streams/tcpip_socket_stream_spec.rb +2 -2
  108. data/spec/system/system_spec.rb +11 -9
  109. data/spec/system/target_spec.rb +3 -0
  110. data/spec/tools/cmd_tlm_server/api_spec.rb +543 -29
  111. data/spec/tools/cmd_tlm_server/background_task_spec.rb +2 -2
  112. data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +31 -75
  113. data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +199 -66
  114. data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +85 -9
  115. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +29 -127
  116. data/spec/tools/cmd_tlm_server/router_thread_spec.rb +10 -50
  117. data/spec/tools/launcher/launcher_config_spec.rb +1 -1
  118. data/spec/tools/table_manager/table_item_spec.rb +1 -1
  119. data/spec/tools/table_manager/tablemanager_core_spec.rb +4 -4
  120. data/spec/top_level/top_level_spec.rb +151 -3
  121. data/spec/utilities/csv_spec.rb +24 -5
  122. metadata +61 -9
  123. data/lib/cosmos/tools/replay/replay_server.rb +0 -91
@@ -19,7 +19,7 @@ module Cosmos
19
19
  #
20
20
  # This should not be confused with the Api module which implements the JSON
21
21
  # API that is used by tools when accessing the Server. The Api module always
22
- # provides Ruby primatives where the PacketDefinition class can return actual
22
+ # provides Ruby primatives where the PacketConfig class can return actual
23
23
  # Packet or PacketItem objects. While there are some overlapping methods between
24
24
  # the two, these are separate interfaces into the system.
25
25
  class Commands
@@ -198,7 +198,7 @@ module Cosmos
198
198
  # to re-sort. We also re-sort if the current item is less than the less
199
199
  # item because we are inserting.
200
200
  if last_item.bit_offset <= 0 or item.bit_offset <= 0 or item.bit_offset < last_item.bit_offset
201
- @sorted_items = @sorted_items.sort {|item1, item2| item1 <=> item2}
201
+ @sorted_items = @sorted_items.sort
202
202
  end
203
203
  else
204
204
  @sorted_items << item
@@ -17,6 +17,8 @@ module Cosmos
17
17
  class StructureItem
18
18
  include Comparable
19
19
 
20
+ @@create_index = 0
21
+
20
22
  # Valid data types adds :DERIVED to those defined by BinaryAccessor
21
23
  DATA_TYPES = BinaryAccessor::DATA_TYPES << :DERIVED
22
24
 
@@ -81,6 +83,8 @@ module Cosmos
81
83
  self.bit_size = bit_size
82
84
  self.array_size = array_size
83
85
  self.overflow = overflow
86
+ @create_index = @@create_index
87
+ @@create_index += 1
84
88
  @structure_item_constructed = true
85
89
  verify_overall()
86
90
  end
@@ -190,6 +194,10 @@ module Cosmos
190
194
  verify_overall() if @structure_item_constructed
191
195
  end
192
196
 
197
+ def create_index
198
+ @create_index.to_i
199
+ end
200
+
193
201
  if RUBY_ENGINE != 'ruby' or ENV['COSMOS_NO_EXT']
194
202
  # Comparison Operator based on bit_offset. This means that StructureItems
195
203
  # with different names or bit sizes are equal if they have the same bit
@@ -202,9 +210,17 @@ module Cosmos
202
210
  if (@bit_offset == 0) && (other_bit_offset == 0)
203
211
  # Both bit_offsets are 0 so sort by bit_size
204
212
  # This allows derived items with bit_size of 0 to be listed first
205
- # Compare based on bit size
213
+ # Compare based on bit size then create index
206
214
  if @bit_size == other_bit_size
207
- return 0
215
+ if @create_index
216
+ if @create_index <= other_item.create_index
217
+ return -1
218
+ else
219
+ return 1
220
+ end
221
+ else
222
+ return 0
223
+ end
208
224
  elsif @bit_size < other_bit_size
209
225
  return -1
210
226
  else
@@ -216,8 +232,16 @@ module Cosmos
216
232
  if ((@bit_offset >= 0) && (other_bit_offset >= 0)) || ((@bit_offset < 0) && (other_bit_offset < 0))
217
233
  # Both Have Same Sign
218
234
  if @bit_offset == other_bit_offset
219
- return 0
220
- elsif @bit_offset < other_bit_offset
235
+ if @create_index
236
+ if @create_index <= other_item.create_index
237
+ return -1
238
+ else
239
+ return 1
240
+ end
241
+ else
242
+ return 0
243
+ end
244
+ elsif @bit_offset <= other_bit_offset
221
245
  return -1
222
246
  else
223
247
  return 1
@@ -225,7 +249,15 @@ module Cosmos
225
249
  else
226
250
  # Different Signs
227
251
  if @bit_offset == other_bit_offset
228
- return 0
252
+ if @create_index
253
+ if @create_index < other_item.create_index
254
+ return -1
255
+ else
256
+ return 1
257
+ end
258
+ else
259
+ return 0
260
+ end
229
261
  elsif @bit_offset < other_bit_offset
230
262
  return 1
231
263
  else
@@ -57,14 +57,42 @@ module Cosmos
57
57
  return $cmd_tlm_server.get_target_info(target_name)
58
58
  end
59
59
 
60
+ def get_all_target_info
61
+ return $cmd_tlm_server.get_all_target_info
62
+ end
63
+
64
+ def get_target_ignored_parameters(target_name)
65
+ return $cmd_tlm_server.get_target_ignored_parameters(target_name)
66
+ end
67
+
68
+ def get_target_ignored_items(target_name)
69
+ return $cmd_tlm_server.get_target_ignored_items(target_name)
70
+ end
71
+
60
72
  def get_interface_info(interface_name)
61
73
  return $cmd_tlm_server.get_interface_info(interface_name)
62
74
  end
63
75
 
76
+ def get_all_router_info
77
+ return $cmd_tlm_server.get_all_router_info
78
+ end
79
+
80
+ def get_all_interface_info
81
+ return $cmd_tlm_server.get_all_interface_info
82
+ end
83
+
64
84
  def get_router_info(router_name)
65
85
  return $cmd_tlm_server.get_router_info(router_name)
66
86
  end
67
87
 
88
+ def get_all_cmd_info
89
+ return $cmd_tlm_server.get_all_cmd_info
90
+ end
91
+
92
+ def get_all_tlm_info
93
+ return $cmd_tlm_server.get_all_tlm_info
94
+ end
95
+
68
96
  def get_cmd_cnt(target_name, command_name)
69
97
  return $cmd_tlm_server.get_cmd_cnt(target_name, command_name)
70
98
  end
@@ -73,10 +101,34 @@ module Cosmos
73
101
  return $cmd_tlm_server.get_tlm_cnt(target_name, packet_name)
74
102
  end
75
103
 
104
+ def get_packet_loggers
105
+ return $cmd_tlm_server.get_packet_loggers
106
+ end
107
+
76
108
  def get_packet_logger_info(packet_logger_name)
77
109
  return $cmd_tlm_server.get_packet_logger_info(packet_logger_name)
78
110
  end
79
111
 
112
+ def get_all_packet_logger_info
113
+ return $cmd_tlm_server.get_all_packet_logger_info
114
+ end
115
+
116
+ def get_background_tasks
117
+ return $cmd_tlm_server.get_background_tasks
118
+ end
119
+
120
+ def start_background_task(task_name)
121
+ return $cmd_tlm_server.start_background_task(task_name)
122
+ end
123
+
124
+ def stop_background_task(task_name)
125
+ return $cmd_tlm_server.stop_background_task(task_name)
126
+ end
127
+
128
+ def get_server_status
129
+ return $cmd_tlm_server.get_server_status
130
+ end
131
+
80
132
  def get_cmd_log_filename(packet_log_writer_name = 'DEFAULT')
81
133
  return $cmd_tlm_server.get_cmd_log_filename(packet_log_writer_name)
82
134
  end
@@ -133,6 +185,28 @@ module Cosmos
133
185
  return $cmd_tlm_server.start_new_server_message_log
134
186
  end
135
187
 
136
- end # module Script
188
+ def subscribe_server_messages(queue_size = CmdTlmServer::DEFAULT_SERVER_MESSAGES_QUEUE_SIZE)
189
+ return $cmd_tlm_server.subscribe_server_messages(queue_size)
190
+ end
191
+
192
+ def unsubscribe_server_messages(id)
193
+ return $cmd_tlm_server.unsubscribe_server_messages(id)
194
+ end
195
+
196
+ def get_server_message(id, non_block = false)
197
+ return $cmd_tlm_server.get_server_message(id, non_block)
198
+ end
199
+
200
+ def cmd_tlm_reload
201
+ return $cmd_tlm_server.cmd_tlm_reload
202
+ end
203
+
204
+ def cmd_tlm_clear_counters
205
+ return $cmd_tlm_server.cmd_tlm_clear_counters
206
+ end
137
207
 
138
- end # module Cosmos
208
+ def get_output_logs_filenames(filter = '*tlm.bin')
209
+ return $cmd_tlm_server.get_output_logs_filenames(filter)
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2017 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 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
+ module Cosmos
12
+
13
+ module Script
14
+ private
15
+
16
+ def replay_select_file(filename, packet_log_reader = "DEFAULT")
17
+ $cmd_tlm_server.replay_select_file(filename, packet_log_reader)
18
+ end
19
+
20
+ def replay_status
21
+ $cmd_tlm_server.replay_status
22
+ end
23
+
24
+ def replay_set_playback_delay(delay)
25
+ $cmd_tlm_server.replay_set_playback_delay(delay)
26
+ end
27
+
28
+ def replay_play
29
+ $cmd_tlm_server.replay_play
30
+ end
31
+
32
+ def replay_reverse_play
33
+ $cmd_tlm_server.replay_reverse_play
34
+ end
35
+
36
+ def replay_stop
37
+ $cmd_tlm_server.replay_stop
38
+ end
39
+
40
+ def replay_step_forward
41
+ $cmd_tlm_server.replay_step_forward
42
+ end
43
+
44
+ def replay_step_back
45
+ $cmd_tlm_server.replay_step_back
46
+ end
47
+
48
+ def replay_move_start
49
+ $cmd_tlm_server.replay_move_start
50
+ end
51
+
52
+ def replay_move_end
53
+ $cmd_tlm_server.replay_move_end
54
+ end
55
+
56
+ def replay_move_index(index)
57
+ $cmd_tlm_server.replay_move_index(index)
58
+ end
59
+ end
60
+ end
@@ -12,6 +12,7 @@ require 'cosmos'
12
12
  require 'cosmos/io/json_drb_object'
13
13
  require 'cosmos/tools/cmd_tlm_server/cmd_tlm_server'
14
14
  require 'cosmos/script/cmd_tlm_server'
15
+ require 'cosmos/script/replay'
15
16
  require 'cosmos/script/commands'
16
17
  require 'cosmos/script/telemetry'
17
18
  require 'cosmos/script/limits'
@@ -20,6 +21,7 @@ require 'cosmos/script/tools'
20
21
 
21
22
  $cmd_tlm_server = nil
22
23
  $cmd_tlm_disconnect = false
24
+ $cmd_tlm_replay_mode = false
23
25
 
24
26
  module Cosmos
25
27
  class CheckError < RuntimeError; end
@@ -39,6 +41,7 @@ module Cosmos
39
41
  # Called when this module is mixed in using "include Cosmos::Script"
40
42
  def self.included(base)
41
43
  $cmd_tlm_disconnect = false
44
+ $cmd_tlm_replay_mode = false
42
45
  $cmd_tlm_server = nil
43
46
  initialize_script_module()
44
47
  end
@@ -48,8 +51,12 @@ module Cosmos
48
51
  # Start up a standalone CTS in disconnected mode
49
52
  $cmd_tlm_server = CmdTlmServer.new(config_file, false, true)
50
53
  else
51
- # Start a Json connect to the real CTS server
52
- $cmd_tlm_server = JsonDRbObject.new(System.connect_hosts['CTS_API'], System.ports['CTS_API'])
54
+ # Start a Json connect to the real server
55
+ if $cmd_tlm_replay_mode
56
+ $cmd_tlm_server = JsonDRbObject.new(System.connect_hosts['REPLAY_API'], System.ports['REPLAY_API'])
57
+ else
58
+ $cmd_tlm_server = JsonDRbObject.new(System.connect_hosts['CTS_API'], System.ports['CTS_API'])
59
+ end
53
60
  end
54
61
  end
55
62
 
@@ -72,5 +79,16 @@ module Cosmos
72
79
  $cmd_tlm_server.disconnect if $cmd_tlm_server && !$cmd_tlm_disconnect
73
80
  end
74
81
 
82
+ def set_replay_mode(replay_mode)
83
+ if replay_mode != $cmd_tlm_replay_mode
84
+ $cmd_tlm_replay_mode = replay_mode
85
+ initialize_script_module()
86
+ end
87
+ end
88
+
89
+ def get_replay_mode
90
+ $cmd_tlm_replay_mode
91
+ end
92
+
75
93
  end
76
94
  end
@@ -72,9 +72,9 @@ module Cosmos
72
72
  prompt_combo_box(string, options)
73
73
  end
74
74
 
75
- def _file_dialog(message, directory, select_files = true)
75
+ def _file_dialog(message, directory, filter, select_files = true)
76
76
  answer = ''
77
- files = Dir["#{directory}/*"]
77
+ files = Dir["#{directory}/#{filter}"]
78
78
  if select_files
79
79
  files.select! {|f| !File.directory? f }
80
80
  else
@@ -87,17 +87,17 @@ module Cosmos
87
87
  end
88
88
  return answer
89
89
  end
90
- def save_file_dialog(directory = Cosmos::USERPATH, message = "Save File")
91
- _file_dialog(message, directory)
90
+ def save_file_dialog(directory = Cosmos::USERPATH, message = "Save File", filter = "*")
91
+ _file_dialog(message, directory, filter)
92
92
  end
93
- def open_file_dialog(directory = Cosmos::USERPATH, message = "Open File")
94
- _file_dialog(message, directory)
93
+ def open_file_dialog(directory = Cosmos::USERPATH, message = "Open File", filter = "*")
94
+ _file_dialog(message, directory, filter)
95
95
  end
96
- def open_files_dialog(directory = Cosmos::USERPATH, message = "Open File(s)")
97
- _file_dialog(message, directory)
96
+ def open_files_dialog(directory = Cosmos::USERPATH, message = "Open File(s)", filter = "*")
97
+ _file_dialog(message, directory, filter)
98
98
  end
99
99
  def open_directory_dialog(directory = Cosmos::USERPATH, message = "Open Directory")
100
- _file_dialog(message, directory, false)
100
+ _file_dialog(message, directory, "*", false)
101
101
  end
102
102
 
103
103
  def prompt_for_hazardous(target_name, cmd_name, hazardous_description)
@@ -92,6 +92,20 @@ module Cosmos
92
92
  end
93
93
  end
94
94
 
95
+ ###########################
96
+ # Telemetry Screen methods
97
+ ###########################
98
+
99
+ # Get the organized list of available telemetry screens
100
+ def get_screen_list(config_filename = nil, force_refresh = false)
101
+ $cmd_tlm_server.get_screen_list(config_filename, force_refresh)
102
+ end
103
+
104
+ # Get a specific screen definition
105
+ def get_screen_definition(screen_full_name, config_filename = nil, force_refresh = false)
106
+ $cmd_tlm_server.get_screen_definition(screen_full_name, config_filename, force_refresh)
107
+ end
108
+
95
109
  end # module Script
96
110
 
97
111
  end # module Cosmos
@@ -17,6 +17,8 @@ require 'cosmos/system/target'
17
17
  require 'cosmos/packet_logs'
18
18
  require 'fileutils'
19
19
  require 'drb/acl'
20
+ require 'zip'
21
+ require 'zip/filesystem'
20
22
  require 'bundler'
21
23
 
22
24
  module Cosmos
@@ -52,7 +54,7 @@ module Cosmos
52
54
  # @return [String] Stores the initial configuration file used when this
53
55
  # System was initialized
54
56
  instance_attr_reader :initial_filename
55
- # @return [PacketDefinition] Stores the initial packet list used when this
57
+ # @return [PacketConfig] Stores the initial packet list used when this
56
58
  # System was initialized
57
59
  instance_attr_reader :initial_config
58
60
  # @return [ACL] Access control list showing which machines can have access
@@ -71,9 +73,9 @@ module Cosmos
71
73
  instance_attr_reader :additional_md5_files
72
74
 
73
75
  # Known COSMOS ports
74
- KNOWN_PORTS = ['CTS_API', 'TLMVIEWER_API', 'CTS_PREIDENTIFIED', 'CTS_CMD_ROUTER']
76
+ KNOWN_PORTS = ['CTS_API', 'TLMVIEWER_API', 'CTS_PREIDENTIFIED', 'CTS_CMD_ROUTER', 'REPLAY_API', 'REPLAY_PREIDENTIFIED', 'REPLAY_CMD_ROUTER']
75
77
  # Known COSMOS hosts
76
- KNOWN_HOSTS = ['CTS_API', 'TLMVIEWER_API', 'CTS_PREIDENTIFIED', 'CTS_CMD_ROUTER']
78
+ KNOWN_HOSTS = ['CTS_API', 'TLMVIEWER_API', 'CTS_PREIDENTIFIED', 'CTS_CMD_ROUTER', 'REPLAY_API', 'REPLAY_PREIDENTIFIED', 'REPLAY_CMD_ROUTER']
77
79
  # Known COSMOS paths
78
80
  KNOWN_PATHS = ['LOGS', 'TMP', 'SAVED_CONFIG', 'TABLES', 'HANDBOOKS', 'PROCEDURES', 'SEQUENCES']
79
81
 
@@ -88,69 +90,7 @@ module Cosmos
88
90
  # read. Be default this is <Cosmos::USERPATH>/config/system/system.txt
89
91
  def initialize(filename = nil)
90
92
  raise "Cosmos::System created twice" unless @@instance.nil?
91
- @targets = {}
92
- @targets['UNKNOWN'] = Target.new('UNKNOWN')
93
- @config = nil
94
- @commands = nil
95
- @telemetry = nil
96
- @limits = nil
97
- @default_packet_log_writer = PacketLogWriter
98
- @default_packet_log_writer_params = []
99
- @default_packet_log_reader = PacketLogReader
100
- @default_packet_log_reader_params = []
101
- @sound = false
102
- @use_dns = false
103
- @acl = nil
104
- @staleness_seconds = 30
105
- @limits_set = :DEFAULT
106
- @use_utc = false
107
- @additional_md5_files = []
108
- @meta_init_filename = nil
109
-
110
- @ports = {}
111
- @ports['CTS_API'] = 7777
112
- @ports['TLMVIEWER_API'] = 7778
113
- @ports['CTS_PREIDENTIFIED'] = 7779
114
- @ports['CTS_CMD_ROUTER'] = 7780
115
-
116
- @listen_hosts = {}
117
- @listen_hosts['CTS_API'] = '127.0.0.1'
118
- @listen_hosts['TLMVIEWER_API'] = '127.0.0.1'
119
- # Localhost would be more secure but historically these are open to allow for chaining servers by default
120
- @listen_hosts['CTS_PREIDENTIFIED'] = '0.0.0.0'
121
- @listen_hosts['CTS_CMD_ROUTER'] = '0.0.0.0'
122
-
123
- @connect_hosts = {}
124
- @connect_hosts['CTS_API'] = '127.0.0.1'
125
- @connect_hosts['TLMVIEWER_API'] = '127.0.0.1'
126
- @connect_hosts['CTS_PREIDENTIFIED'] = '127.0.0.1'
127
- @connect_hosts['CTS_CMD_ROUTER'] = '127.0.0.1'
128
-
129
- @paths = {}
130
- @paths['LOGS'] = File.join(USERPATH, 'outputs', 'logs')
131
- @paths['TMP'] = File.join(USERPATH, 'outputs', 'tmp')
132
- @paths['SAVED_CONFIG'] = File.join(USERPATH, 'outputs', 'saved_config')
133
- @paths['TABLES'] = File.join(USERPATH, 'outputs', 'tables')
134
- @paths['HANDBOOKS'] = File.join(USERPATH, 'outputs', 'handbooks')
135
- @paths['PROCEDURES'] = [File.join(USERPATH, 'procedures')]
136
- @paths['SEQUENCES'] = File.join(USERPATH, 'outputs', 'sequences')
137
-
138
- unless filename
139
- system_arg = false
140
- ARGV.each do |arg|
141
- if system_arg
142
- filename = File.join(USERPATH, 'config', 'system', arg)
143
- break
144
- end
145
- system_arg = true if arg == '--system'
146
- end
147
- filename = File.join(USERPATH, 'config', 'system', 'system.txt') unless filename
148
- end
149
- process_file(filename)
150
- ENV['COSMOS_LOGS_DIR'] = @paths['LOGS']
151
-
152
- @initial_filename = filename
153
- @initial_config = nil
93
+ reset_variables(filename)
154
94
  @@instance = self
155
95
  end
156
96
 
@@ -489,6 +429,8 @@ module Cosmos
489
429
  end # parser.parse_file
490
430
  end
491
431
 
432
+
433
+
492
434
  # Load the specified configuration by iterating through the SAVED_CONFIG
493
435
  # directory looking for a matching MD5 sum. Updates the internal state so
494
436
  # subsequent commands and telemetry methods return the new configuration.
@@ -507,12 +449,16 @@ module Cosmos
507
449
  update_config(@initial_config)
508
450
  else
509
451
  # Look for the requested configuration in the saved configurations
510
- configuration_directory = find_configuration(name)
511
- if configuration_directory
452
+ configuration = find_configuration(name)
453
+ if configuration
512
454
  # We found the configuration requested. Reprocess the system.txt
513
455
  # and reload the packets
514
456
  begin
515
- process_file(File.join(configuration_directory, 'system.txt'), configuration_directory)
457
+ unless File.directory?(configuration)
458
+ # Zip file configuration so unzip and reset configuration path
459
+ configuration = unzip(configuration)
460
+ end
461
+ process_file(File.join(configuration, 'system.txt'), configuration)
516
462
  load_packets(name)
517
463
  rescue Exception => error
518
464
  # Failed to load - Restore initial
@@ -539,8 +485,145 @@ module Cosmos
539
485
  return self.instance.load_configuration(name)
540
486
  end
541
487
 
488
+ # Resets the System's internal state to defaults.
489
+ #
490
+ # @params [String] Path to system.txt config file to process. Defaults to config/system/system.txt
491
+ def reset_variables(filename = nil)
492
+ @targets = {}
493
+ @targets['UNKNOWN'] = Target.new('UNKNOWN')
494
+ @config = nil
495
+ @commands = nil
496
+ @telemetry = nil
497
+ @limits = nil
498
+ @default_packet_log_writer = PacketLogWriter
499
+ @default_packet_log_writer_params = []
500
+ @default_packet_log_reader = PacketLogReader
501
+ @default_packet_log_reader_params = []
502
+ @sound = false
503
+ @use_dns = false
504
+ @acl = nil
505
+ @staleness_seconds = 30
506
+ @limits_set = :DEFAULT
507
+ @use_utc = false
508
+ @additional_md5_files = []
509
+ @meta_init_filename = nil
510
+
511
+ @ports = {}
512
+ @ports['CTS_API'] = 7777
513
+ @ports['TLMVIEWER_API'] = 7778
514
+ @ports['CTS_PREIDENTIFIED'] = 7779
515
+ @ports['CTS_CMD_ROUTER'] = 7780
516
+ @ports['REPLAY_API'] = 7877
517
+ @ports['REPLAY_PREIDENTIFIED'] = 7879
518
+ @ports['REPLAY_CMD_ROUTER'] = 7880
519
+
520
+ @listen_hosts = {}
521
+ @listen_hosts['CTS_API'] = '127.0.0.1'
522
+ @listen_hosts['TLMVIEWER_API'] = '127.0.0.1'
523
+ # Localhost would be more secure but historically these are open to allow for chaining servers by default
524
+ @listen_hosts['CTS_PREIDENTIFIED'] = '0.0.0.0'
525
+ @listen_hosts['CTS_CMD_ROUTER'] = '0.0.0.0'
526
+ @listen_hosts['REPLAY_API'] = '127.0.0.1'
527
+ # Localhost would be more secure but historically these are open to allow for chaining servers by default
528
+ @listen_hosts['REPLAY_PREIDENTIFIED'] = '0.0.0.0'
529
+ @listen_hosts['REPLAY_CMD_ROUTER'] = '0.0.0.0'
530
+
531
+ @connect_hosts = {}
532
+ @connect_hosts['CTS_API'] = '127.0.0.1'
533
+ @connect_hosts['TLMVIEWER_API'] = '127.0.0.1'
534
+ @connect_hosts['CTS_PREIDENTIFIED'] = '127.0.0.1'
535
+ @connect_hosts['CTS_CMD_ROUTER'] = '127.0.0.1'
536
+ @connect_hosts['REPLAY_API'] = '127.0.0.1'
537
+ @connect_hosts['REPLAY_PREIDENTIFIED'] = '127.0.0.1'
538
+ @connect_hosts['REPLAY_CMD_ROUTER'] = '127.0.0.1'
539
+
540
+ @paths = {}
541
+ @paths['LOGS'] = File.join(USERPATH, 'outputs', 'logs')
542
+ @paths['TMP'] = File.join(USERPATH, 'outputs', 'tmp')
543
+ @paths['SAVED_CONFIG'] = File.join(USERPATH, 'outputs', 'saved_config')
544
+ @paths['TABLES'] = File.join(USERPATH, 'outputs', 'tables')
545
+ @paths['HANDBOOKS'] = File.join(USERPATH, 'outputs', 'handbooks')
546
+ @paths['PROCEDURES'] = [File.join(USERPATH, 'procedures')]
547
+ @paths['SEQUENCES'] = File.join(USERPATH, 'outputs', 'sequences')
548
+
549
+ unless filename
550
+ system_arg = false
551
+ ARGV.each do |arg|
552
+ if system_arg
553
+ filename = File.join(USERPATH, 'config', 'system', arg)
554
+ break
555
+ end
556
+ system_arg = true if arg == '--system'
557
+ end
558
+ filename = File.join(USERPATH, 'config', 'system', 'system.txt') unless filename
559
+ end
560
+ process_file(filename)
561
+ ENV['COSMOS_LOGS_DIR'] = @paths['LOGS']
562
+
563
+ @initial_filename = filename
564
+ @initial_config = nil
565
+ end
566
+
567
+ # Reset variables and load packets
568
+ def reset(filename = nil)
569
+ reset_variables(filename)
570
+ load_packets()
571
+ end
572
+
573
+ # Class level convenience reset method
574
+ def self.reset
575
+ self.instance.reset
576
+ end
577
+
542
578
  protected
543
579
 
580
+ def unzip(zip_file)
581
+ zip_dir = File.join(@paths['TMP'], File.basename(zip_file, ".*"))
582
+ # Only unzip if we have to. We assume the unzipped directory structure is
583
+ # intact. If not they'll get a popop with the errors encountered when
584
+ # loading the configuration.
585
+ unless File.exist? zip_dir
586
+ Zip::File.open(zip_file) do |zip_file|
587
+ zip_file.each do |entry|
588
+ path = File.join(@paths['TMP'], entry.name)
589
+ FileUtils.mkdir_p(File.dirname(path))
590
+ zip_file.extract(entry, path) unless File.exist?(path)
591
+ end
592
+ end
593
+ end
594
+ zip_dir
595
+ end
596
+
597
+ # A helper method to make the zip writing recursion work
598
+ def write_zip_entries(base_dir, entries, zip_path, io)
599
+ io.add(zip_path, base_dir) # Add the directory whether it has entries or not
600
+ entries.each do |e|
601
+ zip_file_path = File.join(zip_path, e)
602
+ disk_file_path = File.join(base_dir, e)
603
+ if File.directory? disk_file_path
604
+ recursively_deflate_directory(disk_file_path, io, zip_file_path)
605
+ else
606
+ put_into_archive(disk_file_path, io, zip_file_path)
607
+ end
608
+ end
609
+ end
610
+
611
+ def recursively_deflate_directory(disk_file_path, io, zip_file_path)
612
+ io.add(zip_file_path, disk_file_path)
613
+ entries = Dir.entries(disk_file_path) - %w(. ..)
614
+ write_zip_entries(disk_file_path, entries, zip_file_path, io)
615
+ end
616
+
617
+ def put_into_archive(disk_file_path, io, zip_file_path)
618
+ io.get_output_stream(zip_file_path) do |f|
619
+ data = nil
620
+ File.open(disk_file_path, 'rb') do |file|
621
+ data = file.read
622
+ end
623
+ f.write(data)
624
+ end
625
+ end
626
+
544
627
  def auto_detect_gem_based_targets
545
628
  Bundler.load.specs.each do |spec|
546
629
  spec_name_split = spec.name.split('-')
@@ -577,7 +660,7 @@ module Cosmos
577
660
  Cosmos.set_working_dir do
578
661
  Dir.foreach(@paths['SAVED_CONFIG']) do |filename|
579
662
  full_path = File.join(@paths['SAVED_CONFIG'], filename)
580
- if Dir.exist?(full_path) && (filename[-32..-1] == name)
663
+ if File.exist?(full_path) && File.basename(filename, ".*")[-32..-1] == name
581
664
  return full_path
582
665
  end
583
666
  end
@@ -587,35 +670,45 @@ module Cosmos
587
670
 
588
671
  def save_configuration
589
672
  Cosmos.set_working_dir do
590
- configuration_directory = find_configuration(@config.name)
591
- configuration_directory = File.join(@paths['SAVED_CONFIG'], File.build_timestamped_filename([@config.name], '')) unless configuration_directory
592
- unless Dir.exist?(configuration_directory)
673
+ configuration = find_configuration(@config.name)
674
+ configuration = File.join(@paths['SAVED_CONFIG'], File.build_timestamped_filename([@config.name], '.zip')) unless configuration
675
+ unless File.exist?(configuration)
593
676
  begin
594
- # Create the directory
595
- FileUtils.mkdir_p(configuration_directory)
596
-
597
- # Copy target files into directory
598
- @targets.each do |target_name, target|
599
- destination_dir = File.join(configuration_directory, target.original_name)
600
- unless Dir.exist?(destination_dir)
601
- FileUtils.cp_r(target.dir, destination_dir)
602
- end
603
- end
677
+ Zip.continue_on_exists_proc = true
678
+ Zip::File.open(configuration, Zip::File::CREATE) do |zipfile|
679
+ zip_file_path = File.basename(configuration, ".zip")
680
+ zipfile.mkdir zip_file_path
604
681
 
605
- # Create custom system.txt file
606
- File.open(File.join(configuration_directory, 'system.txt'), 'w') do |file|
682
+ # Copy target files into archive
683
+ zip_targets = []
607
684
  @targets.each do |target_name, target|
608
- target_filename = File.basename(target.filename)
609
- target_filename = nil unless File.exist?(target.filename)
610
- if target.substitute
611
- file.puts "DECLARE_TARGET #{target.original_name} #{target.name} #{target_filename}"
612
- else
613
- file.puts "DECLARE_TARGET #{target.name} nil #{target_filename}"
685
+ entries = Dir.entries(target.dir) - %w(. ..)
686
+ zip_target = File.join(zip_file_path, target.original_name)
687
+ # Check the stored list of targets. We can't ask the zip file
688
+ # itself because it's in progress and hasn't been saved
689
+ unless zip_targets.include?(zip_target)
690
+ write_zip_entries(target.dir, entries, zip_target, zipfile)
691
+ zip_targets << zip_target
692
+ end
693
+ end
694
+
695
+ # Create custom system.txt file
696
+ zipfile.get_output_stream(File.join(zip_file_path, 'system.txt')) do |file|
697
+ @targets.each do |target_name, target|
698
+ target_filename = File.basename(target.filename)
699
+ target_filename = nil unless File.exist?(target.filename)
700
+ # Create a newline character since Zip opens files in binary mode
701
+ newline = Kernel.is_windows? ? "\r\n" : "\n"
702
+ if target.substitute
703
+ file.write "DECLARE_TARGET #{target.original_name} #{target.name} #{target_filename}#{newline}"
704
+ else
705
+ file.write "DECLARE_TARGET #{target.name} nil #{target_filename}#{newline}"
706
+ end
614
707
  end
615
708
  end
616
709
  end
617
710
  rescue Exception => error
618
- Logger.error "Problem saving configuration to #{configuration_directory}: #{error.class}:#{error.message}"
711
+ Logger.error "Problem saving configuration to #{configuration}: #{error.class}:#{error.message}\n#{error.backtrace.join("\n")}\n"
619
712
  end
620
713
  end
621
714
  end