opener-webservice 1.0.0
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 +7 -0
- data/README.md +29 -0
- data/lib/opener/webservice/version.rb +7 -0
- data/lib/opener/webservice.rb +274 -0
- data/opener-webservice.gemspec +23 -0
- metadata +131 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d3c9e68800786848df8f2c1310b2063edbf58939
|
4
|
+
data.tar.gz: e3b445eb8a225c5811663fc7dc5b0077c9e16077
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2f8b4978233d0f11a62828388c425e535be83c4dd8de2a78b06d1fec9b74c322a752dcf0ad5a65a3f365cf318837e0b7fa49d95eac38c10dcf1672c4658e946b
|
7
|
+
data.tar.gz: 7980a3858ddfaf44d0c24c89097ee025352dbea0108b06085634f7df316d04e90c0fb5128705126919d8fb53e8cdff8fcb54b2abc93d7d12eb6b491ed2c951ee
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Opener::Webservice
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'opener-webservice'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install opener-webservice
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
@@ -0,0 +1,274 @@
|
|
1
|
+
require "uuidtools"
|
2
|
+
require "sinatra/base"
|
3
|
+
require "json"
|
4
|
+
require "opener/webservice/version"
|
5
|
+
|
6
|
+
module Opener
|
7
|
+
class Webservice < Sinatra::Base
|
8
|
+
configure do
|
9
|
+
enable :logging
|
10
|
+
end
|
11
|
+
|
12
|
+
configure :development do
|
13
|
+
set :raise_errors, true
|
14
|
+
set :dump_errors, true
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Presents a simple form that can be used for getting the NER of a KAF
|
19
|
+
# document.
|
20
|
+
#
|
21
|
+
get '/' do
|
22
|
+
erb :index
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Puts the text through the primary processor
|
27
|
+
#
|
28
|
+
# @param [Hash] params The POST parameters.
|
29
|
+
#
|
30
|
+
# @option params [String] :input the input to send to the processor
|
31
|
+
# @option params [Array<String>] :callbacks A collection of callback URLs
|
32
|
+
# that act as a chain. The results are posted to the first URL which is
|
33
|
+
# then shifted of the list.
|
34
|
+
# @option params [String] :error_callback Callback URL to send errors to
|
35
|
+
# when using the asynchronous setup.
|
36
|
+
#
|
37
|
+
post '/' do
|
38
|
+
if !params[:input] or params[:input].strip.empty?
|
39
|
+
logger.error('Failed to process the request: no input specified')
|
40
|
+
|
41
|
+
halt(400, 'No input specified')
|
42
|
+
end
|
43
|
+
|
44
|
+
callbacks = extract_callbacks(params[:callbacks])
|
45
|
+
error_callback = params[:error_callback]
|
46
|
+
|
47
|
+
if callbacks.empty?
|
48
|
+
process_sync
|
49
|
+
else
|
50
|
+
process_async(callbacks, error_callback)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# @return [HTTPClient]
|
56
|
+
#
|
57
|
+
def self.http_client
|
58
|
+
return @http_client || new_http_client
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# @return [HTTPClient]
|
63
|
+
#
|
64
|
+
def self.new_http_client
|
65
|
+
client = HTTPClient.new
|
66
|
+
client.connect_timeout = 120
|
67
|
+
|
68
|
+
return client
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Specifies the text processor to use or returns it if no parameter is
|
73
|
+
# given.
|
74
|
+
#
|
75
|
+
# @param [Class] processor
|
76
|
+
# @return [Class]
|
77
|
+
#
|
78
|
+
def self.text_processor(processor=nil)
|
79
|
+
if processor.nil?
|
80
|
+
return @processor
|
81
|
+
else
|
82
|
+
@processor = processor
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# Specifies what parameters are accepted.
|
88
|
+
#
|
89
|
+
# @param [Array] array The parameters to accept.
|
90
|
+
#
|
91
|
+
def self.accepted_params(*array)
|
92
|
+
if array.empty?
|
93
|
+
return @accepted_params
|
94
|
+
else
|
95
|
+
@accepted_params = array
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
##
|
100
|
+
# @return [Class]
|
101
|
+
#
|
102
|
+
def text_processor
|
103
|
+
self.class.text_processor
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# @return [Array]
|
108
|
+
#
|
109
|
+
def accepted_params
|
110
|
+
self.class.accepted_params
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# Processes the request synchronously.
|
115
|
+
#
|
116
|
+
def process_sync
|
117
|
+
output, type = analyze(filtered_params)
|
118
|
+
content_type(type)
|
119
|
+
body(output)
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# Filter the params hash based on the accepted_params
|
124
|
+
#
|
125
|
+
# @return [Hash] accepted params
|
126
|
+
#
|
127
|
+
def filtered_params
|
128
|
+
options = params.select{|k,v| accepted_params.include?(k.to_sym)}
|
129
|
+
cleaned = {}
|
130
|
+
options.each_pair do |k, v|
|
131
|
+
v = true if v == "true"
|
132
|
+
v = false if v == "false"
|
133
|
+
cleaned[k.to_sym] = v
|
134
|
+
end
|
135
|
+
|
136
|
+
return cleaned
|
137
|
+
end
|
138
|
+
|
139
|
+
##
|
140
|
+
# Processes the request asynchronously.
|
141
|
+
#
|
142
|
+
# @param [Array] callbacks The callback URLs to use.
|
143
|
+
#
|
144
|
+
def process_async(callbacks, error_callback)
|
145
|
+
request_id = get_request_id
|
146
|
+
output_url = callbacks.last
|
147
|
+
Thread.new do
|
148
|
+
analyze_async(filtered_params, request_id, callbacks, error_callback)
|
149
|
+
end
|
150
|
+
|
151
|
+
content_type :json
|
152
|
+
|
153
|
+
{
|
154
|
+
:request_id => request_id.to_s,
|
155
|
+
:output_url => [output_url, request_id].join("/")
|
156
|
+
}.to_json
|
157
|
+
end
|
158
|
+
|
159
|
+
##
|
160
|
+
# Gets the Analyzed output of an input.
|
161
|
+
#
|
162
|
+
# @param [Hash] options The options for the text_processor
|
163
|
+
# @return [String] output the output of the text_processor
|
164
|
+
# @return [Symbol] type the output type ot the text_processor
|
165
|
+
#
|
166
|
+
# @raise RunetimeError Raised when the tagging process failed.
|
167
|
+
#
|
168
|
+
def analyze(options)
|
169
|
+
processor = text_processor.new(options)
|
170
|
+
output, error, status = processor.run(options[:input])
|
171
|
+
|
172
|
+
if processor.respond_to?(:output_type)
|
173
|
+
type = processor.output_type
|
174
|
+
else
|
175
|
+
type = :xml
|
176
|
+
end
|
177
|
+
|
178
|
+
raise(error) if !status.nil? && !status.success?
|
179
|
+
|
180
|
+
return output, type
|
181
|
+
end
|
182
|
+
|
183
|
+
##
|
184
|
+
# Gets the NER of a KAF document and submits it to a callback URL.
|
185
|
+
#
|
186
|
+
# @param [String] text
|
187
|
+
# @param [String] request_id
|
188
|
+
# @param [Array] callbacks
|
189
|
+
# @param [String] error_callback
|
190
|
+
#
|
191
|
+
def analyze_async(options, request_id, callbacks, error_callback = nil)
|
192
|
+
begin
|
193
|
+
output, _ = analyze(options)
|
194
|
+
rescue => error
|
195
|
+
logger.error("Failed to process input: #{error.inspect}")
|
196
|
+
|
197
|
+
submit_error(error_callback, error.message) if error_callback
|
198
|
+
end
|
199
|
+
|
200
|
+
url = callbacks.shift
|
201
|
+
|
202
|
+
logger.info("Submitting results to #{url}")
|
203
|
+
|
204
|
+
begin
|
205
|
+
process_callback(url, output, request_id, callbacks, error_callback)
|
206
|
+
rescue => error
|
207
|
+
logger.error("Failed to submit the results: #{error.inspect}")
|
208
|
+
|
209
|
+
submit_error(error_callback, error.message) if error_callback
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
##
|
214
|
+
# @param [String] url
|
215
|
+
# @param [String] text
|
216
|
+
# @param [String] request_id
|
217
|
+
# @param [Array] callbacks
|
218
|
+
#
|
219
|
+
def process_callback(url, text, request_id, callbacks, error_callback)
|
220
|
+
# FIXME: this is a bit of a hack to prevent the webservice from clogging
|
221
|
+
# Airbrake during the hackathon. For whatever reason somebody is posting
|
222
|
+
# internal server errors from *somewhere*. Validation? What's that?
|
223
|
+
return if text =~ /^internal server error/i
|
224
|
+
|
225
|
+
output = {
|
226
|
+
:input => text,
|
227
|
+
:request_id => request_id,
|
228
|
+
:'callbacks[]' => callbacks,
|
229
|
+
:error_callback => error_callback
|
230
|
+
}
|
231
|
+
|
232
|
+
http_client.post_async(
|
233
|
+
url,
|
234
|
+
:body => filtered_params.merge(output)
|
235
|
+
)
|
236
|
+
end
|
237
|
+
|
238
|
+
##
|
239
|
+
# @param [String] url
|
240
|
+
# @param [String] message
|
241
|
+
#
|
242
|
+
def submit_error(url, message)
|
243
|
+
http_client.post_async(url, :body => {:error => message})
|
244
|
+
end
|
245
|
+
|
246
|
+
##
|
247
|
+
# Returns an Array containing the callback URLs, ignoring empty values.
|
248
|
+
#
|
249
|
+
# @param [Array|String] input
|
250
|
+
# @return [Array]
|
251
|
+
#
|
252
|
+
def extract_callbacks(input)
|
253
|
+
return [] if input.nil? || input.empty?
|
254
|
+
|
255
|
+
callbacks = input.compact.reject(&:empty?)
|
256
|
+
|
257
|
+
return callbacks
|
258
|
+
end
|
259
|
+
|
260
|
+
##
|
261
|
+
# @return [String]
|
262
|
+
#
|
263
|
+
def get_request_id
|
264
|
+
return params[:request_id] || UUIDTools::UUID.random_create
|
265
|
+
end
|
266
|
+
|
267
|
+
##
|
268
|
+
# @see Opener::Webservice.http_client
|
269
|
+
#
|
270
|
+
def http_client
|
271
|
+
return self.class.http_client
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.expand_path('../lib/opener/webservice/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "opener-webservice"
|
5
|
+
spec.version = Opener::Webservice::VERSION
|
6
|
+
spec.authors = ["development@olery.com"]
|
7
|
+
spec.summary = %q{Basic webservice hooks for the opener toolchain}
|
8
|
+
spec.description = spec.summary
|
9
|
+
|
10
|
+
spec.files = Dir.glob([
|
11
|
+
'lib/**/*',
|
12
|
+
'*.gemspec',
|
13
|
+
'README.md'
|
14
|
+
]).select { |file| File.file?(file) }
|
15
|
+
|
16
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
17
|
+
spec.add_development_dependency "rake"
|
18
|
+
spec.add_development_dependency "pry"
|
19
|
+
|
20
|
+
spec.add_dependency "sinatra", "~> 1.4.3"
|
21
|
+
spec.add_dependency "uuidtools"
|
22
|
+
spec.add_dependency "json"
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: opener-webservice
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- development@olery.com
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sinatra
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.4.3
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.4.3
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: uuidtools
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: json
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Basic webservice hooks for the opener toolchain
|
98
|
+
email:
|
99
|
+
executables: []
|
100
|
+
extensions: []
|
101
|
+
extra_rdoc_files: []
|
102
|
+
files:
|
103
|
+
- README.md
|
104
|
+
- lib/opener/webservice.rb
|
105
|
+
- lib/opener/webservice/version.rb
|
106
|
+
- opener-webservice.gemspec
|
107
|
+
homepage:
|
108
|
+
licenses: []
|
109
|
+
metadata: {}
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 2.2.2
|
127
|
+
signing_key:
|
128
|
+
specification_version: 4
|
129
|
+
summary: Basic webservice hooks for the opener toolchain
|
130
|
+
test_files: []
|
131
|
+
has_rdoc:
|