ampedxx-yrpc 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|