rbbt-rest 1.8.10 → 1.8.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1bbeba3d4ef508ff35ecfe2210b1d3b12d03a9d9
4
- data.tar.gz: 809cd9b359f9658d5090a3a1ecdefbdcec706cde
3
+ metadata.gz: c8cd9cb57ee4c5ac78055eaf4975e9348c9d29a5
4
+ data.tar.gz: 46bdc357be5ba35777fe28fcb075c8db6c401dd0
5
5
  SHA512:
6
- metadata.gz: 4b72a79a9580da0803d84881d085861a47760be7d7cfce50a4e6e4322c1d3a3696a8cf0d4589fdc810fea0b76b6f4234ff41ed39f4b63c11e332876578e6bd81
7
- data.tar.gz: 81f55b8dfeefd7294f41a9ea695e80c692fd35c6a2f9634f3f6bee3ccc84497a7ed9bd1ba313002242f94a6b574c9c58503a97b70d3460c7a1061e3bdacbd4ac
6
+ metadata.gz: d68415e1bac3b673fac9c82601994685101cf6b50084d57998c686fcd3daf916b41b4ebbf8b48d45f29eb811973c2b093d4e6e55b9f210cf72537f99829c6629
7
+ data.tar.gz: 68c1f4f76ce25a9d5f6eef4f1ddeab673843fc8b6f6820327ae17e3318d5305b0b38b021aa18e999b9b9cebb9fbce7671cd03e47299904d00841383f2f7431e9
@@ -137,8 +137,8 @@ module Sinatra
137
137
 
138
138
  job = workflow.load_id(File.join(task, job))
139
139
 
140
- clean_job(workflow, job) if update == :clean
141
- recursive_clean_job(workflow, job) if update == :recursive_clean
140
+ clean_job(workflow, job) and halt 200 if update.to_s == "clean"
141
+ recursive_clean_job(workflow, job) and halt 200 if update.to_s == "recursive_clean"
142
142
 
143
143
  begin
144
144
  started = job.started?
@@ -168,8 +168,8 @@ module WorkflowRESTHelpers
168
168
  inputs = prepare_job_inputs(workflow, task, params)
169
169
  job = workflow.job(task, jobname, inputs)
170
170
 
171
- job.clean if update == :clean
172
- job.recursive_clean if update == :recursive_clean
171
+ clean_job(workflow, job) and clean = true if update.to_s == "clean"
172
+ recursive_clean_job(workflow, job) and clean = true if update.to_s == "recursive_clean"
173
173
 
174
174
  execution_type = execution_type(workflow, task)
175
175
 
@@ -240,16 +240,22 @@ module WorkflowRESTHelpers
240
240
  def recursive_clean_job(workflow, job)
241
241
  job.recursive_clean
242
242
 
243
- if ajax
243
+ if format == :jobname
244
+ halt 200, job.name
245
+ elsif ajax
244
246
  halt 200
245
247
  else
246
248
  redirect to(File.join("/", workflow.to_s, job.task_name.to_s))
247
249
  end
248
250
  end
251
+
249
252
  def clean_job(workflow, job)
250
253
  job.clean
251
254
 
252
- if ajax
255
+
256
+ if format == :jobname
257
+ halt 200, job.name
258
+ elsif ajax
253
259
  halt 200
254
260
  else
255
261
  redirect to(File.join("/", workflow.to_s, job.task_name.to_s))
@@ -1,312 +1,259 @@
1
1
  class StreamWorkflowTask
2
+ include WorkflowRESTHelpers
3
+ include RbbtRESTHelpers
4
+
2
5
  def initialize(app)
3
6
  @app = app
4
7
  end
5
8
 
9
+ EOL = "\r\n"
10
+
11
+ def parse_uri(env)
12
+ uri = env["REQUEST_URI"]
13
+ _n, workflow, task = uri.split("/")
14
+ workflow = begin
15
+ Kernel.const_get(workflow)
16
+ rescue
17
+ raise "Could not accept task for workflow: #{ workflow }"
18
+ end
19
+ [workflow, task]
20
+ end
21
+
6
22
  def read_normal_inputs(io, boundary, stream_input)
7
- content = ""
8
- content_start = false
9
- variable = nil
10
- filename = nil
11
23
  inputs = {}
12
24
 
25
+ input_name = nil
26
+ variable_chunk = nil
27
+ filename = nil
28
+
13
29
  while line = io.gets
