class THTP::MiddlewareStack
An implementation of the middleware pattern (a la Rack) for RPC handling. Extracts RPCs from a Thrift service and passes requests to a handler via a middleware stack. Note, NOT threadsafe – mount all desired middlewares before calling.
Public Class Methods
new(thrift_service, handlers)
click to toggle source
@param thrift_service [Class] The Thrift service from which to extract RPCs @param handlers [Object,Array<Object>] An object or objects responding to
each defined RPC; if multiple respond, the first will be used
# File lib/thtp/middleware_stack.rb, line 12 def initialize(thrift_service, handlers) # initialise middleware stack as empty with a generic dispatcher at the bottom @stack = [] @dispatcher = ->(rpc, *rpc_args, **_rpc_opts) do handler = Array(handlers).find { |h| h.respond_to?(rpc) } raise NoMethodError, "No handler for rpc #{rpc}" unless handler handler.public_send(rpc, *rpc_args) # opts are for middleware use only end # define instance methods for each RPC Utils.extract_rpcs(thrift_service).each do |rpc| define_singleton_method(rpc) { |*rpc_args_and_opts| call(rpc, *rpc_args_and_opts) } end end
Public Instance Methods
call(rpc, *rpc_args, **rpc_opts)
click to toggle source
Freezes and execute the middleware stack culminating in the RPC itself
# File lib/thtp/middleware_stack.rb, line 42 def call(rpc, *rpc_args, **rpc_opts) compose.call(rpc, *rpc_args, **rpc_opts) end
use(middleware_class, *middleware_args)
click to toggle source
Nests a middleware at the bottom of the stack (closest to the function call). A middleware is any class implementing call
and calling app.call in turn., i.e.,
class PassthroughMiddleware def initialize(app, *opts) @app = app end def call(rpc, *rpc_args, **rpc_opts) @app.call(rpc, *rpc_args, **rpc_opts) end end
# File lib/thtp/middleware_stack.rb, line 37 def use(middleware_class, *middleware_args) @stack << [middleware_class, middleware_args] end
Private Instance Methods
compose()
click to toggle source
compose stack functions into one callable: [f, g, h] => f . g . h
# File lib/thtp/middleware_stack.rb, line 49 def compose @app ||= @stack.freeze.reverse_each. # rubocop:disable Naming/MemoizedInstanceVariableName reduce(@dispatcher) { |app, (mw, mw_args)| mw.new(app, *mw_args) } end