rtext 0.8.0 → 0.9.3
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 +4 -4
- data/CHANGELOG +113 -84
- data/Project.yaml +14 -0
- data/RText_Protocol +47 -4
- data/lib/rtext/context_builder.rb +49 -8
- data/lib/rtext/default_completer.rb +212 -163
- data/lib/rtext/default_service_provider.rb +3 -3
- data/lib/rtext/frontend/connector.rb +122 -55
- data/lib/rtext/frontend/context.rb +12 -12
- data/lib/rtext/instantiator.rb +11 -3
- data/lib/rtext/language.rb +5 -5
- data/lib/rtext/serializer.rb +1 -1
- data/lib/rtext/service.rb +264 -253
- data/lib/rtext/tokenizer.rb +1 -1
- metadata +18 -43
- data/Rakefile +0 -46
- data/test/completer_test.rb +0 -606
- data/test/context_builder_test.rb +0 -948
- data/test/frontend/context_test.rb +0 -205
- data/test/instantiator_test.rb +0 -1691
- data/test/integration/backend.out +0 -13
- data/test/integration/crash_on_request_editor.rb +0 -12
- data/test/integration/ecore_editor.rb +0 -50
- data/test/integration/frontend.log +0 -36049
- data/test/integration/model/invalid_encoding.invenc +0 -2
- data/test/integration/model/test.crash_on_request +0 -18
- data/test/integration/model/test.crashing_backend +0 -18
- data/test/integration/model/test.dont_open_socket +0 -0
- data/test/integration/model/test.invalid_cmd_line +0 -0
- data/test/integration/model/test.not_in_rtext +0 -0
- data/test/integration/model/test_large_with_errors.ect3 +0 -43523
- data/test/integration/model/test_metamodel.ect +0 -24
- data/test/integration/model/test_metamodel2.ect +0 -5
- data/test/integration/model/test_metamodel_error.ect2 +0 -3
- data/test/integration/model/test_metamodel_ok.ect2 +0 -18
- data/test/integration/test.rb +0 -918
- data/test/link_detector_test.rb +0 -287
- data/test/message_helper_test.rb +0 -118
- data/test/rtext_test.rb +0 -11
- data/test/serializer_test.rb +0 -1004
- data/test/tokenizer_test.rb +0 -173
@@ -1,163 +1,212 @@
|
|
1
|
-
require 'rgen/ecore/ecore_ext'
|
2
|
-
|
3
|
-
module RText
|
4
|
-
|
5
|
-
class DefaultCompleter
|
6
|
-
|
7
|
-
CompletionOption
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
(
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
def
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
end
|
161
|
-
|
162
|
-
end
|
163
|
-
|
1
|
+
require 'rgen/ecore/ecore_ext'
|
2
|
+
|
3
|
+
module RText
|
4
|
+
|
5
|
+
class DefaultCompleter
|
6
|
+
|
7
|
+
class CompletionOption
|
8
|
+
|
9
|
+
attr_accessor :insert
|
10
|
+
attr_accessor :display
|
11
|
+
attr_accessor :extra
|
12
|
+
attr_accessor :description
|
13
|
+
|
14
|
+
def self.from_text_extra(text, extra)
|
15
|
+
self.new(text, text + ' ' + extra, nil, extra)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.for_curly_braces(context)
|
19
|
+
self.new("{\n#{context.line_indent}#{context.indent}||\n#{context.line_indent}}", '{}')
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.for_square_brackets
|
23
|
+
self.new('[ || ]', '[]', '')
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(insert, display, description=nil, extra=nil)
|
27
|
+
@insert = insert
|
28
|
+
@display = display
|
29
|
+
@description = description
|
30
|
+
@extra = extra
|
31
|
+
end
|
32
|
+
|
33
|
+
def text
|
34
|
+
@insert
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
# Creates a completer for RText::Language +language+.
|
40
|
+
#
|
41
|
+
def initialize(language)
|
42
|
+
@lang = language
|
43
|
+
end
|
44
|
+
|
45
|
+
# Provides completion options
|
46
|
+
#
|
47
|
+
def complete(context, version=0)
|
48
|
+
clazz = context && context.element && context.element.class.ecore
|
49
|
+
if clazz
|
50
|
+
if context.position.in_block
|
51
|
+
block_options(context, clazz)
|
52
|
+
elsif !context.problem
|
53
|
+
result = []
|
54
|
+
add_value_options(context, result, version) if context.feature
|
55
|
+
add_label_options(context, clazz, result, version) unless context.position.after_label
|
56
|
+
result
|
57
|
+
else
|
58
|
+
# missing comma, after curly brace, etc.
|
59
|
+
if version > 0 && !context.position.before_brace &&
|
60
|
+
context.element.class.ecore.eAllReferences.any? { |r| r.containment }
|
61
|
+
[CompletionOption.for_curly_braces(context)]
|
62
|
+
else
|
63
|
+
[]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
elsif context
|
67
|
+
root_options
|
68
|
+
else
|
69
|
+
[]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def block_options(context, clazz)
|
74
|
+
types = []
|
75
|
+
labled_refs = []
|
76
|
+
if context.feature
|
77
|
+
if context.feature.is_a?(RGen::ECore::EReference) && context.feature.containment
|
78
|
+
types = @lang.concrete_types(context.feature.eType)
|
79
|
+
else
|
80
|
+
# invalid, ignore
|
81
|
+
end
|
82
|
+
else
|
83
|
+
# all target types which don't need a label
|
84
|
+
# and all lables which are needed by a potential target type
|
85
|
+
@lang.containments(clazz).each do |r|
|
86
|
+
([r.eType] + r.eType.eAllSubTypes).select{|t| t.concrete}.each do |t|
|
87
|
+
if @lang.labeled_containment?(clazz, r) || @lang.containments_by_target_type(clazz, t).size > 1
|
88
|
+
labled_refs << r
|
89
|
+
else
|
90
|
+
types << t
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
types.uniq.
|
96
|
+
sort{|a,b| a.name <=> b.name}.collect do |c|
|
97
|
+
class_completion_option(c)
|
98
|
+
end +
|
99
|
+
labled_refs.uniq.collect do |r|
|
100
|
+
CompletionOption.from_text_extra("#{r.name}:", "<#{r.eType.name}>")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def add_value_options(context, result, version)
|
105
|
+
if context.feature.is_a?(RGen::ECore::EAttribute) || !context.feature.containment
|
106
|
+
if context.feature.is_a?(RGen::ECore::EReference)
|
107
|
+
result.concat(reference_options(context))
|
108
|
+
if version > 0 && !context.position.before_bracket && context.feature.upperBound != 1
|
109
|
+
result << CompletionOption.for_square_brackets
|
110
|
+
end
|
111
|
+
elsif context.feature.eType.is_a?(RGen::ECore::EEnum)
|
112
|
+
result.concat(enum_options(context))
|
113
|
+
elsif context.feature.eType.instanceClass == String
|
114
|
+
result.concat(string_options(context))
|
115
|
+
elsif context.feature.eType.instanceClass == Integer
|
116
|
+
result.concat(integer_options(context))
|
117
|
+
elsif context.feature.eType.instanceClass == Float
|
118
|
+
result.concat(float_options(context))
|
119
|
+
elsif context.feature.eType.instanceClass == RGen::MetamodelBuilder::DataTypes::Boolean
|
120
|
+
result.concat(boolean_options(context))
|
121
|
+
else
|
122
|
+
# no options
|
123
|
+
end
|
124
|
+
else
|
125
|
+
if version > 0 && !context.position.before_bracket && context.feature.upperBound != 1
|
126
|
+
result << CompletionOption.for_square_brackets
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def add_label_options(context, clazz, result, version)
|
132
|
+
result.concat(@lang.labled_arguments(clazz).
|
133
|
+
select{|f|
|
134
|
+
!context.element.eIsSet(f.name)}.collect do |f|
|
135
|
+
CompletionOption.from_text_extra("#{f.name}:", "<#{f.eType.name}>")
|
136
|
+
end )
|
137
|
+
if version > 0 && !context.position.after_comma &&
|
138
|
+
context.element.class.ecore.eAllReferences.any? { |r| r.containment } && !context.position.before_brace
|
139
|
+
result << CompletionOption.for_curly_braces(context)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def root_options
|
144
|
+
@lang.root_classes.
|
145
|
+
sort{|a,b| a.name <=> b.name}.collect do |c|
|
146
|
+
class_completion_option(c)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def reference_options(context)
|
151
|
+
[]
|
152
|
+
end
|
153
|
+
|
154
|
+
def enum_options(context)
|
155
|
+
context.feature.eType.eLiterals.collect do |l|
|
156
|
+
lname = l.name
|
157
|
+
if lname =~ /^\d|\W/ || lname == "true" || lname == "false"
|
158
|
+
lname = "\"#{lname.gsub("\\","\\\\\\\\").gsub("\"","\\\"").gsub("\n","\\n").
|
159
|
+
gsub("\r","\\r").gsub("\t","\\t").gsub("\f","\\f").gsub("\b","\\b")}\""
|
160
|
+
end
|
161
|
+
CompletionOption.from_text_extra("#{lname}", "<#{context.feature.eType.name}>")
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def string_options(context)
|
166
|
+
if @lang.unquoted?(context.feature)
|
167
|
+
[ CompletionOption.from_text_extra("#{context.feature.name.gsub(/\W/,"")}", value_description(context)) ]
|
168
|
+
else
|
169
|
+
[ CompletionOption.from_text_extra("\"\"", value_description(context)) ]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def get_default_value_completion(context)
|
174
|
+
return nil unless context.feature.defaultValue
|
175
|
+
CompletionOption.from_text_extra("#{context.feature.defaultValue}", value_description(context))
|
176
|
+
end
|
177
|
+
|
178
|
+
def integer_options(context)
|
179
|
+
default_comp = get_default_value_completion(context)
|
180
|
+
return [default_comp] if default_comp
|
181
|
+
(0..0).collect{|i| CompletionOption.from_text_extra("#{i}", value_description(context)) }
|
182
|
+
end
|
183
|
+
|
184
|
+
def float_options(context)
|
185
|
+
default_comp = get_default_value_completion(context)
|
186
|
+
return [default_comp] if default_comp
|
187
|
+
(0..0).collect{|i| CompletionOption.from_text_extra("#{i}.0", value_description(context)) }
|
188
|
+
end
|
189
|
+
|
190
|
+
def boolean_options(context)
|
191
|
+
[true, false].collect{|b| CompletionOption.from_text_extra("#{b}", value_description(context)) }
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
def value_description(context)
|
197
|
+
if context.position.after_label
|
198
|
+
"<#{context.feature.eType.name}>"
|
199
|
+
else
|
200
|
+
"[#{context.feature.name}] <#{context.feature.eType.name}>"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def class_completion_option(eclass)
|
205
|
+
uargs = @lang.unlabled_arguments(eclass).collect{|a| "<#{a.name}>"}.join(", ")
|
206
|
+
CompletionOption.from_text_extra(@lang.command_by_class(eclass.instanceClass), uargs)
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
@@ -35,17 +35,17 @@ class DefaultServiceProvider
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
def get_completion_options(context)
|
38
|
+
def get_completion_options(context, version=0)
|
39
39
|
completer = RText::DefaultCompleter.new(@lang)
|
40
40
|
class << completer
|
41
41
|
attr_accessor :service_provider
|
42
42
|
def reference_options(context)
|
43
43
|
service_provider.get_reference_completion_options(context).collect {|o|
|
44
|
-
DefaultCompleter::CompletionOption.
|
44
|
+
DefaultCompleter::CompletionOption.from_text_extra(o.identifier, "<#{o.type}>")}
|
45
45
|
end
|
46
46
|
end
|
47
47
|
completer.service_provider = self
|
48
|
-
completer.complete(context)
|
48
|
+
completer.complete(context, version)
|
49
49
|
end
|
50
50
|
|
51
51
|
ReferenceCompletionOption = Struct.new(:identifier, :type)
|
@@ -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] ||
|
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
|
-
|
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
|
-
|
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 == :
|
143
|
+
!@process_id.nil? && @state == :read_from_socket && backend_running?
|
96
144
|
end
|
97
145
|
|
98
146
|
def connecting?
|
99
|
-
@state == :
|
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
|
-
|
106
|
-
|
153
|
+
waitpid(@process_id, Process::WNOHANG)
|
154
|
+
return true
|
155
|
+
rescue Errno::ECHILD => _
|
107
156
|
end
|
108
157
|
end
|
109
158
|
false
|
@@ -121,66 +170,85 @@ def tempfile_name
|
|
121
170
|
end
|
122
171
|
|
123
172
|
def connect
|
124
|
-
|
173
|
+
return if connected?
|
125
174
|
@connect_start_time = Time.now
|
126
175
|
|
127
176
|
@logger.info @config.command if @logger
|
128
177
|
|
129
178
|
if @outfile_provider
|
130
|
-
@out_file = @outfile_provider.call
|
179
|
+
@out_file = File.expand_path(@outfile_provider.call)
|
131
180
|
else
|
132
|
-
@out_file = tempfile_name
|
181
|
+
@out_file = File.expand_path(tempfile_name)
|
133
182
|
end
|
134
|
-
File.unlink(@out_file) if File.exist?(@out_file)
|
135
183
|
|
136
|
-
|
137
|
-
@
|
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
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
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
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
@
|
163
|
-
|
164
|
-
|
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
|
-
|
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
|
-
|
183
|
-
|
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
|
-
@
|
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
|
-
|
294
|
+
ensure_process_cleanup(@process_id, @keep_outfile ? @out_file : nil, 10)
|
228
295
|
end
|
229
296
|
|
230
297
|
end
|