cosmos 3.3.1 → 3.3.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fb2fffb8f204bc932ef93438457c310503837e2f
4
- data.tar.gz: 6ecd99712d7682a2d70de2539c03826502868cc9
3
+ metadata.gz: d82d5f0bf5ba66085f85878c642a00882a44eae6
4
+ data.tar.gz: 06f95196ee1a8cef8a806a51ceff0bebfeb480e8
5
5
  SHA512:
6
- metadata.gz: e3b958ffc7000f284188567ae8cf57934288373617682208b913767b2d230cdeb05b98f55745347d9d6ad12ab5d4874e1a8c6f29f379baccbaf4a3f2f21c4253
7
- data.tar.gz: c3b6704c2d87fdc6a9413eab98be998fe278a364f2097776521610a876b605c3eb6b0876dd349a5f523ea5255ad7df6259769fe111d6be439b18ebfd6b3389a9
6
+ metadata.gz: e73b10b1c4ef740738c03421e698c4f6d5a1ecee377d7f147a10b28f6919a1cd0bc05a8d4db31d4cdf88232ca700df733969f594edeb32d5e3d7311faf1aa116
7
+ data.tar.gz: 03006e36721d7afcf22adcb05cc2f056d32f7d6f83270437de56a0ffbe07d1c09aa15eeb5c6a69138a46401dd537d849f0a126e77f59fceb1a4f45dbde01207c
@@ -90,7 +90,7 @@
90
90
  "lib/cosmos/gui/choosers/combobox_chooser.rb" 0xAD5383D5
91
91
  "lib/cosmos/gui/choosers/float_chooser.rb" 0x23B2FA77
92
92
  "lib/cosmos/tools/script_runner/script_runner_config.rb" 0x1E46E8AA
93
- "lib/cosmos/tools/script_runner/script_runner_frame.rb" 0xB999FC77
93
+ "lib/cosmos/tools/script_runner/script_runner_frame.rb" 0xF3F14036
94
94
  "lib/cosmos/tools/script_runner/script_runner.rb" 0x88EEB809
95
95
  "lib/cosmos/tools/script_runner/script_audit.rb" 0xB857FA4A
96
96
  "lib/cosmos/tools/cmd_extractor/cmd_extractor.rb" 0xEECB31B8
@@ -234,7 +234,7 @@
234
234
  "lib/cosmos/tools/tlm_viewer/tlm_viewer.rb" 0x1D2090F6
235
235
  "lib/cosmos/system.rb" 0x735DFB42
236
236
  "lib/cosmos/conversions.rb" 0x43679D05
237
- "lib/cosmos/version.rb" 0xFED34D5F
237
+ "lib/cosmos/version.rb" 0x1CF2C150
238
238
  "lib/cosmos/core_ext.rb" 0x1951B346
239
239
  "lib/cosmos/interfaces.rb" 0x7E3EA326
240
240
  "lib/cosmos/processors.rb" 0x5241327D
@@ -267,7 +267,7 @@
267
267
  "lib/cosmos/packets/parsers/limits_response_parser.rb" 0x05979119
268
268
  "lib/cosmos/packets/packet_config.rb" 0xFDD8F251
269
269
  "lib/cosmos/packets/binary_accessor.rb" 0xF913F2EA
270
- "lib/cosmos/packets/packet.rb" 0x39B6C0C4
270
+ "lib/cosmos/packets/packet.rb" 0x043EF800
271
271
  "lib/cosmos/packets/structure_item.rb" 0xBDC81085
272
272
  "lib/cosmos/packets/packet_item_limits.rb" 0xE187C389
273
273
  "lib/cosmos/packets/packet_item.rb" 0x2A07D5B4
@@ -277,7 +277,7 @@
277
277
  "lib/cosmos/processors/watermark_processor.rb" 0xDADF4580
278
278
  "lib/cosmos/io/stdout.rb" 0xAC9CC4B1
279
279
  "lib/cosmos/io/buffered_file.rb" 0x70A3B880
280
- "lib/cosmos/io/json_drb_object.rb" 0x58BE861D
280
+ "lib/cosmos/io/json_drb_object.rb" 0x9825D709
281
281
  "lib/cosmos/io/cosmos_snmp.rb" 0x64541158
282
282
  "lib/cosmos/io/json_rpc.rb" 0xAF9D95D5
283
283
  "lib/cosmos/io/tcpip_server.rb" 0xBAA24660
@@ -286,7 +286,7 @@
286
286
  "lib/cosmos/io/serial_driver.rb" 0x9A2515F4