14
30
  line.chomp!
15
31
 
16
- if line == "--" + boundary
17
- if variable
18
- inputs[variable] = content
32
+ chunk_start = line == "--" + boundary
33
+
34
+ if chunk_start
35
+ if input_name
36
+ inputs[input_name] = variable_chunk
19
37
  end
20
38
  content_start = false
21
- content = ""
39
+ elsif content_start
40
+ if variable_chunk.empty?
41
+ variable_chunk << line
42
+ else
43
+ variable_chunk << "\n" << line
44
+ end
22
45
  elsif line =~ /^Content.* name="([^\s;"]*)"/
23
- variable = $1
46
+ input_name = $1
24
47
  filename = line.match(/filename="([^"]+)"/)[1] if line =~ /filename/
25
- content = ""
26
48
  elsif line.empty?
49
+ variable_chunk = ""
50
+ break if input_name == stream_input
27
51
  content_start = true
28
- break if variable == stream_input
29
- else
30
- content << line if content_start
31
52
  end
32
53
  end
33
54
 
34
55
  [inputs, filename]
35
56
  end
36
57
 
37
- def parse_uri(env)
38
- uri = env["REQUEST_URI"]
39
- _n, workflow, task = uri.split("/")
40
- workflow = begin
41
- Kernel.const_get(workflow)
42
- rescue
43
- raise "Could not accept task for workflow: #{ workflow }"
44
- end
45
- [workflow, task]
58
+ def copy_until_boundary(sin, sout, boundary)
59
+ while line = sin.gets
60
+ break if line.include? boundary
61
+ sout.write line
62
+ end
46
63
  end
47
64
 
48
- EOL = "\r\n"
49
- def read_chunk(sin, rest = "")
50
- parts = []
51
- c = sin.read(1024)
52
- #c = sin.gets
53
- raise "Early connection close" if c.nil?
54
- c = rest << c unless rest.empty?
55
- c = c[2..-1] if c[0..1] == EOL
56
- index = c.index EOL
57
- while index
58
- part = c[0..index-1]
59
- parts << part
60
- c = c[index+2..-1]
61
- index = c.index EOL
62
- end
63
- rest = c
64
- [parts, rest]
65
+ def get_inputs(content_type, stream)
66
+ boundary = content_type.match(/boundary=([^\s;]*)/)[1]
67
+ stream_input = content_type.match(/stream=([^\s;]*)/)[1]
68
+ inputs, filename = read_normal_inputs(stream, boundary, stream_input)
69
+
70
+ IndiferentHash.setup(inputs)
71
+
72
+ [inputs, stream_input, filename, stream, boundary]
65
73
  end
66
74
 
67
- def copy_chunked_stream(sin, sout, boundary)
68
-
69
- rest = ""
70
- done = false
71
- content = false
72
-
73
- while not done
74
- parts, rest = read_chunk(sin, rest)
75
- while parts.any?
76
- part = parts.shift
77
- if content
78
- part.split("\n").each do |line|
79
- sout.puts line
80
- if line.include? boundary
81
- done = true
82
- break
83
- end
75
+ def run_job(workflow, task, inputs, stream_input, stream, boundary, filename = nil)
76
+ name = inputs.delete "jobname"
77
+
78
+ task_parameters = prepare_job_inputs(workflow, task, inputs)
79
+
80
+ Misc.add_stream_filename(stream, filename) if filename
81
+
82
+ task_parameters[stream_input] = stream
83
+
84
+ task = task.to_sym
85
+
86
+ job = workflow.job(task, name, task_parameters)
87
+
88
+ execution_type = case
89
+ when workflow.exec_exports.include?(task)
90
+ "exec"
91
+ when workflow.synchronous_exports.include?(task)
92
+ "synchronous"
93
+ when workflow.asynchronous_exports.include?(task)
94
+ "asynchronous"
95
+ else
96
+ raise "No known export type for #{ workflow } #{ task }. Accesses denied"
97
+ end
98
+
99
+ execution_type = "exec" if inputs["_cache_type"] == 'exec'
100
+
101
+ begin
102
+ case execution_type
103
+ when "exec", nil
104
+ job.exec(:stream)
105
+ when "sync", "synchronous", "async", "asynchronous"
106
+ if job.done? or job.started?
107
+ done_consumer = Thread.new do
108
+ Misc.consume_stream(stream, false)
84
109
  end
