cosmos 4.4.1-java → 4.5.2-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build_v4.yml +33 -0
  3. data/Dockerfile +10 -4
  4. data/Gemfile +1 -1
  5. data/Manifest.txt +26 -2
  6. data/README.md +4 -1
  7. data/Rakefile +33 -27
  8. data/autohotkey/tools/cmd_extractor.ahk +11 -9
  9. data/autohotkey/tools/cmd_sender.ahk +1 -1
  10. data/autohotkey/tools/cmd_sequence.ahk +1 -1
  11. data/autohotkey/tools/data_viewer.ahk +1 -1
  12. data/autohotkey/tools/limits_monitor.ahk +1 -1
  13. data/autohotkey/tools/packet_viewer.ahk +1 -1
  14. data/autohotkey/tools/script_runner.ahk +1 -1
  15. data/autohotkey/tools/test_runner2.ahk +1 -1
  16. data/autohotkey/tools/tlm_grapher.ahk +1 -1
  17. data/autohotkey/tools/tlm_grapher3.ahk +1 -1
  18. data/autohotkey/tools/tlm_viewer.ahk +1 -1
  19. data/autohotkey/tools/tlm_viewer2.ahk +1 -1
  20. data/autohotkey/tools/tlm_viewer5.ahk +1 -1
  21. data/bin/rubysloc +73 -28
  22. data/bin/xtce_converter +1 -1
  23. data/cosmos.gemspec +6 -12
  24. data/data/config/interface_modifiers.yaml +3 -2
  25. data/data/config/system.yaml +81 -24
  26. data/data/crc.txt +435 -435
  27. data/demo/Rakefile +4 -4
  28. data/demo/config/data/crc.txt +250 -250
  29. data/demo/config/system/system.txt +15 -7
  30. data/demo/config/system/system2.txt +15 -7
  31. data/demo/config/system/system_alt_ports.txt +15 -7
  32. data/demo/config/targets/INST/cmd_tlm/inst_cmds.txt +1 -1
  33. data/demo/config/tools/handbook_creator/default_toc.xsl +59 -59
  34. data/ext/cosmos/ext/buffered_file/buffered_file.c +2 -2
  35. data/ext/cosmos/ext/config_parser/config_parser.c +1 -2
  36. data/ext/cosmos/ext/line_graph/line_graph.c +53 -94
  37. data/ext/cosmos/ext/packet/packet.c +0 -6
  38. data/ext/cosmos/ext/platform/platform.c +56 -21
  39. data/ext/cosmos/ext/polynomial_conversion/polynomial_conversion.c +4 -8
  40. data/ext/cosmos/ext/structure/structure.c +12 -0
  41. data/extensions/vscode/.gitignore +4 -0
  42. data/extensions/vscode/.vscode/launch.json +32 -0
  43. data/extensions/vscode/.vscode/settings.json +13 -0
  44. data/extensions/vscode/.vscode/tasks.json +79 -0
  45. data/extensions/vscode/License.txt +879 -0
  46. data/extensions/vscode/README.md +9 -0
  47. data/extensions/vscode/client/License.txt +879 -0
  48. data/extensions/vscode/client/README.md +39 -0
  49. data/extensions/vscode/client/cosmos.configuration.json +23 -0
  50. data/extensions/vscode/client/images/icon.png +0 -0
  51. data/extensions/vscode/client/package-lock.json +414 -0
  52. data/extensions/vscode/client/package.json +105 -0
  53. data/extensions/vscode/client/src/extension.ts +132 -0
  54. data/extensions/vscode/client/src/screen_preview.rb +25 -0
  55. data/extensions/vscode/client/syntaxes/cosmos.tmLanguage.json +219 -0
  56. data/extensions/vscode/client/tsconfig.json +17 -0
  57. data/extensions/vscode/package-lock.json +26 -0
  58. data/extensions/vscode/package.json +35 -0
  59. data/extensions/vscode/server/License.txt +879 -0
  60. data/extensions/vscode/server/package-lock.json +236 -0
  61. data/extensions/vscode/server/package.json +29 -0
  62. data/extensions/vscode/server/src/server.ts +59 -0
  63. data/extensions/vscode/server/tsconfig.json +16 -0
  64. data/install/Rakefile +4 -4
  65. data/install/config/data/crc.txt +145 -145
  66. data/install/config/system/system.txt +15 -7
  67. data/install/config/tools/handbook_creator/default_toc.xsl +59 -59
  68. data/lib/cosmos/config/config_parser.rb +2 -10
  69. data/lib/cosmos/core_ext/class.rb +10 -0
  70. data/lib/cosmos/core_ext/time.rb +5 -3
  71. data/lib/cosmos/dart/examples/dart_decom_client.rb +1 -1
  72. data/lib/cosmos/dart/lib/dart_common.rb +3 -3
  73. data/lib/cosmos/dart/lib/dart_decommutator.rb +4 -4
  74. data/lib/cosmos/dart/processes/dart_decom_server.rb +1 -1
  75. data/lib/cosmos/dart/processes/dart_master.rb +1 -1
  76. data/lib/cosmos/dart/spec/dart/dart_database_cleaner_spec.rb +2 -2
  77. data/lib/cosmos/gui/qt.rb +10 -10
  78. data/lib/cosmos/gui/qt_tool.rb +17 -12
  79. data/lib/cosmos/gui/text/completion_text_edit.rb +2 -0
  80. data/lib/cosmos/gui/widgets/dart_meta_frame.rb +1 -1
  81. data/lib/cosmos/interfaces/dart_status_interface.rb +1 -1
  82. data/lib/cosmos/interfaces/linc_interface.rb +3 -3
  83. data/lib/cosmos/interfaces/protocols/burst_protocol.rb +1 -1
  84. data/lib/cosmos/interfaces/protocols/crc_protocol.rb +1 -1
  85. data/lib/cosmos/interfaces/protocols/template_protocol.rb +3 -3
  86. data/lib/cosmos/interfaces/serial_interface.rb +7 -1
  87. data/lib/cosmos/interfaces/stream_interface.rb +1 -1
  88. data/lib/cosmos/interfaces/tcpip_server_interface.rb +16 -16
  89. data/lib/cosmos/io/io_multiplexer.rb +6 -2
  90. data/lib/cosmos/io/json_drb.rb +3 -11
  91. data/lib/cosmos/io/json_drb_object.rb +7 -2
  92. data/lib/cosmos/io/json_drb_rack.rb +25 -5
  93. data/lib/cosmos/io/json_rpc.rb +1 -1
  94. data/lib/cosmos/io/posix_serial_driver.rb +60 -22
  95. data/lib/cosmos/io/serial_driver.rb +11 -8
  96. data/lib/cosmos/io/win32_serial_driver.rb +8 -1
  97. data/lib/cosmos/packets/packet.rb +8 -8
  98. data/lib/cosmos/packets/packet_config.rb +1 -1
  99. data/lib/cosmos/packets/packet_item_limits.rb +2 -14
  100. data/lib/cosmos/packets/parsers/xtce_converter.rb +10 -10
  101. data/lib/cosmos/packets/parsers/xtce_parser.rb +3 -0
  102. data/lib/cosmos/packets/structure.rb +18 -5
  103. data/lib/cosmos/packets/structure_item.rb +4 -21
  104. data/lib/cosmos/script/api_shared.rb +18 -1
  105. data/lib/cosmos/script/extract.rb +1 -1
  106. data/lib/cosmos/script/script.rb +4 -11
  107. data/lib/cosmos/streams/serial_stream.rb +11 -6
  108. data/lib/cosmos/system/system.rb +47 -13
  109. data/lib/cosmos/tools/cmd_sender/cmd_param_table_item_delegate.rb +15 -0
  110. data/lib/cosmos/tools/cmd_sender/cmd_params.rb +25 -3
  111. data/lib/cosmos/tools/cmd_sender/cmd_sender.rb +7 -0
  112. data/lib/cosmos/tools/cmd_sequence/sequence_item.rb +0 -5
  113. data/lib/cosmos/tools/cmd_tlm_server/api.rb +10 -8
  114. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +2 -2
  115. data/lib/cosmos/tools/cmd_tlm_server/gui/logging_tab.rb +1 -1
  116. data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +29 -26
  117. data/lib/cosmos/tools/cmd_tlm_server/limits_groups_background_task.rb +1 -1
  118. data/lib/cosmos/tools/cmd_tlm_server/router_thread.rb +5 -0
  119. data/lib/cosmos/tools/config_editor/config_editor.rb +1 -1
  120. data/lib/cosmos/tools/handbook_creator/handbook_creator.rb +1 -1
  121. data/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +1 -1
  122. data/lib/cosmos/tools/script_runner/script_runner_frame.rb +5 -2
  123. data/lib/cosmos/tools/test_runner/test.rb +1 -1
  124. data/lib/cosmos/tools/test_runner/test_runner.rb +4 -4
  125. data/lib/cosmos/tools/tlm_extractor/tlm_extractor.rb +3 -3
  126. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_config.rb +1 -4
  127. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_processor.rb +3 -3
  128. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_dart_thread.rb +1 -1
  129. data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +2 -2
  130. data/lib/cosmos/tools/tlm_viewer/widgets/canvasdot_widget.rb +2 -0
  131. data/lib/cosmos/top_level.rb +1 -1
  132. data/lib/cosmos/utilities/simulated_target.rb +1 -1
  133. data/lib/cosmos/version.rb +5 -5
  134. data/make_gems.sh +1 -1
  135. data/spec/core_ext/class_spec.rb +54 -0
  136. data/spec/core_ext/time_spec.rb +4 -0
  137. data/spec/gui/qt_spec.rb +1 -1
  138. data/spec/gui/utilities/script_module_gui_spec.rb +1 -1
  139. data/spec/interfaces/linc_interface_spec.rb +1 -1
  140. data/spec/interfaces/serial_interface_spec.rb +1 -5
  141. data/spec/io/json_drb_rack_spec.rb +166 -0
  142. data/spec/io/json_rpc_spec.rb +4 -5
  143. data/spec/io/posix_serial_driver_spec.rb +87 -0
  144. data/spec/io/win32_serial_driver_spec.rb +17 -1
  145. data/spec/packet_logs/packet_log_reader_spec.rb +34 -35
  146. data/spec/packets/packet_item_limits_spec.rb +6 -33
  147. data/spec/packets/structure_item_spec.rb +3 -21
  148. data/spec/script/extract_spec.rb +4 -1
  149. data/spec/system/system_spec.rb +109 -1
  150. data/spec/tools/cmd_tlm_server/api_spec.rb +12 -12
  151. data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +2 -2
  152. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +4 -3
  153. data/spec/tools/cmd_tlm_server/router_thread_spec.rb +2 -3
  154. data/spec/top_level/top_level_spec.rb +2 -2
  155. data/spec/utilities/logger_spec.rb +3 -3
  156. data/test/performance/Rakefile +4 -4
  157. data/test/performance/config/data/crc.txt +67 -48
  158. metadata +53 -9
  159. data/.coveralls.yml +0 -1
  160. data/.travis.yml +0 -16