287
287
  "lib/cosmos/io/raw_logger_pair.rb" 0x7A0A3F00
288
288
  "lib/cosmos/io/raw_logger.rb" 0x42BC42CC
289
- "lib/cosmos/io/json_drb.rb" 0x53EC6DBC
289
+ "lib/cosmos/io/json_drb.rb" 0x878C8A71
290
290
  "lib/cosmos/io/stderr.rb" 0x401624AF
291
291
  "lib/cosmos/io/io_multiplexer.rb" 0xD183938D
292
292
  "lib/cosmos/io/win32_serial_driver.rb" 0xA7E055CA
@@ -299,7 +299,7 @@
299
299
  "lib/cosmos/interfaces/tcpip_client_interface.rb" 0x5F0DB50D
300
300
  "lib/cosmos/interfaces/udp_interface.rb" 0xCE4532AD
301
301
  "lib/cosmos/interfaces/tcpip_server_interface.rb" 0xC8F6E908
302
- "lib/cosmos/script/script.rb" 0x06BF2D5F
302
+ "lib/cosmos/script/script.rb" 0x472901A7
303
303
  "lib/cosmos/script/extract.rb" 0xF3243476
304
304
  "lib/cosmos/core_ext/range.rb" 0x0D55D9D1
305
305
  "lib/cosmos/core_ext/stringio.rb" 0x28B64FB4
@@ -30,8 +30,6 @@ module Cosmos
30
30
 
31
31
  # @return [Integer] The number of JSON-RPC requests processed
32
32
  attr_accessor :request_count
33
- # @return [Integer] The number of clients currently connected to the server
34
- attr_accessor :num_clients
35
33
  # @return [Array<String>] List of methods that should be allowed
36
34
  attr_accessor :method_whitelist
37
35
  # @return [ACL] The access control list
@@ -47,16 +45,42 @@ module Cosmos
47
45
  @request_times = []
48
46
  @request_times_index = 0
49
47
  @request_mutex = Mutex.new
50
- @num_clients = 0
48
+ @client_sockets = []
49
+ @client_threads = []
50
+ @client_mutex = Mutex.new
51
51
  @thread_reader, @thread_writer = IO.pipe
52
52
  end
53
53
 
54
+ # Returns the number of connected clients
55
+ # @return [Integer] The number of connected clients
56
+ def num_clients
57
+ @client_threads.length
58
+ end
59
+
54
60
  # Stops the DRb service by closing the socket and the processing thread
55
61
  def stop_service
56
62
  Cosmos.kill_thread(self, @thread)
57
63
  @thread = nil
58
64
  Cosmos.close_socket(@listen_socket)
59
65
  @listen_socket = nil
66
+ client_threads = nil
67
+ @client_mutex.synchronize do
68
+ @client_sockets.each do |client_socket|
69
+ Cosmos.close_socket(client_socket)
70
+ end
71
+ client_threads = @client_threads.clone
72
+ end
73
+
74
+ # This cannot be inside of the client_mutex or the threads will not
75
+ # be able to shutdown because they will stick on the client_mutex
76
+ client_threads.each do |client_thread|
77
+ Cosmos.kill_thread(self, client_thread)
78
+ end
79
+
80
+ @client_mutex.synchronize do
81
+ @client_threads.clear
82
+ @client_sockets.clear
83
+ end
60
84
  end
61
85
 
62
86
  # Gracefully kill the thread
@@ -254,7 +278,11 @@ module Cosmos
254
278
  socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1)
255
279
 
256
280
  Thread.new(socket) do |my_socket|
257
- @num_clients += 1
281
+ @client_mutex.synchronize do
282
+ @client_sockets << my_socket
283
+ @client_threads << Thread.current
284
+ end
285
+
258
286
  data = ''
259
287
  begin
260
288
  while true
@@ -270,14 +298,18 @@ module Cosmos
270
298
  break unless process_request(request_data, my_socket, start_time)
271
299
  else
272
300
  # Socket was closed by client
273
- Cosmos.close_socket(my_socket)
274
301
  break
275
302
  end
276
303
  end
277
304
  rescue Exception => error
278
305
  Logger.error "JsonDrb client thread unexpectedly died.\n#{error.formatted}"
279
306
  end
280
- @num_clients -= 1
307
+
308
+ @client_mutex.synchronize do
309
+ Cosmos.close_socket(my_socket)
310
+ @client_sockets.delete(my_socket)
311
+ @client_threads.delete(Thread.current)
312
+ end
281
313
  end
