cosmos 4.4.1-java → 4.5.2-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 (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