@@ -25,7 +25,7 @@ Cosmos.catch_fatal_exception do
25
25
  json_drb.method_whitelist = ['query', 'item_names', 'dart_status', 'clear_errors']
26
26
  begin
27
27
  json_drb.start_service(Cosmos::System.listen_hosts['DART_DECOM'],
28
- Cosmos::System.ports['DART_DECOM'], DartDecomQuery.new)
28
+ Cosmos::System.ports['DART_DECOM'], DartDecomQuery.new, 1000, Cosmos::System)
29
29
  rescue Exception => error
30
30
  raise Cosmos::FatalError.new("Error starting JsonDRb on port #{Cosmos::System.ports['DART_DECOM']}.\nPerhaps another DART Decom Server is already running?\n#{error.formatted}")
31
31
  end
@@ -29,7 +29,7 @@ Cosmos.catch_fatal_exception do
29
29
  json_drb.method_whitelist = ['get_decom_ple_ids']
30
30
  begin
31
31
  json_drb.start_service(Cosmos::System.listen_hosts['DART_MASTER'],
32
- Cosmos::System.ports['DART_MASTER'], DartMasterQuery.new(ples_per_request))
32
+ Cosmos::System.ports['DART_MASTER'], DartMasterQuery.new(ples_per_request), 1000, Cosmos::System)
33
33
  rescue Exception => error