282
314
  end
283
315
 
@@ -58,6 +58,10 @@ module Cosmos
58
58
  # Disconnects from the JSON server
59
59
  def disconnect
60
60
  Cosmos.close_socket(@socket)
61
+ # Cannot set @socket to nil here because this method can be called by
62
+ # other threads and @socket being nil would cause unexpected errors in method_missing
63
+ # Also don't want to take the mutex so that we can interrupt method_missing if necessary
64
+ # Only method_missing can set @socket to nil
61
65
  end
62
66
 
63
67
  # Permanently disconnects from the JSON server
@@ -75,91 +79,120 @@ module Cosmos
75
79
  # protocol a DRb::DRbConnError exception is raised.
76
80
  def method_missing(method_name, *method_params)
77
81
  @mutex.synchronize do
78
- raise DRb::DRbConnError, "Shutdown" if @shutdown
79
- if !@socket or @socket.closed? or @request_in_progress
80
- if @request_in_progress
82
+ # This flag and loop are used to automatically reconnect and retry if something goes
83
+ # wrong on the first attempt writing to the socket. Sockets can become disconnected
84
+ # between function calls, but as long as the remote server is back up and running the
85
+ # call should succeed even when it discovers a broken socket on the first attempt.
86
+ first_try = true
87
+ loop do
88
+ raise DRb::DRbConnError, "Shutdown" if @shutdown
89
+ connect() if !@socket or @socket.closed? or @request_in_progress
90
+
91
+ response = make_request(method_name, method_params, first_try)
92
+ unless response
81
93
  disconnect()
82
94
  @socket = nil
83
- @request_in_progress = false
95
+ was_first_try = first_try
96
+ first_try = false
97
+ next if was_first_try
84
98
  end
99
+ return handle_response(response)
100
+ end # loop
101
+ end # @mutex.synchronize
102
+ end # def method_missing
103
+
104
+ private
105
+
106
+ def connect
107
+ if @request_in_progress
108
+ disconnect()
109
+ @socket = nil
110
+ @request_in_progress = false
111
+ end
112
+ begin
113
+ addr = Socket.pack_sockaddr_in(@port, @hostname)
114
+ @socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
115
+ @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
116
+ begin
117
+ @socket.connect_nonblock(addr)
118
+ rescue IO::WaitWritable
85
119
  begin
86
- addr = Socket.pack_sockaddr_in(@port, @hostname)
87
- @socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
88
- @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
120
+ _, sockets, _ = IO.select(nil, [@socket], nil, @connect_timeout) # wait 3-way handshake completion
121
+ rescue IOError, Errno::ENOTSOCK
122
+ disconnect()
123
+ @socket = nil
124
+ raise "Connect canceled"
125
+ end
126
+ if sockets and !sockets.empty?
89
127
  begin
90
- @socket.connect_nonblock(addr)
91
- rescue IO::WaitWritable
92
- begin
93
- _, sockets, _ = IO.select(nil, [@socket], nil, @connect_timeout) # wait 3-way handshake completion
94
- rescue IOError, Errno::ENOTSOCK
95
- disconnect()
96
- @socket = nil
97
- raise "Connect canceled"
98
- end
99
- if sockets and !sockets.empty?
100
- begin
101
- @socket.connect_nonblock(addr) # check connection failure
102
- rescue IOError, Errno::ENOTSOCK
103
- disconnect()
104
- @socket = nil
105
- raise "Connect canceled"
106
- rescue Errno::EINPROGRESS
107
- retry
108
- rescue Errno::EISCONN, Errno::EALREADY
109
- end
110
- else
111
- disconnect()
112
- @socket = nil
113
- raise "Connect timeout"
114
- end
128
+ @socket.connect_nonblock(addr) # check connection failure
115
129
  rescue IOError, Errno::ENOTSOCK
116
130
  disconnect()
117
131
  @socket = nil
118
132
  raise "Connect canceled"
133
+ rescue Errno::EINPROGRESS
134
+ retry
135
+ rescue Errno::EISCONN, Errno::EALREADY
119
136
  end
120
- rescue => e
121
- raise DRb::DRbConnError, e.message
137
+ else
138
+ disconnect()
139
+ @socket = nil
140
+ raise "Connect timeout"
122
141
  end