85
- content = false
110
+ job.join unless job.done?
86
111
  else
87
- content = true
112
+ job.run(:stream)
88
113
  end
114
+ else
115
+ raise "Unknown execution_type: #{execution_type}"
89
116
  end
117
+
118
+ rescue Aborted, Interrupt
119
+ job.abort
120
+ stream.write "HTTP/1.1 500\r\n"
121
+ stream.close_write
122
+ rescue Exception
123
+ job.exception $!
124
+ stream.write "HTTP/1.1 500\r\n"
125
+ stream.close_write
90
126
  end
91
127
 
92
- sout.write rest
93
- sout.close
128
+ job
94
129
  end
95
130
 
96
- def merge_chunks(sin, sout)
131
+ def _merge_chunks(sin, sout)
97
132
 
98
- rest = ""
99
- done = false
100
- content = true
101
-
102
- while not done
103
- chunk_size_str = ""
104
- while chunk_size_str.strip.empty?
105
- chunk_size_str = sin.gets
106
- raise "Error reading chunks" if chunk_size_str.nil?
133
+ begin
134
+ while true
135
+ chunk_size_str = ""
136
+ stop = false
137
+ while chunk_size_str.strip.empty?
138
+ chunk_size_str = sin.gets
139
+ raise "Empty chunk size" if chunk_size_str.nil? or chunk_size_str.strip.empty?
140
+ chunk_size_str = "" if chunk_size_str.nil?
141
+ end
142
+ break if stop
143
+ size = chunk_size_str.strip.to_i(16)
144
+ break if size == 0
145
+ chunk = sin.read(size)
146
+ bound = sin.read(2)
147
+ raise "bound not right: #{ bound }" if bound != EOL
148
+ raise "Size does not match: #{[chunk.length, size] * " != "}" if chunk.length != size
149
+ sout.write chunk
150
+ end
151
+ rescue Aborted
152
+ raise $!
153
+ rescue Exception
154
+ Log.exception $!
155
+ raise $!
156
+ ensure
157
+ if sin.respond_to? :close_read
158
+ sin.close_read
159
+ else
160
+ sin.close unless sin.closed?
161
+ end
162
+ if sin.respond_to? :threads
163
+ sin.threads.each do |th| th.raise Aborted end
107
164
  end
108
- size = chunk_size_str.strip.to_i(16)
109
- break if size == 0
110
- chunk = sin.read(size)
111
- bound = sin.read(2)
112
- raise "Size does not match" if false and chunk.length != size
113
- sout.write chunk
114
- end
115
165
 
116
- sout.write rest
117
- sout.close
166
+ end
118
167
  end
119
168
 
120
- def copy_until_boundary(sin, sout, boundary)
121
- while line = sin.gets
122
- break if line.include? boundary
123
- sout.write line
169
+ def merge_chunks(sin, sout, buffer)
170
+ if buffer.nil?
171
+ _merge_chunks(sin, sout)
172
+ else
173
+ ssin = Misc.open_pipe do |s|
174
+ begin
175
+ s << buffer
176
+ while c = sin.readpartial(Misc::BLOCK_SIZE)
177
+ s << c
178
+ end
179
+ rescue Aborted, IOError
180
+ rescue Exception
181
+ ensure
182
+ sin.close_read
183
+ s.close
184
+ end
185
+ end
186
+ _merge_chunks(ssin, sout)
124
187
  end
125
188
  end
126
189
 
190
+ def do_stream(env)
191
+ uri = env["REQUEST_URI"]
192
+ post = env["REQUEST_METHOD"]
193
+ hijack = !!env["rack.hijack"]
194
+ content_type = env["CONTENT_TYPE"]
195
+ encoding = env["HTTP_TRANSFER_ENCODING"]
196
+ id = env["HTTP_RBBT_ID"]
197
+ id = id + ": " + Thread.current.object_id.to_s if id
198
+
199
+ post == "POST" and hijack and content_type and content_type.include? "Rbbt_Param_Stream" and encoding == 'chunked'
200
+ end
127
201
 
128
202
  def call(env)
129
- if env["REQUEST_METHOD"] == "POST" and env["rack.hijack"] and env["CONTENT_TYPE"] and env["CONTENT_TYPE"].include? "Rbbt_Param_Stream" and env["HTTP_TRANSFER_ENCODING"] == 'chunked'
130
- Log.high "Hijacking post data"
131
- inputs = {}
132
- content_type = env["CONTENT_TYPE"]
133
- boundary = content_type.match(/boundary=([^\s;]*)/)[1]
134
- stream_input = content_type.match(/stream=([^\s;]*)/)[1]
135
- post_stream_chunked = env["rack.hijack"].call
136
-
137
- job_url = nil
203
+
204
+ if do_stream(env)
138
205
  begin
