rtext 0.9.0 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -21,15 +21,21 @@ def initialize(config, options={})
21
21
  @outfile_provider = options[:outfile_provider]
22
22
  @keep_outfile = options[:keep_outfile]
23
23
  @connection_timeout = options[:connection_timeout] || 10
24
+ @process_id = nil
24
25
  end
25
26
 
26
27
  def execute_command(obj, options={})
27
- timeout = options[:timeout] || 5
28
+ timeout = options[:timeout] || 10
28
29
  @busy = false if @busy_start_time && (Time.now > @busy_start_time + timeout)
29
30
  if @busy
30
31
  do_work
31
- :backend_busy
32
- elsif connected?
32
+ return :backend_busy
33
+ end
34
+ unless connected?
35
+ connect unless connecting?
36
+ do_work
37
+ end
38
+ if connected?
33
39
  obj["invocation_id"] = @invocation_id
34
40
  obj["type"] = "request"
35
41
  @socket.send(serialize_message(obj), 0)
@@ -66,9 +72,7 @@ def execute_command(obj, options={})
66
72
  result
67
73
  end
68
74
  else
69
- connect unless connecting?
70
- do_work
71
- :connecting
75
+ :connecting
72
76
  end
73
77
  end
74
78
 
@@ -87,23 +91,68 @@ def stop
87
91
  sleep(0.1)
88
92
  end
89
93
  end
94
+ ensure_process_cleanup(@process_id, @keep_outfile ? nil : @out_file, 10)
95
+ @process_id = nil
90
96
  end
91
97
 
92
98
  private
93
99
 
100
+ def wait_for_process_to_exit(process_id, timeout)
101
+ with_timeout timeout do
102
+ begin
103
+ waitpid(process_id, Process::WNOHANG)
104
+ process_id = nil
105
+ true
106
+ rescue Errno::ECHILD => _
107
+ false
108
+ end
109
+ end
110
+ end
111
+
112
+ def ensure_process_cleanup(process_id, out_file, timeout)
113
+ Thread.new do
114
+ begin
115
+ unless process_id.nil?
116
+ process_id = nil if wait_for_process_to_exit(process_id, timeout)
117
+ end
118
+ ensure
119
+ unless process_id.nil?
120
+ begin
121
+ Process.kill('QUIT', process_id)
122
+ rescue Errno::ESRCH => _
123
+ end
124
+ end
125
+ File.unlink(out_file) if !out_file.nil? && File.exist?(out_file)
126
+ end
127
+ end
128
+ end
129
+
130
+ def with_timeout(timeout, sleep_time = 0.1, &block)
131
+ started = Time.now
132
+ while true do
133
+ return true if block.call
134
+ if Time.now > started + timeout
135
+ return false
136
+ end
137
+ sleep(sleep_time)
138
+ end
139
+ end
140
+
141
+
94
142
  def connected?
95
- @state == :connected && backend_running?
143
+ !@process_id.nil? && @state == :read_from_socket && backend_running?
96
144
  end
97
145
 
98
146
  def connecting?
99
- @state == :connecting
147
+ !@process_id.nil? && (@state == :wait_for_file || @state == :wait_for_port)
100
148
  end
101
149
 
102
150
  def backend_running?
103
151
  if @process_id
104
152
  begin
105
- return true unless waitpid(@process_id, Process::WNOHANG)
106
- rescue Errno::ECHILD
153
+ waitpid(@process_id, Process::WNOHANG)
154
+ return true
155
+ rescue Errno::ECHILD => _
107
156
  end
108
157
  end
109
158
  false
@@ -121,7 +170,7 @@ def tempfile_name
121
170
  end
122
171
 
123
172
  def connect
124
- @state = :connecting
173
+ return if connected?
125
174
  @connect_start_time = Time.now
126
175
 
127
176
  @logger.info @config.command if @logger
@@ -131,56 +180,75 @@ def connect
131
180
  else
132
181
  @out_file = tempfile_name
133
182
  end
134
- File.unlink(@out_file) if File.exist?(@out_file)
135
183
 
136
- Dir.chdir(File.dirname(@config.file)) do
137
- @process_id = spawn(@config.command.strip + " > #{@out_file} 2>&1")
184
+ if @process_id.nil?
185
+ File.unlink(@out_file) if File.exist?(@out_file)
186
+ Dir.chdir(File.dirname(@config.file)) do
187
+ @process_id = spawn(@config.command.strip + " > #{@out_file} 2>&1")
188
+ @state = :wait_for_file
189
+ end
138
190
  end
139
- @work_state = :wait_for_file
140
191
  end
141
192
 
142
193
  def do_work