123
- end
124
-
125
- request = JsonRpcRequest.new(method_name, method_params, @id)
126
- @id += 1
127
-
128
- request_data = request.to_json(:allow_nan => true)
129
- begin
130
- @request_in_progress = true
131
- STDOUT.puts "Request:\n" if JsonDRb.debug?
132
- STDOUT.puts request_data if JsonDRb.debug?
133
- JsonDRb.send_data(@socket, request_data)
134
- response_data = JsonDRb.receive_message(@socket, '')
135
- STDOUT.puts "\nResponse:\n" if JsonDRb.debug?
136
- STDOUT.puts response_data if JsonDRb.debug?
137
- @request_in_progress = false
138
- rescue => e
142
+ rescue IOError, Errno::ENOTSOCK
139
143
  disconnect()
140
144
  @socket = nil
141
- raise DRb::DRbConnError, e.message, e.backtrace
145
+ raise "Connect canceled"
142
146
  end
147
+ rescue => e
148
+ raise DRb::DRbConnError, e.message
149
+ end
150
+ end
143
151
 
144
- if response_data
145
- response = JsonRpcResponse.from_json(response_data)
146
- if JsonRpcErrorResponse === response
147
- if response.error.data
148
- raise Exception.from_hash(response.error.data)
149
- else
150
- raise "JsonDRb Error (#{response.error.code}): #{response.error.message}"
151
- end
152
+ def make_request(method_name, method_params, first_try)
153
+ request = JsonRpcRequest.new(method_name, method_params, @id)
154
+ @id += 1
155
+
156
+ request_data = request.to_json(:allow_nan => true)
157
+ begin
158
+ STDOUT.puts "Request:\n" if JsonDRb.debug?
159
+ STDOUT.puts request_data if JsonDRb.debug?
160
+ @request_in_progress = true
161
+ JsonDRb.send_data(@socket, request_data)
162
+ response_data = JsonDRb.receive_message(@socket, '')
163
+ @request_in_progress = false
164
+ STDOUT.puts "\nResponse:\n" if JsonDRb.debug?
165
+ STDOUT.puts response_data if JsonDRb.debug?
166
+ rescue => e
167
+ disconnect()
168
+ @socket = nil
169
+ return false if first_try
170
+ raise DRb::DRbConnError, e.message, e.backtrace
171
+ end
172
+ response_data
173
+ end
174
+
175
+ def handle_response(response_data)
176
+ # The code below will always either raise or return breaking out of the loop
177
+ if response_data
178
+ response = JsonRpcResponse.from_json(response_data)
179
+ if JsonRpcErrorResponse === response
180
+ if response.error.data
181
+ raise Exception.from_hash(response.error.data)
152
182
  else
153
- return response.result
183
+ raise "JsonDRb Error (#{response.error.code}): #{response.error.message}"
154
184
  end
155
185
  else
156
- # Socket was closed by server
157
- disconnect()
158
- @socket = nil
159
- raise DRb::DRbConnError, "Socket closed by server"
186
+ return response.result
160
187
  end
188
+ else
189
+ # Socket was closed by server
190
+ disconnect()
191
+ @socket = nil
192
+ raise DRb::DRbConnError, "Socket closed by server"
161
193
  end
162
194
  end
163
- end
195
+
196
+ end # class JsonDRbObject
164
197
 
165
198
  end # module Cosmos
@@ -357,7 +357,7 @@ module Cosmos
357
357
 
358
358
  # Convert from value to state if possible
359
359
  if item.states
360
- if item.array_size
360
+ if Array === value
361
361
  value = value.map do |val, index|
362
362
  if item.states.key(val)
363
363
  item.states.key(val)
@@ -374,7 +374,7 @@ module Cosmos
374
374
  end
375
375
  end
376
376
  else
377
- if item.array_size
377
+ if Array === value
378
378
  value = value.map do |val, index|
379
379
  apply_format_string_and_units(item, val, value_type)
380
380
  end
@@ -970,6 +970,25 @@ module Cosmos
970
970
  end
971
971
  end
972
972
 
973
+ def disable_instrumentation
974
+ if defined? ScriptRunnerFrame and ScriptRunnerFrame.instance
975
+ ScriptRunnerFrame.instance.use_instrumentation = false
976
+ begin
977
+ yield
978
+ ensure
979
+ ScriptRunnerFrame.instance.use_instrumentation = true
980
+ end
981
+ else
982
+ yield
983
+ end
984
+ end
985
+
986
+ def set_stdout_max_lines(max_lines)
987
+ if defined? ScriptRunnerFrame and ScriptRunnerFrame.instance
988
+ ScriptRunnerFrame.instance.stdout_max_lines = max_lines
989
+ end
990
+ end
991
+
973
992
  #######################################