34
34
  raise Cosmos::FatalError.new("Error starting JsonDRb on port #{Cosmos::System.ports['DART_MASTER']}.\nPerhaps another DART Master is already running?\n#{error.formatted}")
35
35
  end
@@ -189,7 +189,7 @@ describe DartDatabaseCleaner do
189
189
  end
190
190
  model.reset_column_information
191
191
  model_name = table_name.upcase
192
- Cosmos.send(:remove_const, model_name) if Cosmos.const_defined?(model_name)
192
+ Cosmos.public_send(:remove_const, model_name) if Cosmos.const_defined?(model_name)
193
193
  Cosmos.const_set(model_name, model)
194
194
 
195
195
  expect(model.column_names).to include("delete_me")
@@ -205,7 +205,7 @@ describe DartDatabaseCleaner do
205
205
  end
206
206
  model.reset_column_information
207
207
  model_name = table_name.upcase
208
- Cosmos.send(:remove_const, model_name) if Cosmos.const_defined?(model_name)
208
+ Cosmos.public_send(:remove_const, model_name) if Cosmos.const_defined?(model_name)
209
209
  Cosmos.const_set(model_name, model)
210
210
 
211
211
  expect(model.column_names).to include("delete_me")
data/lib/cosmos/gui/qt.rb CHANGED
@@ -101,22 +101,22 @@ module Cosmos
101
101
  return color_r if (color_r.is_a? Qt::Color) || (color_r.is_a? Qt::Pen) || (color_r.is_a? Qt::LinearGradient)
102
102
 
103
103
  color = nil
104
- key = color_r
105
- key = key.to_i if key.is_a? Qt::Enum
104
+ color_key = color_r
105
+ color_key = color_key.to_i if color_key.is_a? Qt::Enum
106
106
 
107
107
  if color_r && color_g && color_b
108
- key = (color_r.to_i << 24) + (color_g.to_i << 16) + (color_b.to_i << 8)
108
+ color_key = (color_r.to_i << 24) + (color_g.to_i << 16) + (color_b.to_i << 8)
109
109
  end
110
110
 
111
- if Cosmos::COLORS[key]
112
- color = Cosmos::COLORS[key]
111
+ if Cosmos::COLORS[color_key]
112
+ color = Cosmos::COLORS[color_key]
113
113
  else
114
114
  if color_r && color_g && color_b
115
115
  color = Qt::Color.new(color_r.to_i, color_g.to_i, color_b.to_i)
116
116
  else
117
117
  color = Qt::Color.new(color_r)
118
118
  end
119
- Cosmos::COLORS[key] = color
119
+ Cosmos::COLORS[color_key] = color
120
120
  end
121
121
  color
122
122
  end
@@ -214,12 +214,12 @@ module Cosmos
214
214
  end
215
215
 
216
216
  def self.getCursor(shape)
217
- key = shape
218
- key = shape.to_i if shape.is_a? Qt::Enum
219
- cursor = CURSORS[key]
217
+ shape_key = shape
218
+ shape_key = shape.to_i if shape.is_a? Qt::Enum
219
+ cursor = CURSORS[shape_key]
220
220
  unless cursor
221
221
  cursor = Qt::Cursor.new(shape)
222
- CURSORS[key] = cursor
222
+ CURSORS[shape_key] = cursor
223
223
  end
224
224
  cursor
225
225
  end
@@ -61,6 +61,7 @@ module Cosmos
61
61
  @stylesheet = File.read(app_style) if File.exist? app_style
62
62
 
63
63
  self.class.normalize_config_options(@options)
64
+ setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint) if @options.stay_on_top
64
65
 
65
66
  # Add a banner based on system configuration
66
67
  add_classification_banner
@@ -82,7 +83,7 @@ module Cosmos
82
83
  else
83
84
  options.config_file = nil
84
85
  options.stylesheet = nil
85
- end
86
+ end
86
87
  end
87
88
 
88
89
  # Creates a path to a configuration file. If the file is given it is
@@ -209,28 +210,26 @@ module Cosmos
209
210
 
210
211
  # Handle manually positioning the window
211
212
  unless @options.auto_position
212
- # Get the desktop's geometry
213
- desktop = Qt::Application.desktop
214
-
215
- # Handle position relative to right edge
216
- @options.x = desktop.width - frameGeometry().width + @options.x + 1 if @options.x < 0
217
-
218
- # Handle position relative to bottom edge
219
- @options.y = desktop.height - frameGeometry().height + @options.y + 1 if @options.y < 0
220
-
221
213
  # Move to the desired position
222
214
  move(@options.x, @options.y)
223
215
  end
224
216
 
225
217
  if @options.remember_geometry and !@options.command_line_geometry
218
+ # Get the desktop's geometry
219
+ desktop = Qt::Application.desktop
220
+ screen = desktop.screen
226
221
  settings = Qt::Settings.new('Ball Aerospace', self.class.to_s)
227
222
  if settings.contains('size') and @options.restore_size and @options.startup_state != :DEFAULT
228
223
  size = settings.value('size').toSize
229
- resize(size)
224
+ if size.height > 0 and size.height < screen.height and size.width > 0 and size.width < screen.width
225
+ resize(size)
226
+ end
230
227
  end
231
228
  if settings.contains('position') and @options.restore_position
232
229
  position = settings.value('position').toPoint
233
- move(position)
230
+ if position.x > 0 and position.y > 0 and position.x < screen.width and position.y < screen.height
231
+ move(position)
232
+ end
234
233
  end
235
234
  end
236
235
 
@@ -352,6 +351,7 @@ module Cosmos
352
351
  options.remember_geometry = true
353
352
  options.restore_position = true
354
353
  options.restore_size = true
354
+ options.stay_on_top = false
355
355
  options.redirect_io = true
356
356
  options.title = "COSMOS Tool"
357
357
  options.config_file = nil
@@ -403,6 +403,11 @@ module Cosmos
403
403
  options.startup_state = :DEFAULT
404
404
  end
405
405
 
406
+ # Create the defaultsize option
407
+ option_parser.on("--stay-on-top", "Force the tool to stay on top of all other windows") do |arg|
408
+ options.stay_on_top = true
409
+ end
410
+
406
411
  # Create the x and y position options
407
412
  option_parser.separator("")
408
413
  option_parser.separator("Window X & Y Position Options:")
@@ -17,6 +17,7 @@ module Cosmos
17
17
  # This calss also includes many helper methods to access various
18
18
  # lines, indent selections, highlight lines and center the view.
19
19
  class CompletionTextEdit < Qt::PlainTextEdit
20
+ attr_accessor :read_only
20
21
  # Create a signal so users of CompletionTextEdit don't have to
21
22
  # subclass in order to listen to keyPressEvents
22
23
  signals 'key_pressed(QKeyEvent*)'
@@ -47,6 +48,7 @@ module Cosmos
47
48
 
48
49
  @last_hightlighted_line = 1
49
50
  @code_completion = nil
51
+ @read_only = false
50
52
  begin
51
53
  @code_completion = Completion.new(self)
52
54
  rescue
@@ -114,7 +114,7 @@ module Cosmos
114
114
  if !@got_meta_item_names and !@update_thread
115
115
  @update_thread = Thread.new do
116
116
  begin
117
- server = JsonDRbObject.new(System.connect_hosts['DART_DECOM'], System.ports['DART_DECOM'])
117
+ server = JsonDRbObject.new(System.connect_hosts['DART_DECOM'], System.ports['DART_DECOM'], 1.0, Cosmos::System.x_csrf_token)
118
118
  item_names = server.item_names("SYSTEM", "META")
119
119
  Qt.execute_in_main_thread do
120
120
  unless self.disposed?
@@ -36,7 +36,7 @@ module Cosmos
36
36
  @status_packet.write('PACKET_ID', 1)
37
37
  @clear_errors_command = System.commands.packet('DART', 'CLEAR_ERRORS')
38
38
  @sleeper = Sleeper.new
39
- @dart = JsonDRbObject.new(System.connect_hosts['DART_DECOM'], System.ports['DART_DECOM'])
39
+ @dart = JsonDRbObject.new(System.connect_hosts['DART_DECOM'], System.ports['DART_DECOM'], 1.0, Cosmos::System.x_csrf_token)
40
40
  end
41
41
 
42
42
  # Indicates if the interface is connected to its target(s) or not. Must be
@@ -256,7 +256,7 @@ module Cosmos
256
256
  # Handle handshake warnings and errors
257
257
  if status == "OK" and code != 0
258
258
  unless @ignored_error_codes[handshake_cmd.handshake.handshake.target_name].include? code
