exe/faastruby-server in faastruby-0.4.8 vs exe/faastruby-server in faastruby-0.4.9

- old
+ new

@@ -1,200 +1,74 @@ #!/usr/bin/env ruby - -require 'sinatra' -require 'sinatra/multi_route' require 'yaml' require 'oj' require 'faastruby-rpc' require 'base64' +require 'faastruby/server' +require 'sinatra' +require 'sinatra/multi_route' +require 'colorize' +FaaStRuby::EventHub.listen_for_events! -module FaaStRuby - class DoubleRenderError < StandardError; end +set :port, 3000 +set :bind, '0.0.0.0' +case ARGV.shift +when '-p' + set :port, ARGV.shift +when '-b', '-o' + set :bind, ARGV.shift end +set :server, %w[puma] +set :show_exceptions, true -module FaaStRuby - class Runner - def initialize - @rendered = false - end - - def call(workspace_name, function_name, event, args) - begin - load "./#{workspace_name}/#{function_name}/handler.rb" - response = handler(event, *args) - return response if response.is_a?(FaaStRuby::Response) - body = { - 'error' => "Please use the helpers 'render' or 'respond_with' as your function return value." - } - FaaStRuby::Response.new(body: Oj.dump(body), status: 500, headers: {'Content-Type' => 'application/json'}) - rescue Exception => e - body = { - 'error' => e.message, - 'location' => e.backtrace&.first, - } - FaaStRuby::Response.new(body: Oj.dump(body), status: 500, headers: {'Content-Type' => 'application/json'}) - end - end - - def rendered! - @rendered = true - end - def rendered? - @rendered - end - - def respond_with(body, status: 200, headers: {}, binary: false) - raise FaaStRuby::DoubleRenderError.new("You called 'render' or 'respond_with' twice in your handler method") if rendered? - response = FaaStRuby::Response.new(body: body, status: status, headers: headers, binary: binary) - rendered! - response - end - - def render( - js: nil, - body: nil, - inline: nil, - html: nil, - json: nil, - yaml: nil, - text: nil, - data: nil, - png: nil, - svg: nil, - jpeg: nil, - gif: nil, - icon: nil, - status: 200, headers: {}, content_type: nil, binary: false - ) - headers["Content-Type"] = content_type if content_type - bin = false - case - when json - headers["Content-Type"] ||= "application/json" - resp_body = json.is_a?(String) ? json : Oj.dump(json) - when html, inline - headers["Content-Type"] ||= "text/html" - resp_body = html - when text - headers["Content-Type"] ||= "text/plain" - resp_body = text - when yaml - headers["Content-Type"] ||= "application/yaml" - resp_body = yaml.is_a?(String) ? yaml : YAML.load(yaml) - when body - headers["Content-Type"] ||= "application/octet-stream" - bin = binary - resp_body = bin ? Base64.urlsafe_encode64(body) : body - when data - headers["Content-Type"] ||= "application/octet-stream" - resp_body = Base64.urlsafe_encode64(data) - bin = true - when js - headers["Content-Type"] ||= "text/javascript" - resp_body = js - when png - headers["Content-Type"] ||= "image/png" - resp_body = Base64.urlsafe_encode64(png) - bin = true - when svg - headers["Content-Type"] ||= "image/svg+xml" - resp_body = svg - when jpeg - headers["Content-Type"] ||= "image/jpeg" - resp_body = Base64.urlsafe_encode64(jpeg) - bin = true - when gif - headers["Content-Type"] ||= "image/gif" - resp_body = Base64.urlsafe_encode64(gif) - bin = true - when icon - headers["Content-Type"] ||= "image/x-icon" - resp_body = Base64.urlsafe_encode64(icon) - bin = true - end - respond_with(resp_body, status: status, headers: headers, binary: bin) - end +register Sinatra::MultiRoute +route :get, :post, :put, :patch, :delete, '/:workspace_name/:function_name' do + path = "#{params[:workspace_name]}/#{params[:function_name]}" + headers = env.select { |key, value| key.include?('HTTP_') || ['CONTENT_TYPE', 'CONTENT_LENGTH', 'REMOTE_ADDR', 'REQUEST_METHOD', 'QUERY_STRING'].include?(key) } + if headers.has_key?("HTTP_FAASTRUBY_RPC") + body = nil + rpc_args = parse_body(request.body.read, headers['CONTENT_TYPE'], request.request_method) || [] + else + body = parse_body(request.body.read, headers['CONTENT_TYPE'], request.request_method) + rpc_args = [] end - - class Event < Struct + query_params = parse_query(request.query_string) + context = set_context(params[:workspace_name], params[:function_name]) + event = FaaStRuby::Event.new(body, query_params, headers, context) + response = FaaStRuby::Runner.new.call(params[:workspace_name], params[:function_name], event, rpc_args) + status response.status + headers response.headers + if response.binary? + response_body = Base64.urlsafe_decode64(response.body) + else + response_body = response.body end + puts "[#{path}] #=> status=#{response.status} body=#{response_body.inspect} headers=#{Oj.dump response.headers}".light_blue + body response_body +end - class Response - attr_accessor :body, :status, :headers, :binary - def initialize(body:, status: 200, headers: {}, binary: false) - @body = body - @status = status - @headers = headers - @binary = binary - end +def parse_body(body, content_type, method) + return nil if method == 'GET' + return {} if body.nil? && method != 'GET' + return Oj.load(body) if content_type == 'application/json' + return body +end - def binary? - @binary - end - end +def set_context(workspace_name, function_name) + return nil unless File.file?('context.yml') + yaml = YAML.load(File.read('context.yml')) + return nil unless yaml.has_key?(workspace_name) + yaml[workspace_name][function_name] end -class FaaStRubyServer < Sinatra::Application - set :port, 3000 - set :bind, '0.0.0.0' - case ARGV.shift - when '-p' - set :port, ARGV.shift - when '-b' - set :bind, ARGV.shift +def parse_query(query_string) + hash = {} + query_string.split('&').each do |param| + key, value = param.split('=') + hash[key] = value end - set :server, %w[puma] - set :run, false - set :show_exceptions, true - - register Sinatra::MultiRoute - route :get, :post, :put, :patch, :delete, '/:workspace_name/:function_name' do - e = FaaStRuby::Event.new(:body, :query_params, :headers, :context) - headers = env.select { |key, value| key.include?('HTTP_') || ['CONTENT_TYPE', 'CONTENT_LENGTH', 'REMOTE_ADDR', 'REQUEST_METHOD', 'QUERY_STRING'].include?(key) } - if headers.has_key?("HTTP_FAASTRUBY_RPC") - body = nil - rpc_args = parse_body(request.body.read, headers['CONTENT_TYPE'], request.request_method) || [] - else - body = parse_body(request.body.read, headers['CONTENT_TYPE'], request.request_method) - rpc_args = [] - end - query_params = parse_query(request.query_string) - context = set_context(params[:workspace_name], params[:function_name]) - event = e.new(body, query_params, headers, context) - response = FaaStRuby::Runner.new.call(params[:workspace_name], params[:function_name], event, rpc_args) - status response.status - headers response.headers - if response.binary? - body Base64.urlsafe_decode64(response.body) - else - body response.body - end - end - - def parse_body(body, content_type, method) - return nil if method == 'GET' - return {} if body.nil? && method != 'GET' - return Oj.load(body) if content_type == 'application/json' - return body - end - - def set_context(workspace_name, function_name) - return nil unless File.file?('context.yml') - yaml = YAML.load(File.read('context.yml')) - return nil unless yaml.has_key?(workspace_name) - yaml[workspace_name][function_name] - end - - def parse_query(query_string) - hash = {} - query_string.split('&').each do |param| - key, value = param.split('=') - hash[key] = value - end - hash - end - def self.run? - true - end + hash end +def self.run? + true +end -FaaStRubyServer.run! rescue nil # this will suppress some of the errors messages