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 +4 -4
- data/lib/rbbt/rest/workflow.rb +2 -2
- data/lib/rbbt/rest/workflow/jobs.rb +10 -4
- data/lib/rbbt/rest/workflow/stream_task.rb +197 -250
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8cd9cb57ee4c5ac78055eaf4975e9348c9d29a5
|
4
|
+
data.tar.gz: 46bdc357be5ba35777fe28fcb075c8db6c401dd0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d68415e1bac3b673fac9c82601994685101cf6b50084d57998c686fcd3daf916b41b4ebbf8b48d45f29eb811973c2b093d4e6e55b9f210cf72537f99829c6629
|
7
|
+
data.tar.gz: 68c1f4f76ce25a9d5f6eef4f1ddeab673843fc8b6f6820327ae17e3318d5305b0b38b021aa18e999b9b9cebb9fbce7671cd03e47299904d00841383f2f7431e9
|
data/lib/rbbt/rest/workflow.rb
CHANGED
@@ -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 ==
|
141
|
-
recursive_clean_job(workflow, job) if update ==
|
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
|
172
|
-
job
|
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
|
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
|
-
|
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
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
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
|
-
|
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
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
-
|
110
|
+
job.join unless job.done?
|
86
111
|
else
|
87
|
-
|
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
|
-
|
93
|
-
sout.close
|
128
|
+
job
|
94
129
|
end
|
95
130
|
|
96
|
-
def
|
131
|
+
def _merge_chunks(sin, sout)
|
97
132
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
-
|
117
|
-
sout.close
|
166
|
+
end
|
118
167
|
end
|
119
168
|
|
120
|
-
def
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
-
|
130
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
216
|
+
inputs, stream_input, filename, stream, boundary = get_inputs(content_type, tcp_merged_io)
|
155
217
|
|
156
|
-
task =
|
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
|
-
|
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
|
-
|
222
|
+
job_url = File.join("/", workflow.to_s, task, job.name)
|
216
223
|
|
217
|
-
|
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.
|
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-
|
11
|
+
date: 2016-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|