259
- Logger.warn "Warning sending command (#{code}): #{source}"
259
+ Logger.warn "#{@name}: Warning sending command (#{code}): #{source}"
260
260
  end
261
261
  elsif status == "ERROR"
262
262
  unless @ignored_error_codes[handshake_cmd.handshake.handshake.target_name].include? code
@@ -295,7 +295,7 @@ module Cosmos
295
295
  command.received_count += 1
296
296
 
297
297
  # Put a log of the command onto the server for the user to see
298
- Logger.info("External Command: " + System.commands.format(linc_handshake.identified_command, System.targets[linc_handshake.identified_command.target_name].ignored_parameters))
298
+ Logger.info("#{@name}: External Command: " + System.commands.format(linc_handshake.identified_command, System.targets[linc_handshake.identified_command.target_name].ignored_parameters))
299
299
 
300
300
  # Log the command to the command log(s)
301
301
  @packet_log_writer_pairs.each do |packet_log_writer_pair|
@@ -361,7 +361,7 @@ module Cosmos
361
361
  if @handshake
362
362
  timed_out = false
363
363
  else
364
- Logger.warn "No handshake - must be timeout."
364
+ Logger.warn "#{@name}: No handshake - must be timeout."
365
365
  timed_out = true
366
366
  end
367
367
 
@@ -156,7 +156,7 @@ module Cosmos
156
156
  end
157
157
 
158
158
  def log_discard(length, found)
159
- Logger.error("Sync #{'not ' unless found}found. Discarding #{length} bytes of data.")
159
+ Logger.error("#{@interface ? @interface.name : ""}: Sync #{'not ' unless found}found. Discarding #{length} bytes of data.")
160
160
  if @data.length >= 0