974
993
  # Methods for debugging
975
994
  #######################################
@@ -101,6 +101,7 @@ module Cosmos
101
101
  attr_reader :message_log
102
102
  attr_reader :script_class
103
103
  attr_reader :top_level_instrumented_cache
104
+ attr_accessor :stdout_max_lines
104
105
 
105
106
  @@instance = nil
106
107
  @@run_thread = nil
@@ -1195,8 +1196,8 @@ module Cosmos
1195
1196
  lines_to_write << line_to_write
1196
1197
 
1197
1198
  line_count += 1
1198
- if line_count > 1000
1199
- out_line = "ERROR: Too much written to stdout. Truncating output to 1000 lines.\n"
1199
+ if line_count > @stdout_max_lines
1200
+ out_line = "ERROR: Too much written to stdout. Truncating output to #{@stdout_max_lines} lines.\n"
1200
1201
  if filename
1201
1202
  line_to_write = time_formatted + " (#{out_filename}:#{out_line_number}): " + out_line
1202
1203
  else
@@ -1249,6 +1250,7 @@ module Cosmos
1249
1250
  @inline_eval = nil
1250
1251
  @current_filename = nil
1251
1252
  @current_line_number = 0
1253
+ @stdout_max_lines = 1000
1252
1254
 
1253
1255
  @script.stop_highlight
1254
1256
  @call_stack.push(@current_file.dup)
@@ -1,12 +1,12 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- COSMOS_VERSION = '3.3.1'
3
+ COSMOS_VERSION = '3.3.2'
4
4
  module Cosmos
5
5
  module Version
6
6
  MAJOR = '3'
7
7
  MINOR = '3'
8
- PATCH = '1'
9
- BUILD = 'ec5e7d055502c4160427af946416839a23cda7ea'
8
+ PATCH = '2'
9
+ BUILD = '5c4dd480988b12d90f6b7bc8c161489fca570a63'
10
10
  end
11
- VERSION = '3.3.1'
11
+ VERSION = '3.3.2'
12
12
  end
@@ -93,6 +93,26 @@ module Cosmos
93
93
  sleep(0.1)
94
94
  end
95
95
 
96
+ it "handles the remote going away and coming back" do
97
+ class JsonDRbObjectServer
98
+ def my_method(param)
99
+ param * 2
100
+ end
101
+ end
102
+
103
+ json = JsonDRb.new
104
+ json.start_service('127.0.0.1', 7777, JsonDRbObjectServer.new)
105
+ obj = JsonDRbObject.new("localhost", 7777)
106
+ expect(obj.my_method(10)).to eql 20
107
+ json.stop_service
108
+ json = JsonDRb.new
109
+ json.start_service('127.0.0.1', 7777, JsonDRbObjectServer.new)
110
+ expect(obj.my_method(10)).to eql 20
111
+ obj.disconnect
112
+ json.stop_service
113
+ sleep(0.1)
114
+ end
115
+
96
116
  end
97
117
  end
98
118
  end
@@ -449,6 +449,12 @@ module Cosmos
449
449
  expect(@p.read_item(i, :WITH_UNITS, "\x02\x04")).to eql ["TRUE","FALSE"]
450
450
  expect(@p.read("ITEM", :WITH_UNITS, "\x08")).to eql ["0x4 V"]
451
451
  expect(@p.read_item(i, :WITH_UNITS, "\x08")).to eql ["0x4 V"]
452
+ @p.define_item("item2",0, 0, :DERIVED)
453
+ i = @p.get_item("ITEM2")
454
+ i.units = "V"
455
+ i.read_conversion = GenericConversion.new("[1,2,3,4,5]")
456
+ expect(@p.read("ITEM2", :FORMATTED, "")).to eql ["1", "2", "3", "4", "5"]
457
+ expect(@p.read("ITEM2", :WITH_UNITS, "")).to eql ["1 V", "2 V", "3 V", "4 V", "5 V"]
452
458
  end
453
459
  end
454
460
 
@@ -704,6 +704,10 @@ module Cosmos
704
704
  get_line_delay
705
705
  get_scriptrunner_message_log_filename
706
706
  start_new_scriptrunner_message_log
707
+ disable_instrumentation do
708
+ value = 1
709
+ end
710
+ set_stdout_max_lines(1000)
707
711
  insert_return
708
712
  step_mode
709
713
  run_mode
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cosmos
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.1
4
+ version: 3.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Melton
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-03-19 00:00:00.000000000 Z
12
+ date: 2015-03-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler