Skip to content

Instantly share code, notes, and snippets.

@zaneclaes
Last active April 28, 2019 08:46
Show Gist options
  • Save zaneclaes/aabe749144be22480c30a5791f8f5d19 to your computer and use it in GitHub Desktop.
Save zaneclaes/aabe749144be22480c30a5791f8f5d19 to your computer and use it in GitHub Desktop.
# MIT License
#
# Copyright (c) 2018, Zane Claes
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
module Gateway
class GrpcGatewayError < StandardError; end
class HealthError < GrpcGatewayError; end
class ConfigurationError < GrpcGatewayError; end
class RpcNotFoundError < GrpcGatewayError; end
class Proxy
attr_reader :services
# @param stub_services [Hash] mapping of a service_name to an instance of a stub service.
# @param error_presenter [Proc] a method that turns exceptions into a hash.
def initialize(stub_services = {}, &block)
@function_map = {} # func name => hash containing details
@services = {}
@error_presenter = block
map_functions(stub_services)
end
# Return a hash of all the healthchecks from all the services.
def healthcheck
Hash[@services.map do |service_name, stub|
hc = stub.send(:healthcheck, Google::Protobuf::Empty.new)
raise HealthError, "#{service_name} is not healthy." unless hc && hc.processID > 0
[service_name, hc]
end]
end
def function(function_name, noisy = true)
func = @function_map[GRPC::GenericService.underscore(function_name.to_s).to_sym]
raise RpcNotFoundError, "#{function_name} does not exist." if noisy && !func
func
end
def graphql
@graphql ||= Graphql.new(self, @error_presenter)
end
# Execute a function with given params.
def rpc(function_name, params = {}, metadata = {})
function(function_name).call(params, metadata || {})
end
def respond_to_missing?(method, include_private=false)
!!function(method, false)
end
# Proxy methods through to the services, instead of calling rpc()
def method_missing(method, *args, &block)
return rpc(method, args.first, args.second) if function(method)
super
end
private
# Add to the function_map by inspecting each service for the RPCs it provides.
def map_functions(stub_services)
stub_services.keys.each do |service_name|
stub = @services[service_name] = stub_services[service_name]
stub.class.to_s.gsub('::Stub', '::Service').constantize.rpc_descs.values.each do |d|
if d.name.to_sym == :Healthcheck
next
end
grpc_func = Gateway::Function.new(service_name, stub, d)
if @function_map.key?(grpc_func.name)
sn = @function_map[grpc_func.name].service_name
raise ConfigurationError, "#{grpc_func.name} was already defined on #{sn}."
end
@function_map[grpc_func.name] = grpc_func
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment