cosmos 4.0.3-java → 4.1.0-java

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 (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 +12 -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