161
161
  Logger.error(sprintf("Starting: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
162
162
  @data.length >= 1 ? @data.getbyte(0) : 0,
@@ -140,7 +140,7 @@ module Cosmos
140
140
  crc = BinaryAccessor.read(@bit_offset, @bit_size, :UINT, data, @endianness)
141
141
  calculated_crc = @crc.calc(data[0...(@bit_offset / 8)])
142
142
  if calculated_crc != crc
143
- Logger.error "Invalid CRC detected! Calculated 0x#{calculated_crc.to_s(16).upcase} vs found 0x#{crc.to_s(16).upcase}."
143
+ Logger.error "#{@interface ? @interface.name : ""}: Invalid CRC detected! Calculated 0x#{calculated_crc.to_s(16).upcase} vs found 0x#{crc.to_s(16).upcase}."
144
144
  if @bad_strategy == DISCONNECT
145
145
  return :DISCONNECT
146
146
  end
@@ -146,13 +146,13 @@ module Cosmos
146
146
  # Write the packet value with each of the values received
147
147
  response_values = response_string.scan(response_regexp)[0]
148
148
  if !response_values || (response_values.length != response_item_names.length)
149
- handle_error("#{@interface.name}: Unexpected response: #{response_string}")
149
+ handle_error("#{@interface ? @interface.name : ""}: Unexpected response: #{response_string}")
150
150
  else
151
151
  response_values.each_with_index do |value, i|
152
152
  begin
153
153
  result_packet.write(response_item_names[i], value)
154
154
  rescue => error
155
- handle_error("#{@interface.name}: Could not write value #{value} due to #{error.message}")
155
+ handle_error("#{@interface ? @interface.name : ""}: Could not write value #{value} due to #{error.message}")
156
156
  break
157
157
  end
158
158
  end
@@ -234,7 +234,7 @@ module Cosmos
234
234
  sleep(@response_polling_period)
235
235
  retry if !response_timeout_time
236
236
  retry if response_timeout_time and Time.now < response_timeout_time
237
- handle_error("#{@interface.name}: Timeout waiting for response")
237
+ handle_error("#{@interface ? @interface.name : ""}: Timeout waiting for response")
238
238
  end
239
239
 
240
240
  @response_template = nil
@@ -52,6 +52,7 @@ module Cosmos
52
52
  @read_allowed = false unless @read_port_name
53
53
  @flow_control = :NONE
54
54
  @data_bits = 8
55
+ @struct = []
55
56
  end
56
57
 
57
58
  # Creates a new {SerialStream} using the parameters passed in the constructor
@@ -65,13 +66,16 @@ module Cosmos
65
66
  @write_timeout,
66
67
  @read_timeout,
67
68
  @flow_control,
68
- @data_bits
69
+ @data_bits,
70
+ @struct
69
71
  )
70
72
  super()
71
73
  end
72
74
 
73
75
  # Supported Options
74
76
  # FLOW_CONTROL - Flow control method NONE or RTSCTS. Defaults to NONE
77
+ # DATA_BITS - How many data bits to use
78
+ # STRUCT - Directly set fields in the Win32 DCB or POSIX termios structure
75
79
  def set_option(option_name, option_values)
76
80
  super(option_name, option_values)
77
81
  case option_name.upcase
@@ -79,6 +83,8 @@ module Cosmos
79
83
  @flow_control = option_values[0]
80
84
  when 'DATA_BITS'
81
85
  @data_bits = option_values[0].to_i
86
+ when 'STRUCT'
87
+ @struct << option_values
82
88
  end
83
89
  end
84
90
  end
@@ -49,7 +49,7 @@ module Cosmos
49
49
  begin
50
50
  data = @stream.read
51
51
  rescue Timeout::Error
52
- Logger.instance.error "Timeout waiting for data to be read"
52
+ Logger.instance.error "#{@name}: Timeout waiting for data to be read"
53
53
  data = nil
54
54
  end
55
55
  return nil if data.nil? or data.length <= 0
@@ -132,7 +132,7 @@ module Cosmos
132
132
  end
133
133
  rescue Exception => err
134
134
  shutdown_interfaces(@write_interface_infos)
135
- Logger.instance.error("Tcpip server write thread unexpectedly died")
135
+ Logger.instance.error("#{@name}: Tcpip server write thread unexpectedly died")
136
136
  Logger.instance.error(err.formatted)
137
137
  end
138
138
  end
@@ -144,7 +144,7 @@ module Cosmos
144
144
  end
145
145
  rescue Exception => err
146
146
  shutdown_interfaces(@write_interface_infos)
147
- Logger.instance.error("Tcpip server write raw thread unexpectedly died")
147
+ Logger.instance.error("#{@name}: Tcpip server write raw thread unexpectedly died")
148
148
  Logger.instance.error(err.formatted)
149
149
  end
150
150
  end
@@ -298,10 +298,10 @@ module Cosmos
298
298
  def change_raw_logging(method)
299
299
  if @raw_logger_pair
300
300
  @write_interface_infos.each do |interface_info|
301
- interface_info.interface.raw_logger_pair.send(method) if interface_info.interface.raw_logger_pair
301
+ interface_info.interface.raw_logger_pair.public_send(method) if interface_info.interface.raw_logger_pair
302
302
  end
303
303
  @read_interface_infos.each do |interface_info|
304
- interface_info.interface.raw_logger_pair.send(method) if interface_info.interface.raw_logger_pair
304
+ interface_info.interface.raw_logger_pair.public_send(method) if interface_info.interface.raw_logger_pair
305
305
  end
306
306
  end
307
307
  end
@@ -346,7 +346,7 @@ module Cosmos
346
346
  break if @cancel_threads
347
347
  end
348
348
  rescue => err
349
- Logger.instance.error("Tcpip server listen thread unexpectedly died")
349
+ Logger.instance.error("#{@name}: Tcpip server listen thread unexpectedly died")
350
350
  Logger.instance.error(err.formatted)
351
351
  end
352
352
  end
@@ -372,7 +372,7 @@ module Cosmos
372
372
  if not System.instance.acl.allow_addr?(addr)
373
373
  # Reject connection
374
374
  Cosmos.close_socket(socket)
375
- Logger.instance.info "Tcpip server rejected connection from #{hostname}(#{host_ip}):#{port}"
375
+ Logger.instance.info "#{@name}: Tcpip server rejected connection from #{hostname}(#{host_ip}):#{port}"
376
376
  return
377
377
  end
378
378
  end
@@ -417,7 +417,7 @@ module Cosmos
417
417
  end
418
418
  start_read_thread(@read_interface_infos[-1])
419
419
  end
420
- Logger.instance.info "Tcpip server accepted connection from #{hostname}(#{host_ip}):#{port}"
420
+ Logger.instance.info "#{@name}: Tcpip server accepted connection from #{hostname}(#{host_ip}):#{port}"
421
421
  end
422
422
 
423
423
  def start_read_thread(interface_info)
@@ -427,10 +427,10 @@ module Cosmos
427
427
  begin
428
428
  read_thread_body(interface_info.interface)
429
429
  rescue Exception => err
430
- Logger.instance.error "Tcpip server read thread unexpectedly died"
430
+ Logger.instance.error "#{@name}: Tcpip server read thread unexpectedly died"
431
431
  Logger.instance.error err.formatted
432
432
  end
433
- Logger.instance.info "Tcpip server lost read connection to #{interface_info.hostname}(#{interface_info.host_ip}):#{interface_info.port}"
433
+ Logger.instance.info "#{@name}: Tcpip server lost read connection to #{interface_info.hostname}(#{interface_info.host_ip}):#{interface_info.port}"
434
434
  @read_threads.delete(Thread.current)
435
435
 
436
436
  index_to_delete = nil
@@ -453,7 +453,7 @@ module Cosmos
453
453
  end
454
454
  end
455
455
  rescue Exception => err
456
- Logger.instance.error "Tcpip server read thread unexpectedly died"
456
+ Logger.instance.error "#{@name}: Tcpip server read thread unexpectedly died"
457
457
  Logger.instance.error err.formatted
458
458
  end
459
459
  end
@@ -500,7 +500,7 @@ module Cosmos
500
500
  end
501
501
 
502
502
  def interface_disconnect(interface_info)
503
- Logger.instance.info "Tcpip server lost write connection to "\
503
+ Logger.instance.info "#{@name}: Tcpip server lost write connection to "\
504
504
  "#{interface_info.hostname}(#{interface_info.host_ip}):#{interface_info.port}"
505
505
  interface_info.interface.disconnect
506
506
  interface_info.interface.raw_logger_pair.stop if interface_info.interface.raw_logger_pair
@@ -552,13 +552,13 @@ module Cosmos
552
552
  next
553
553
  end
554
554
  # Client has disconnected (or is invalidly sending data on the socket)
555
- Logger.instance.info "Tcpip server lost write connection to #{interface_info.hostname}(#{interface_info.host_ip}):#{interface_info.port}"
555
+ Logger.instance.info "#{@name}: Tcpip server lost write connection to #{interface_info.hostname}(#{interface_info.host_ip}):#{interface_info.port}"
556
556
  interface_info.interface.disconnect
557
557
  interface_info.interface.raw_logger_pair.stop if interface_info.interface.raw_logger_pair
558
558
  indexes_to_delete.unshift(index) # Put later indexes at front of array
559
559
  rescue Errno::ECONNRESET, Errno::ECONNABORTED, IOError
560
560
  # Client has disconnected
561
- Logger.instance.info "Tcpip server lost write connection to #{interface_info.hostname}(#{interface_info.host_ip}):#{interface_info.port}"
561
+ Logger.instance.info "#{@name}: Tcpip server lost write connection to #{interface_info.hostname}(#{interface_info.host_ip}):#{interface_info.port}"
562
562
  interface_info.interface.disconnect
563
563
  interface_info.interface.raw_logger_pair.stop if interface_info.interface.raw_logger_pair
564
564
  indexes_to_delete.unshift(index) # Put later indexes at front of array
@@ -590,7 +590,7 @@ module Cosmos
590
590
  need_disconnect = false
591
591
  begin
592
592
  interface_bytes_written = interface_info.interface.bytes_written
593
- interface_info.interface.send(method, packet_or_data)
593
+ interface_info.interface.public_send(method, packet_or_data)
594
594
  diff = interface_info.interface.bytes_written - interface_bytes_written
595
595
  @written_raw_data_time = interface_info.interface.written_raw_data_time
596
596
  @written_raw_data = interface_info.interface.written_raw_data
@@ -600,13 +600,13 @@ module Cosmos
600
600
  need_disconnect = true
601
601
  rescue Exception => err
602
602
  if err.message != "Stream not connected for write_raw"
603
- Logger.instance.error "Error sending to client: #{err.class} #{err.message}"
603
+ Logger.instance.error "#{@name}: Error sending to client: #{err.class} #{err.message}"
604
604
  end
605
605
  need_disconnect = true
606
606
  end
607
607
 
608
608
  if need_disconnect
609
- Logger.instance.info "Tcpip server lost write connection to #{interface_info.hostname}(#{interface_info.host_ip}):#{interface_info.port}"
609
+ Logger.instance.info "#{@name}: Tcpip server lost write connection to #{interface_info.hostname}(#{interface_info.host_ip}):#{interface_info.port}"
610
610
  interface_info.interface.disconnect
611
611
  interface_info.interface.raw_logger_pair.stop if interface_info.interface.raw_logger_pair
612
612
  indexes_to_delete.unshift(index) # Put later indexes at front of array
@@ -40,11 +40,15 @@ module Cosmos
40
40
  result = nil
41
41
  @streams.each do |stream|
42
42
  if first
43
- result = stream.send(method_name, *args)
43
+ # Fortify Access Specifier Manipulation
44
+ # We're forwarding only public methods to the stream
45
+ result = stream.public_send(method_name, *args)
44
46
  result = self if result == stream
45
47
  first = false
46
48
  else
47
- stream.send(method_name, *args)
49
+ # Fortify Access Specifier Manipulation
50
+ # We're forwarding only public methods to the stream
51
+ stream.public_send(method_name, *args)
48
52
  end
49
53
  end
50
54
  result
@@ -17,14 +17,6 @@ require 'set'
17
17
  require 'cosmos/io/json_rpc'
18
18
  require 'cosmos/io/json_drb_rack'
19
19
  require 'rack/handler/puma'
20
- if RUBY_ENGINE == 'ruby' and %w(2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1).include? RUBY_VERSION
21
- begin
22
- require 'stopgap_13632'
23
- rescue Exception => err
24
- msg = "Error loading stopgap. Make sure gem install stopgap_13632 succeeds: #{err.message}"
25
- raise $!, msg, $!.backtrace
26
- end
27
- end
28
20
 
29
21
  # Add methods to the Puma::Launcher and Puma::Single class so we can tell
30
22
  # if the server has been started.
@@ -123,7 +115,7 @@ module Cosmos
123
115
  # @param object [Object] The object to send the DRb requests to. This
124
116
  # object must either include the Cosmos::Script module or be the
125
117
  # CmdTlmServer.
126
- def start_service(hostname = nil, port = nil, object = nil, max_threads = 1000)
118
+ def start_service(hostname = nil, port = nil, object = nil, max_threads = 1000, system = nil)
127
119
  server_started = false
128
120
  @server_mutex.synchronize do
129
121
  server_started = true if @server
@@ -147,7 +139,7 @@ module Cosmos
147
139
  }
148
140
 
149
141
  # The run call will block until the server is stopped.
150
- Rack::Handler::Puma.run(JsonDrbRack.new(self), server_config) do |server|
142
+ Rack::Handler::Puma.run(JsonDrbRack.new(self, system), server_config) do |server|
151
143
  @server_mutex.synchronize do
152
144
  @server = server
153
145
  end
@@ -262,7 +254,7 @@ module Cosmos
262
254
  if (@method_whitelist and @method_whitelist.include?(request.method.downcase())) or
263
255
  (!@method_whitelist and !JsonRpcRequest::DANGEROUS_METHODS.include?(request.method.downcase()))
264
256
  begin
265
- result = @object.send(request.method.downcase().intern, *request.params)
257
+ result = @object.public_send(request.method.downcase().intern, *request.params)
266
258
  if request.id
267
259
  response = JsonRpcSuccessResponse.new(result, request.id)
268
260
  end
@@ -38,7 +38,7 @@ module Cosmos
38
38
  # @param hostname [String] The name of the machine which has started
39
39
  # the JSON service
40
40
  # @param port [Integer] The port number of the JSON service
41
- def initialize(hostname, port, connect_timeout = 1.0)
41
+ def initialize(hostname, port, connect_timeout = 1.0, x_csrf_token = nil)
42
42
  hostname = '127.0.0.1' if (hostname.to_s.upcase == 'LOCALHOST')
43
43
  begin
44
44
  Socket.pack_sockaddr_in(port, hostname)
@@ -61,6 +61,7 @@ module Cosmos
61
61
  @connect_timeout = connect_timeout
62
62
  @connect_timeout = @connect_timeout.to_f if @connect_timeout
63
63
  @shutdown = false
64
+ @x_csrf_token = x_csrf_token
64
65
  end
65
66
 
66
67
  # Disconnects from http server
@@ -127,7 +128,11 @@ module Cosmos
127
128
  STDOUT.puts "\nRequest:\n" if JsonDRb.debug?
128
129
  STDOUT.puts @request_data if JsonDRb.debug?
129
130
  @request_in_progress = true
130
- headers = {'Content-Type' => 'application/json-rpc'}
131
+ if @x_csrf_token
132
+ headers = {'Content-Type' => 'application/json-rpc', 'X-Csrf-Token' => @x_csrf_token}
133
+ else
134
+ headers = {'Content-Type' => 'application/json-rpc'}
135
+ end
131
136
  res = @http.post(@uri,
132
137
  :body => @request_data,
133
138
  :header => headers)
@@ -17,8 +17,9 @@ module Cosmos
17
17
  class JsonDrbRack
18
18
  # @param drb [JsonDRb] - An instance of the JsonDRb class that'll be used
19
19
  # to process the JSON request and generate a response
20
- def initialize(drb)
20
+ def initialize(drb, system = nil)
21
21
  @drb = drb
22
+ @system = system
22
23
  end
23
24
 
24
25
  # Handles a request.
@@ -32,22 +33,41 @@ module Cosmos
32
33
  # ACL allow_addr? function takes address in the form returned by
33
34
  # IPSocket.peeraddr.
34
35
  req_addr = ["AF_INET", request.port, request.host.to_s, request.ip.to_s]
36
+ status = nil
35
37
 
36
38
  if @drb.acl and !@drb.acl.allow_addr?(req_addr)
37
39
  status = 403
38
40
  content_type = "text/plain"
39
41
  body = "Forbidden"
40
42
  elsif request.post?
41
- status, content_type, body = handle_post(request)
43
+ if @system
44
+ if @system.x_csrf_token and (request.env['HTTP_X_CSRF_TOKEN'] != @system.x_csrf_token)
45
+ status = 403
46
+ content_type = "text/plain"
47
+ body = "Forbidden: Bad X-Csrf-Token: #{request.env['HTTP_X_CSRF_TOKEN']}"
48
+ end
49
+ if !@system.allowed_hosts.include?(request.env['HTTP_HOST'])
50
+ status = 403
51
+ content_type = "text/plain"
52
+ body = "Forbidden: #{request.env['HTTP_HOST']} not in allowed hosts"
53
+ end
54
+ if request.env['HTTP_ORIGIN'] and !@system.allowed_origins.include?(request.env['HTTP_ORIGIN'])
55
+ status = 403
56
+ content_type = "text/plain"
57
+ body = "Forbidden: #{request.env['HTTP_ORIGIN']} not in allowed origins"
58
+ end
59
+ end
60
+
61
+ status, content_type, body = handle_post(request) unless status
42
62
  else
43
63
  status = 405
44
64
  content_type = "text/plain"
45
65
  body = "Request not allowed"
46
66
  end
47
-
67
+
48
68
  return status, {'Content-Type' => content_type}, [body]
49
69
  end
50
-
70
+
51
71
  # Handles an http post.
52
72
  #
53
73
  # @param request [Rack::Request] - A rack post request
@@ -57,7 +77,7 @@ module Cosmos
57
77
  request_data = request.body.read
58
78
  start_time = Time.now.sys
59
79
  response_data, error_code = @drb.process_request(request_data, start_time)
60
-
80
+
61
81
  # Convert json error code into html status code
62
82
  # see http://www.jsonrpc.org/historical/json-rpc-over-http.html#errors
63
83
  if error_code
@@ -269,7 +269,7 @@ module Cosmos
269
269
  # @param response_data [String] JSON encoded string representing the response
270
270
  # @return [JsonRpcResponse]
271
271
  def self.from_json(response_data)
272
- msg = "Invalid JSON-RPC 2.0 Response"
272
+ msg = "Invalid JSON-RPC 2.0 Response: #{response_data.inspect}"
273
273
  begin
274
274
  hash = JSON.parse(response_data, :allow_nan => true, :create_additions => true)
275
275
  rescue