Class: Opener::Webservice::Server
- Inherits:
-
Sinatra::Base
- Object
- Sinatra::Base
- Opener::Webservice::Server
- Defined in:
- lib/opener/webservice/server.rb
Overview
The meat of the webservices: the actual Sinatra application. Components should extend this class and configure it (e.g. to specify what component class to use).
Constant Summary collapse
- INPUT_FIELDS =
List of fields that can contain input to process.
%w{input input_url}
Class Method Summary collapse
-
.accepted_params ⇒ Array
Returns the accepted component parameters.
-
.accepted_params=(params) ⇒ Object
Sets the accepted component parameters.
-
.text_processor ⇒ Class
Returns the text processor to use.
-
.text_processor=(processor) ⇒ Object
Sets the text processor to use.
Instance Method Summary collapse
-
#/ ⇒ Object
Processes the input using a component.
-
#analyze(options) ⇒ Array
Analyzes the input and returns an Array containing the output and content type.
-
#analyze_async(options, request_id) ⇒ Object
Analyzes the input asynchronously.
-
#async ⇒ Object
Runs the block in a separate thread.
-
#authenticate! ⇒ Object
Authenticates the current request.
-
#json_input? ⇒ TrueClass|FalseClass
Returns ‘true` if the input data is in JSON, false otherwise.
-
#params_from_json ⇒ Hash
Returns a Hash containing the parameters from a JSON payload.
-
#process_async(options) ⇒ Hash
Processes a request asynchronously, results are submitted to the next callback URL.
-
#process_sync(options) ⇒ String
Processes a request synchronously, results are sent as the response upon completion.
-
#submit_output(output, request_id, options) ⇒ Object
Submits the output to the next callback URL.
Class Method Details
.accepted_params ⇒ Array
Returns the accepted component parameters.
31 32 33 |
# File 'lib/opener/webservice/server.rb', line 31 def self.accepted_params return @accepted_params ||= [] end |
.accepted_params=(params) ⇒ Object
Sets the accepted component parameters. Parameter names are always stored as symbols.
22 23 24 |
# File 'lib/opener/webservice/server.rb', line 22 def self.accepted_params=(params) @accepted_params = params.map(&:to_sym) end |
.text_processor ⇒ Class
Returns the text processor to use.
49 50 51 |
# File 'lib/opener/webservice/server.rb', line 49 def self.text_processor return @text_processor end |
.text_processor=(processor) ⇒ Object
Sets the text processor to use.
40 41 42 |
# File 'lib/opener/webservice/server.rb', line 40 def self.text_processor=(processor) @text_processor = processor end |
Instance Method Details
#/ ⇒ Object
Processes the input using a component.
Data can be submitted in two ways:
-
As regular POST fields
-
A single JSON object as the POST body
When submitting data, you can use the following fields (either as POST fields or as the fields of a JSON object):
| Field | Description | |:—————|:——————————————–| | input | The raw input text/KAF to process | | input_url | A URL to a document to download and process | | callbacks | An array of callback URLs | | error_callback | A URL to submit errors to | | request_id | A unique ID to associate with the document | | metadata | A custom metadata object to store in S3 |
In case of a JSON object the input body would look something like the following:
{"input": "Hello world, this is....", request_id: "123abc"}
78 79 80 |
# File 'lib/opener/webservice/server.rb', line 78 get '/' do erb :index end |
#analyze(options) ⇒ Array
Analyzes the input and returns an Array containing the output and content type.
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/opener/webservice/server.rb', line 179 def analyze() = InputSanitizer.new.( , self.class.accepted_params ) input = InputExtractor.new.extract() processor = self.class.text_processor.new() output = processor.run(input) if processor.respond_to?(:output_type) type = processor.output_type else type = :xml end return output, type end |
#analyze_async(options, request_id) ⇒ Object
Analyzes the input asynchronously.
204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/opener/webservice/server.rb', line 204 def analyze_async(, request_id) output, _ = analyze() submit_output(output, request_id, ) # Submit the error to the error callback, re-raise so Rollbar can also # report it. rescue Exception => error ErrorHandler.new.submit(error, request_id) if ['error_callback'] raise error end |
#async ⇒ Object
Runs the block in a separate thread. When running a test environment the block is instead yielded normally.
288 289 290 291 292 293 294 |
# File 'lib/opener/webservice/server.rb', line 288 def async if self.class.environment == :test yield else Thread.new { yield } end end |
#authenticate! ⇒ Object
Authenticates the current request.
272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/opener/webservice/server.rb', line 272 def authenticate! token = Configuration.authentication_token secret = Configuration.authentication_secret creds = {token => params[token], secret => params[secret]} response = HTTPClient.get(Configuration.authentication_endpoint, creds) unless response.ok? halt(403, "Authentication failed: #{response.body}") end end |
#json_input? ⇒ TrueClass|FalseClass
Returns ‘true` if the input data is in JSON, false otherwise
265 266 267 |
# File 'lib/opener/webservice/server.rb', line 265 def json_input? return request.content_type == 'application/json' end |
#params_from_json ⇒ Hash
Returns a Hash containing the parameters from a JSON payload. The keys of this Hash are returned as strings to prevent Symbol DOS attacks.
256 257 258 |
# File 'lib/opener/webservice/server.rb', line 256 def params_from_json return JSON.load(request.body.read) end |
#process_async(options) ⇒ Hash
Processes a request asynchronously, results are submitted to the next callback URL.
158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/opener/webservice/server.rb', line 158 def process_async() request_id = ['request_id'] || SecureRandom.hex final_url = ['callbacks'].last async { analyze_async(, request_id) } content_type :json return JSON.dump( :request_id => request_id, :output_url => "#{final_url}/#{request_id}" ) end |
#process_sync(options) ⇒ String
Processes a request synchronously, results are sent as the response upon completion.
143 144 145 146 147 148 149 |
# File 'lib/opener/webservice/server.rb', line 143 def process_sync() output, ctype = analyze() content_type(ctype) return output end |
#submit_output(output, request_id, options) ⇒ Object
Submits the output to the next callback URL.
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/opener/webservice/server.rb', line 224 def submit_output(output, request_id, ) callbacks = ['callbacks'].dup next_url = callbacks.shift # Re-use the old payload so that any extra data (e.g. metadata) is kept # in place. new_payload = .merge( 'callbacks' => callbacks, 'request_id' => request_id ) # Make sure we don't re-send this to the next component. new_payload.delete('input') if Configuration.output_bucket uploader = Uploader.new object = uploader.upload(request_id, output, ['metadata']) new_payload['input_url'] = object.url_for(:read, :expires => 3600) else new_payload['input'] = output end CallbackHandler.new.post(next_url, new_payload) end |