ampedxx-yrpc 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/inspectionProfiles/Project_Default.xml +6 -0
- data/.idea/misc.xml +4 -0
- data/.idea/modules.xml +8 -0
- data/.idea/vcs.xml +6 -0
- data/.idea/workspace.xml +782 -0
- data/.idea/yrpc.iml +23 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +30 -0
- data/LICENSE.txt +21 -0
- data/README.md +207 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/yrpc-cli +19 -0
- data/lib/yrpc.rb +29 -0
- data/lib/yrpc/client.rb +79 -0
- data/lib/yrpc/configuration.rb +48 -0
- data/lib/yrpc/controllers/base.rb +47 -0
- data/lib/yrpc/controllers/request.rb +91 -0
- data/lib/yrpc/controllers/response.rb +104 -0
- data/lib/yrpc/controllers/service_binder.rb +87 -0
- data/lib/yrpc/error/response_error.rb +12 -0
- data/lib/yrpc/executor/executor.rb +29 -0
- data/lib/yrpc/helpers/autoload.rb +13 -0
- data/lib/yrpc/interceptors/active_record.rb +26 -0
- data/lib/yrpc/interceptors/base.rb +19 -0
- data/lib/yrpc/interceptors/client_interceptor.rb +97 -0
- data/lib/yrpc/interceptors/register.rb +28 -0
- data/lib/yrpc/outbound/request_context.rb +69 -0
- data/lib/yrpc/server.rb +82 -0
- data/lib/yrpc/version.rb +3 -0
- data/yrpc.gemspec +35 -0
- metadata +166 -0
data/lib/yrpc/client.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
module Yrpc
|
2
|
+
class Client < SimpleDelegator
|
3
|
+
|
4
|
+
def initialize(service:, options: {}, client_options: {})
|
5
|
+
@base_klass = service
|
6
|
+
@service_klass = "#{base_klass}::Service".constantize
|
7
|
+
@opts = options || {}
|
8
|
+
@opts[:password] = options.fetch(:password, '').to_s
|
9
|
+
@opts[:hostname] = options.fetch(:hostname, Yrpc.default_client_host)
|
10
|
+
client = "#{service}::Stub".constantize.new(@opts[:hostname], build_ssl_credentials, interceptors: [*client_options[:interceptors]])
|
11
|
+
super(client)
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :service_klass
|
15
|
+
attr_reader :base_klass
|
16
|
+
attr_reader :opts
|
17
|
+
|
18
|
+
def invoke(request_method, params = {}, metadata={}, opts={}, &block)
|
19
|
+
request_method = request_method.to_sym
|
20
|
+
req = streaming_request?(request_method) ? params : request_object(request_method, params)
|
21
|
+
md = build_metadata(metadata)
|
22
|
+
call_sig = call_signature(request_method)
|
23
|
+
raise NotImplementedError, "The method #{request_method} has not been implemented in this service." unless call_sig
|
24
|
+
resp = execute(call_sig, req, md, opts, &block)
|
25
|
+
p resp
|
26
|
+
Response.new(resp)
|
27
|
+
end
|
28
|
+
|
29
|
+
def build_metadata(metadata = {})
|
30
|
+
unless opts[:password].empty?
|
31
|
+
username = opts.fetch(:username, 'grpc').to_s
|
32
|
+
username = username.empty? ? '' : "#{username}:"
|
33
|
+
auth_string = Base64.encode64("#{username}#{opts[:password]}")
|
34
|
+
metadata[:authorization] = "Basic #{auth_string}".tr("\n", '')
|
35
|
+
end
|
36
|
+
metadata
|
37
|
+
end
|
38
|
+
|
39
|
+
def execute(call_sig, req, metadata, opts = {}, &block)
|
40
|
+
# Timer.time do
|
41
|
+
opts[:return_op] = true
|
42
|
+
opts[:metadata] = metadata
|
43
|
+
# end
|
44
|
+
send(call_sig, req, opts, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def rpc_desc(request_method)
|
48
|
+
service_klass.rpc_descs[request_method]
|
49
|
+
end
|
50
|
+
|
51
|
+
def request_object(request_method, params = {})
|
52
|
+
desc = rpc_desc(request_method)
|
53
|
+
desc && desc.input ? desc.input.new(params) : nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def call_signature(request_method)
|
57
|
+
desc = rpc_desc(request_method)
|
58
|
+
desc && desc.name ? desc.name.to_s.underscore.to_sym : nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def build_ssl_credentials
|
62
|
+
cert = nil
|
63
|
+
if opts[:ssl_certificate_file]
|
64
|
+
cert = File.read(opts[:ssl_certificate_file]).to_s.strip
|
65
|
+
elsif opts[:ssl_certificate]
|
66
|
+
cert = opts[:ssl_certificate].to_s.strip
|
67
|
+
end
|
68
|
+
|
69
|
+
cert ? GRPC::Core::ChannelCredentials.new(cert) : :this_channel_is_insecure
|
70
|
+
end
|
71
|
+
|
72
|
+
def streaming_request?(request_method)
|
73
|
+
desc = rpc_desc(request_method)
|
74
|
+
desc && (desc.client_streamer? || desc.bidi_streamer?)
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative "interceptors/active_record"
|
2
|
+
require 'logger'
|
3
|
+
module Yrpc
|
4
|
+
module Configuration
|
5
|
+
VALID_CONFIG_KEYS = {
|
6
|
+
server_binding_url: '0.0.0.0:9001',
|
7
|
+
interceptors: nil,
|
8
|
+
use_default_interceptors: true,
|
9
|
+
default_client_host: '',
|
10
|
+
controllers_path: 'app/controllers',
|
11
|
+
server_options: {},
|
12
|
+
services: [],
|
13
|
+
logger:nil,
|
14
|
+
use_ssl: false,
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
attr_accessor *VALID_CONFIG_KEYS.keys
|
18
|
+
|
19
|
+
def self.extended(base)
|
20
|
+
base.reset
|
21
|
+
end
|
22
|
+
|
23
|
+
def configure
|
24
|
+
yield self
|
25
|
+
end
|
26
|
+
|
27
|
+
def options
|
28
|
+
opts = {}
|
29
|
+
VALID_CONFIG_KEYS.each_key do |k|
|
30
|
+
opts.merge!(k => send(k))
|
31
|
+
end
|
32
|
+
opts
|
33
|
+
end
|
34
|
+
|
35
|
+
#重制一些配置
|
36
|
+
def reset
|
37
|
+
VALID_CONFIG_KEYS.each do |k, v|
|
38
|
+
send((k.to_s + '='), v)
|
39
|
+
end
|
40
|
+
self.logger = ::Logger.new(STDOUT)
|
41
|
+
self.interceptors = Yrpc::Interceptors::Registry.new
|
42
|
+
if use_default_interceptors
|
43
|
+
interceptors.use(Yrpc::Interceptors::ActiveRecord::ResetConnection)
|
44
|
+
end
|
45
|
+
options
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Yrpc
|
2
|
+
module Controllers
|
3
|
+
class Base
|
4
|
+
include ActiveSupport::Callbacks
|
5
|
+
|
6
|
+
define_callbacks :call
|
7
|
+
|
8
|
+
attr_reader :request
|
9
|
+
|
10
|
+
|
11
|
+
def initialize(method_key:, service:, rpc_desc:, active_call:, message:)
|
12
|
+
@request = Request.new(
|
13
|
+
method_key: method_key,
|
14
|
+
service: service,
|
15
|
+
rpc_desc: rpc_desc,
|
16
|
+
active_call: active_call,
|
17
|
+
message: message
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.before_action(methods)
|
22
|
+
[*methods].each do |method|
|
23
|
+
set_callback :call, :before, method
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.after_action(methods)
|
28
|
+
[*methods].each do |method|
|
29
|
+
set_callback :call, :after, method
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def self.bind(service_class)
|
35
|
+
Yrpc.services << service_class.name.constantize
|
36
|
+
ServiceBinder.new(service_class).bind!(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def call(method_key, &block)
|
41
|
+
run_callbacks :call do
|
42
|
+
send(method_key, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Yrpc
|
2
|
+
module Controllers
|
3
|
+
|
4
|
+
class Request
|
5
|
+
|
6
|
+
attr_reader :message
|
7
|
+
# @var [GRPC::ActiveCall] active_call
|
8
|
+
attr_reader :active_call
|
9
|
+
# @var [Symbol] method_key
|
10
|
+
attr_reader :method_key
|
11
|
+
# @var [Grpc::Controllers::Request::Type] type
|
12
|
+
attr_reader :type
|
13
|
+
# @var [Class] service
|
14
|
+
attr_reader :service
|
15
|
+
|
16
|
+
delegate :metadata, to: :active_call
|
17
|
+
delegate :messages, :client_streamer?, :server_streamer?, :bidi_streamer?, :request_response?, to: :type
|
18
|
+
|
19
|
+
##
|
20
|
+
# Abstract representation of a gRPC request type
|
21
|
+
#
|
22
|
+
class Type
|
23
|
+
delegate :client_streamer?, :server_streamer?, :bidi_streamer?, :request_response?, to: :@rpc_desc
|
24
|
+
|
25
|
+
##
|
26
|
+
# Initialize a new request type object
|
27
|
+
#
|
28
|
+
# @param [GRPC::RpcDesc] rpc_desc The RPC descriptor for the request type
|
29
|
+
#
|
30
|
+
def initialize(rpc_desc)
|
31
|
+
@rpc_desc = rpc_desc
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
|
37
|
+
#struct GRPC::RpcDesc
|
38
|
+
def initialize(method_key:, service:, rpc_desc:, active_call:, message:)
|
39
|
+
@method_key = method_key
|
40
|
+
@service = service
|
41
|
+
@active_call = active_call
|
42
|
+
@message = message
|
43
|
+
@rpc_desc = rpc_desc
|
44
|
+
@type = Type.new(rpc_desc)
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def service_key
|
49
|
+
@service.name.underscore.tr('/', '.').gsub('.service', '')
|
50
|
+
end
|
51
|
+
|
52
|
+
def method_missing(method_id, *arguments, &block)
|
53
|
+
method_message = *arguments.join
|
54
|
+
if (method_id.to_s =~ /^raise_[\w]+/) == 0
|
55
|
+
error_type = method_id.to_s.split('raise_')[1].upcase!
|
56
|
+
code = "Yrpc::Response::Code::#{error_type}".constantize
|
57
|
+
message = method_message
|
58
|
+
raise Yrpc::Error::ResponseError.new(code, message)
|
59
|
+
else
|
60
|
+
super
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def response_class
|
66
|
+
@rpc_desc.output
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def request_class
|
71
|
+
@rpc_desc.input
|
72
|
+
end
|
73
|
+
|
74
|
+
# grpc 中的 service.method
|
75
|
+
def method_name
|
76
|
+
"#{service_key}.#{method_key}"
|
77
|
+
end
|
78
|
+
|
79
|
+
# 返回这个request的所有mesage 要根据stremer类型来判断
|
80
|
+
def messages
|
81
|
+
if client_streamer?
|
82
|
+
message.call { |msg| yield msg }
|
83
|
+
elsif bidi_streamer?
|
84
|
+
message
|
85
|
+
else
|
86
|
+
[message]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Yrpc
|
2
|
+
|
3
|
+
class Response
|
4
|
+
|
5
|
+
module Code
|
6
|
+
# 添加模型常量国际化方法
|
7
|
+
# include Dictionary::Module::I18n
|
8
|
+
|
9
|
+
################################################################################
|
10
|
+
#
|
11
|
+
# 20000 成功
|
12
|
+
#
|
13
|
+
################################################################################
|
14
|
+
|
15
|
+
SUCCESS = '20000'
|
16
|
+
|
17
|
+
################################################################################
|
18
|
+
#
|
19
|
+
# 3xxxx 数据相关
|
20
|
+
#
|
21
|
+
################################################################################
|
22
|
+
|
23
|
+
# 用户绑定第三方账户
|
24
|
+
|
25
|
+
# 第三方账户已绑定其它用户
|
26
|
+
PROVIDER_BIND_ANOTHER_USER = '30010'
|
27
|
+
|
28
|
+
################################################################################
|
29
|
+
#
|
30
|
+
# 4xxxx 业务相关
|
31
|
+
#
|
32
|
+
################################################################################
|
33
|
+
|
34
|
+
# 非法请求
|
35
|
+
INVALID_REQUEST = '40300'
|
36
|
+
|
37
|
+
# 终端密钥错误
|
38
|
+
INVALID_TERMINAL_SESSION_KEY = '40301'
|
39
|
+
|
40
|
+
# 用户密钥错误
|
41
|
+
INVALID_USER_SESSION_KEY = '40302'
|
42
|
+
|
43
|
+
# 超出请求限制数
|
44
|
+
EXCEED_REQUEST_LIMIT = '40303'
|
45
|
+
|
46
|
+
# 版本号不适配
|
47
|
+
NOT_COMPATIBLE_REVISION = '40304'
|
48
|
+
|
49
|
+
# 访问令牌过期
|
50
|
+
ACCESS_TOKEN_EXPIRED = '40305'
|
51
|
+
|
52
|
+
################################################################################
|
53
|
+
#
|
54
|
+
# 5xxxx 系统相关
|
55
|
+
#
|
56
|
+
################################################################################
|
57
|
+
|
58
|
+
# 未知错误(通常在捕捉异常后使用)
|
59
|
+
ERROR = '50000'
|
60
|
+
|
61
|
+
# 请求参数缺失
|
62
|
+
# Todo: 移动到数据相关
|
63
|
+
MISS_REQUEST_PARAMS = '50001'
|
64
|
+
|
65
|
+
# 数据处理错误
|
66
|
+
# Todo: 移动到数据相关
|
67
|
+
DATA_PROCESS_ERROR = '51000'
|
68
|
+
|
69
|
+
# 数据缺失错误
|
70
|
+
# Todo: 移动到数据相关
|
71
|
+
DATA_MISS_ERROR = '51001'
|
72
|
+
|
73
|
+
ORDER_PAYMENT_COMPLETED = '55000'
|
74
|
+
|
75
|
+
NEED_LOGIN = '40100'
|
76
|
+
|
77
|
+
ERROR_VALIDATE_CODE = '40200'
|
78
|
+
|
79
|
+
# 全部
|
80
|
+
# ALL = get_all_constants.map { |constant| constant.to_s.downcase }
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def initialize(operation, execution_time = nil)
|
85
|
+
@operation = operation
|
86
|
+
@message = operation.execute
|
87
|
+
@metadata = operation.metadata
|
88
|
+
@trailing_metadata = operation.trailing_metadata
|
89
|
+
@deadline = operation.deadline
|
90
|
+
@cancelled = operation.cancelled?
|
91
|
+
@execution_time = execution_time || 0.0
|
92
|
+
end
|
93
|
+
|
94
|
+
def message
|
95
|
+
@message ||= @operation.execute
|
96
|
+
end
|
97
|
+
|
98
|
+
def status
|
99
|
+
@message ||= @operation.execute
|
100
|
+
@message&.status
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Yrpc
|
2
|
+
module Controllers
|
3
|
+
|
4
|
+
class ServiceBinder
|
5
|
+
##
|
6
|
+
#未来可能会有一些desc 的 拓展,先预留一个肉便器类。
|
7
|
+
#
|
8
|
+
class BoundDesc < SimpleDelegator;
|
9
|
+
end
|
10
|
+
|
11
|
+
#初始化。。没什么好解释的
|
12
|
+
def initialize(service)
|
13
|
+
@service = service
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# 通过controller绑定所有的方法
|
18
|
+
def bind!(controller)
|
19
|
+
rpc_methods.each { |name, desc| bind_method(controller, name, desc) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def rpc_desc(request_method)
|
23
|
+
@service.rpc_descs[request_method]
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
|
29
|
+
#打开类并且进行一个方法define,返回给这个方法打call。这里要注意的是request 会以参数形式构造进controller
|
30
|
+
#这里也涉及到stream 类型。
|
31
|
+
def bind_method(controller, method_name, desc)
|
32
|
+
method_desc = method_name.to_s.to_sym
|
33
|
+
method_key = method_name.to_s.underscore.to_sym
|
34
|
+
current_desc = rpc_desc(method_desc)
|
35
|
+
service_ref = @service
|
36
|
+
@service.class_eval do
|
37
|
+
if desc.request_response?
|
38
|
+
define_method(method_key) do |message, active_call|
|
39
|
+
c = controller.new(method_key: method_key, service: service_ref, message: message, active_call: active_call, rpc_desc: desc)
|
40
|
+
begin
|
41
|
+
c.call(method_key)
|
42
|
+
rescue => e
|
43
|
+
p method_key
|
44
|
+
p e.backtrace_locations
|
45
|
+
desc && desc.output ? desc.output.new(status: {code: e.respond_to?(:code) ? e.code : Yrpc::Response::Code::ERROR , message: e.message}) : (raise e)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
elsif desc.client_streamer?
|
49
|
+
define_method(method_key) do |active_call|
|
50
|
+
c = controller.new(method_key: method_key, service: service_ref, message: proc { |&block| active_call.each_remote_read(&block) }, active_call: active_call, rpc_desc: desc)
|
51
|
+
begin
|
52
|
+
c.call(method_key)
|
53
|
+
rescue => e
|
54
|
+
desc && desc.output ? desc.output.new(status: {code: e&.code || Yrpc::Response::Code::ERROR, message: e.message}) : (raise e)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
elsif desc.server_streamer?
|
58
|
+
define_method(method_key) do |message, active_call, &block|
|
59
|
+
c = controller.new(method_key: method_key, service: service_ref, message: message, active_call: active_call, rpc_desc: desc)
|
60
|
+
begin
|
61
|
+
c.call(method_key)
|
62
|
+
rescue => e
|
63
|
+
desc && desc.output ? desc.output.new(status: {code: e&.code || Yrpc::Response::Code::ERROR , message: e.message}) : (raise e)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
else # bidi
|
67
|
+
define_method(method_key) do |messages, active_call, &block|
|
68
|
+
c = controller.new(method_key: method_key, service: service_ref, message: messages, active_call: active_call, rpc_desc: desc)
|
69
|
+
begin
|
70
|
+
c.call(method_key)
|
71
|
+
rescue => e
|
72
|
+
desc && desc.output ? desc.output.new(status: {code: e&.code || Yrpc::Response::Code::ERROR, message: e.message}) : (raise e)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# 讲方法都代理到boundDesc 上
|
81
|
+
#
|
82
|
+
def rpc_methods
|
83
|
+
@service.rpc_descs.map { |rd| BoundDesc.new(rd) }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|