143
- case @work_state
144
- when :wait_for_file
145
- if File.exist?(@out_file)
146
- @work_state = :wait_for_port
147
- end
148
- if Time.now > @connect_start_time + @connection_timeout
149
- cleanup
150
- @connection_listener.call(:timeout) if @connection_listener
151
- @work_state = :done
152
- @state = :off
153
- @logger.warn "process didn't startup (connection timeout)" if @logger
194
+ if @process_id.nil?
195
+ @state = :off
196
+ return false
197
+ end
198
+ if @state == :wait_for_port && !File.exist?(@out_file)
199
+ @state = :wait_for_file
200
+ end
201
+ if @state == :wait_for_file && File.exist?(@out_file)
202
+ @state = :wait_for_port
203
+ end
204
+ if @state == :wait_for_file
205
+ while true
206
+ if Time.now > @connect_start_time + @connection_timeout
207
+ cleanup
208
+ @connection_listener.call(:timeout) if @connection_listener
209
+ @state = :off
210
+ @logger.warn "process didn't startup (connection timeout)" if @logger
211
+ return false
212
+ end
213
+ sleep(0.1)
214
+ if File.exist?(@out_file)
215
+ @state = :wait_for_port
216
+ break
217
+ end
154
218
  end
155
- true
156
- when :wait_for_port
157
- output = File.read(@out_file)
158
- if output =~ /^RText service, listening on port (\d+)/
159
- port = $1.to_i
160
- @logger.info "connecting to #{port}" if @logger
161
- begin
162
- @socket = TCPSocket.new("127.0.0.1", port)
163
- @socket.setsockopt(:SOCKET, :RCVBUF, 1000000)
164
- rescue Errno::ECONNREFUSED
219
+ end
220
+ if @state == :wait_for_port
221
+ while true
222
+ break unless File.exist?(@out_file)
223
+ output = File.read(@out_file)
224
+ if output =~ /^RText service, listening on port (\d+)/
225
+ port = $1.to_i
226
+ @logger.info "connecting to #{port}" if @logger
227
+ begin
228
+ @socket = TCPSocket.new("127.0.0.1", port)
229
+ @socket.setsockopt(:SOCKET, :RCVBUF, 1000000)
230
+ rescue Errno::ECONNREFUSED
231
+ cleanup
232
+ @connection_listener.call(:timeout) if @connection_listener
233
+ @state = :off
234
+ @logger.warn "could not connect socket (connection timeout)" if @logger
235
+ return false
236
+ end
237
+ @state = :read_from_socket
238
+ @connection_listener.call(:connected) if @connection_listener
239
+ break
240
+ end
241
+ if Time.now > @connect_start_time + @connection_timeout
165
242
  cleanup
166
243
  @connection_listener.call(:timeout) if @connection_listener
167
- @work_state = :done
168
244
  @state = :off
169
245
  @logger.warn "could not connect socket (connection timeout)" if @logger
246
+ return false
170
247
  end
171
- @state = :connected
172
- @work_state = :read_from_socket
173
- @connection_listener.call(:connected) if @connection_listener
174
- end
175
- if Time.now > @connect_start_time + @connection_timeout
176
- cleanup
177
- @connection_listener.call(:timeout) if @connection_listener
178
- @work_state = :done
179
- @state = :off
180
- @logger.warn "could not connect socket (connection timeout)" if @logger
248
+ sleep(0.1)
181
249
  end
182
- true
183
- when :read_from_socket
250
+ end
251
+ if @state == :read_from_socket
184
252
  repeat = true
185
253
  socket_closed = false
186
254
  response_data = ""
@@ -208,13 +276,12 @@ def do_work
208
276
  end
209
277
  elsif !backend_running? || socket_closed
210
278
  cleanup
211
- @work_state = :done
279
+ @state = :off
212
280
  return false
213
281
  end
214
282
  end
215
- true
216
283
  end
217
-
284
+ true
218
285
  end
219
286
 
220
287
  def cleanup
@@ -224,7 +291,7 @@ def cleanup
224
291
  break unless backend_running?
225
292
  sleep(0.1)
226
293
  end
227
- File.unlink(@out_file) unless @keep_outfile
294
+ ensure_process_cleanup(@process_id, @keep_outfile ? @out_file : nil, 10)
228
295
  end
229
296
 
230
297
  end
@@ -247,7 +247,15 @@ class Instantiator
247
247
  element.setOrAddGeneric(feature.name, proxy)
248
248
  else
249
249
  begin
250
- element.setOrAddGeneric(feature.name, v.value)
250
+ v_value = v.value
251
+ feature_instance_class = feature.eType.instanceClass
252
+ if feature_instance_class == String && (v_value.is_a?(Float) || v_value.is_a?(Fixnum))
253
+ element.setOrAddGeneric(feature.name, v_value.to_s)
254
+ elsif feature_instance_class == Float && v_value.is_a?(Fixnum)
255
+ element.setOrAddGeneric(feature.name, v_value.to_f)
256
+ else
257
+ element.setOrAddGeneric(feature.name, v_value)
258
+ end
251
259
  rescue StandardError
252
260
  # backward compatibility for RGen versions not supporting BigDecimal
253
261
  if v.value.is_a?(BigDecimal)
@@ -302,9 +310,9 @@ class Instantiator
302
310
  elsif feature.eType.is_a?(RGen::ECore::EEnum)
303
311
  [:identifier, :string]
304
312
  else
305
- expected = { String => [:string, :identifier],
313
+ expected = { String => [:string, :identifier, :integer, :float],
306
314
  Integer => [:integer],
307
- Float => [:float],
315
+ Float => [:float, :integer],
308
316
  RGen::MetamodelBuilder::DataTypes::Boolean => [:boolean],
309
317
  Object => [:string, :identifier, :integer, :float, :boolean]
310
318
  }[feature.eType.instanceClass]