opener-webservice 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,7 @@
1
+ require 'sinatra/base'
2
+
3
+ module Opener
4
+ class Webservice < Sinatra::Base
5
+ VERSION = "1.0.0"
6
+ end
7
+ end
@@ -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: