class Opener::Webservice::Server
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).
Constants
- INPUT_FIELDS
List of fields that can contain input to process.
@return [Array]
Public Class Methods
Returns the accepted component parameters.
@return [Array]
# File lib/opener/webservice/server.rb, line 31 def self.accepted_params return @accepted_params ||= [] end
Sets the accepted component parameters. Parameter names are always stored as symbols.
@param [Array] params
# File lib/opener/webservice/server.rb, line 22 def self.accepted_params=(params) @accepted_params = params.map(&:to_sym) end
Returns the text processor to use.
@return [Class]
# File lib/opener/webservice/server.rb, line 49 def self.text_processor return @text_processor end
Sets the text processor to use.
@param [Class] processor
# File lib/opener/webservice/server.rb, line 40 def self.text_processor=(processor) @text_processor = processor end
Public Instance Methods
Shows a form that allows users to submit data directly from their browser.
# File lib/opener/webservice/server.rb, line 83 get '/' do erb :index end
@param [Hash] options
# File lib/opener/webservice/server.rb, line 277 def add_transaction_parameters(options) # If raw input is given we'll trim it so the payload isn't too large for # Rollbar/New Relic. This uses Hash#merge so we don't modify the # original options variable. if options['input'] options = options.merge( 'input' => options['input'].byteslice(0, 256) ) end Transaction.current.add_parameters(options) end
Analyzes the input and returns an Array containing the output and content type.
@param [Hash] options @return [Array]
# File lib/opener/webservice/server.rb, line 191 def analyze(options) add_transaction_parameters(options) comp_options = InputSanitizer.new.whitelist_options( options, self.class.accepted_params ) input = InputExtractor.new.extract(options) processor = self.class.text_processor.new(comp_options) output = processor.run(input) if processor.respond_to?(:output_type) type = processor.output_type else type = :xml end return output, type end
Analyzes the input asynchronously.
@param [Hash] options @param [String] request_id
# File lib/opener/webservice/server.rb, line 218 def analyze_async(options, request_id) output, _ = analyze(options) submit_output(output, request_id, options) # 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 options['error_callback'] raise error end
Runs the block in a separate thread. When running a test environment the block is instead yielded normally.
# File lib/opener/webservice/server.rb, line 328 def async if self.class.environment == :test yield else Thread.new { yield } end end
Authenticates the current request.
# File lib/opener/webservice/server.rb, line 312 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
Returns `true` if the input data is in JSON, false otherwise
@return [TrueClass|FalseClass]
# File lib/opener/webservice/server.rb, line 305 def json_input? return request.content_type == 'application/json' end
Returns a Hash containing the parameters from a JSON payload. The keys of this Hash are returned as strings to prevent Symbol DOS attacks.
@return [Hash]
# File lib/opener/webservice/server.rb, line 296 def params_from_json return JSON.load(request.body.read) end
Processes a request asynchronously, results are submitted to the next callback URL.
@param [Hash] options @return [Hash]
# File lib/opener/webservice/server.rb, line 165 def process_async(options) request_id = options['request_id'] || SecureRandom.hex final_url = options['callbacks'].last Core::Syslog.info( "Processing asynchronous request with final URL #{final_url}", :request_id => request_id ) async { analyze_async(options, request_id) } content_type :json return JSON.dump( :request_id => request_id, :output_url => "#{final_url}/#{request_id}" ) end
Processes a request synchronously, results are sent as the response upon completion.
@param [Hash] options @return [String]
# File lib/opener/webservice/server.rb, line 148 def process_sync(options) output, ctype = analyze(options) content_type(ctype) Transaction.reset_current return output end
Submits the output to the next callback URL.
@param [String] output @param [String] request_id @param [Hash] options
# File lib/opener/webservice/server.rb, line 238 def submit_output(output, request_id, options) callbacks = options['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 = options.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 Core::Syslog.info( "Uploading output to s3://#{Configuration.output_bucket}", :request_id => request_id ) uploader = Uploader.new object = uploader.upload(request_id, output, options['metadata']) new_payload['input_url'] = object.url_for(:read, :expires => 3600) else new_payload['input'] = output end Core::Syslog.info( "Submitting output to #{next_url}", :request_id => request_id ) CallbackHandler.new.post(next_url, new_payload) end