139
- post_stream = Misc.open_pipe do |sin|
140
- merge_chunks(post_stream_chunked, sin)
141
- end
142
206
 
143
- inputs, filename = read_normal_inputs(post_stream, boundary, stream_input)
207
+ client = env["rack.hijack"]
208
+ buffer = client.instance_variable_get('@buffer')
209
+ tcp_io = client.call
210
+ Log.low "YES Hijacking post data #{tcp_io}"
144
211
 
145
- input_stream_out, input_stream_in = Misc.pipe
146
- Misc.add_stream_filename(input_stream_out, filename) if filename
147
- inputs[stream_input] = input_stream_out
212
+ content_type = env["CONTENT_TYPE"]
148
213
 
149
- workflow, task = parse_uri(env)
150
- name = inputs.delete "jobname"
151
- job = workflow.job(task, name, inputs)
152
- Log.high "Run job #{job.path} with inputs #{Misc.fingerprint(inputs)}"
214
+ tcp_merged_io = Misc.open_pipe do |sin| merge_chunks(tcp_io, sin, buffer) end
153
215
 
154
- job_url = File.join("/", workflow.to_s, task, job.name)
216
+ inputs, stream_input, filename, stream, boundary = get_inputs(content_type, tcp_merged_io)
155
217
 
156
- task = task.to_sym
157
- execution_type = case
158
- when workflow.exec_exports.include?(task)
159
- "exec"
160
- when workflow.synchronous_exports.include?(task)
161
- "synchronous"
162
- when workflow.asynchronous_exports.include?(task)
163
- "asynchronous"
164
- else
165
- raise "No known export type for #{ workflow } #{ task }. Accesses denied"
166
- end
167
-
168
- execution_type = "exec" if inputs["_cache_type"] == 'exec'
169
- Log.info "Streaming task with execution_type: #{ execution_type }"
170
-
171
- case execution_type
172
- when "exec", nil
173
- job.exec(:stream)
174
- when "sync", "synchronous", "async", "asynchronous"
175
- if job.done?
176
- done_consumer = Thread.new do
177
- while c = post_stream.read(1024)
178
- end
179
- end
180
- else
181
- job.run(:stream)
182
- end
183
- else
184
- raise "Unknown execution_type: #{execution_type}"
185
- end
218
+ workflow, task = parse_uri(env)
186
219
 
187
- t_in = Thread.new do
188
- begin
189
- copy_until_boundary(post_stream, input_stream_in, boundary)
190
- input_stream_in.close
191
- post_stream.close_read
192
- rescue
193
- Log.exception $!
194
- end
195
- end unless job.done?
196
-
197
- job_output = TSV.get_stream job
198
- t_out = Thread.new do
199
- begin
200
- post_stream_chunked.write "HTTP/1.1 200\r\n"
201
- post_stream_chunked.write "RBBT-STREAMING-JOB-URL: #{ job_url }\r\n"
202
- post_stream_chunked.write "\r\n"
203
- while c = job_output.read(1024)
204
- post_stream_chunked.write c
205
- end
206
- job_output.join if job_output.respond_to? :join
207
- post_stream_chunked.close_write
208
- done_consumer.join if done_consumer
209
- rescue
210
- Log.exception $!
211
- job.abort
212
- end
213
- end
220
+ job = run_job(workflow, task, inputs, stream_input, stream, boundary, filename)
214
221
 
215
- end
222
+ job_url = File.join("/", workflow.to_s, task, job.name)
216
223
 
217
- [200, {}, nil]
224
+ out_stream = TSV.get_stream job
225
+
226
+ begin
227
+ Log.low "Write response #{tcp_io} "
228
+ tcp_io.write "HTTP/1.1 200\r\n"
229
+ tcp_io.write "Connection: close\r\n"
230
+ tcp_io.write "RBBT-STREAMING-JOB-URL: #{ job_url }\r\n"
231
+ tcp_io.write "\r\n"
232
+ Log.low "Comsuming response #{tcp_io}"
233
+ Misc.consume_stream(out_stream, false, tcp_io)
234
+ Log.low "Comsumed response #{tcp_io}"
235
+ rescue Exception
236
+ Log.exception $!
237
+ end if out_stream
238
+
239
+ tcp_io.close unless tcp_io.closed?
240
+ Log.low "Closed io #{tcp_io}"
241
+
242
+ [-1, {}, []]
243
+ rescue
244
+ Log.exception $!
245
+ io.write "HTTP/1.1 515\r\n"
246
+ io.write "Connection: close\r\n"
247
+ io.write "\r\n"
248
+ io.close_write
249
+ raise $!
250
+ end
218
251
  else
219
252
  Log.high "NOT Hijacking post data"
253
+
220
254
  @app.call(env)
221
255
  end
222
256
  end
223
257
 
224
- #def call_old(env)
225
- # if env["REQUEST_METHOD"] == "POST" and env["rack.hijack"] and env["CONTENT_TYPE"] and env["CONTENT_TYPE"].include? "Rbbt_Param_Stream" and env["HTTP_TRANSFER_ENCODING"] == 'chunked'
226
- # Log.high "Hijacking post data"
227
- # inputs = {}
228
- # content_type = env["CONTENT_TYPE"]
229
- # boundary = content_type.match(/boundary=([^\s;]*)/)[1]
230
- # stream_input = content_type.match(/stream=([^\s;]*)/)[1]
231
- # post_stream = env["rack.hijack"].call
232
- # job_url = nil
233
- # begin
234
- # inputs, filename = read_normal_inputs(post_stream, boundary, stream_input)
235
-
236
- # input_stream_out, input_stream_in = Misc.pipe
237
- # Misc.add_stream_filename(input_stream_out, filename) if filename
238
- # inputs[stream_input] = input_stream_out
239
-
240
- # workflow, task = parse_uri(env)
241
- # name = inputs.delete "jobname"
242
- # job = workflow.job(task, name, inputs)
243
- # Log.high "Run job #{job.path} with inputs #{Misc.fingerprint(inputs)}"
244
-
245
- # job_url = File.join("/", workflow.to_s, task, job.name)
246
-
247
- # task = task.to_sym
248
- # execution_type = case
249
- # when workflow.exec_exports.include?(task)
250
- # "exec"
251
- # when workflow.synchronous_exports.include?(task)
252
- # "synchronous"
253
- # when workflow.asynchronous_exports.include?(task)
254
- # "asynchronous"
255
- # else
256
- # raise "No known export type for #{ workflow } #{ task }. Accesses denied"
257
- # end
258
-
259
- # execution_type = "exec" if inputs["_cache_type"] == 'exec'
260
- # Log.info "Streaming task with execution_type: #{ execution_type }"
261
-
262
- # case execution_type
263
- # when "exec", nil
264
- # job.exec(:stream)
265
- # when "sync", "synchronous", "async", "asynchronous"
266
- # if job.done?
267
- # done_consumer = Thread.new do
268
- # while c = post_stream.read(1024)
269
- # end
270
- # end
271
- # else
272
- # job.run(:stream)
273
- # end
274
- # else
275
- # raise "Unknown execution_type: #{execution_type}"
276
- # end
277
-
278
- # t_in = Thread.new do
279
- # begin
280
- # copy_chunked_stream(post_stream, input_stream_in, boundary)
281
- # rescue
282
- # Log.exception $!
283
- # end
284
- # end unless job.done?
285
-
286
- # job_output = TSV.get_stream job
287
- # t_out = Thread.new do
288
- # begin
289
- # post_stream.write "HTTP/1.1 200\r\n"
290
- # post_stream.write "RBBT-STREAMING-JOB-URL: #{ job_url }\r\n"
291
- # post_stream.write "\r\n"
292
- # while c = job_output.read(1024)
293
- # post_stream.write c
294
- # end
295
- # job_output.join if job_output.respond_to? :join
296
- # post_stream.close_write
297
- # done_consumer.join if done_consumer
298
- # rescue
299
- # Log.exception $!
300
- # job.abort
301
- # end
302
- # end
303
-
304
- # end
305
- # [200, {}, nil]
306
- # else
307
- # Log.high "NOT Hijacking post data"
308
- # @app.call(env)
309
- # end
310
- #end
311
258
  end
312
259
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbbt-rest
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.10
4
+ version: 1.8.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Vazquez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-19 00:00:00.000000000 Z
11
+ date: 2016-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake