krpc 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/krpc.gemspec +24 -0
- data/lib/krpc.rb +1 -0
- data/lib/krpc/KRPC.pb.rb +125 -0
- data/lib/krpc/attributes.rb +81 -0
- data/lib/krpc/client.rb +130 -0
- data/lib/krpc/connection.rb +108 -0
- data/lib/krpc/core_extensions.rb +28 -0
- data/lib/krpc/decoder.rb +54 -0
- data/lib/krpc/doc.rb +124 -0
- data/lib/krpc/encoder.rb +60 -0
- data/lib/krpc/error.rb +33 -0
- data/lib/krpc/gen.rb +117 -0
- data/lib/krpc/protobuf_utils.rb +134 -0
- data/lib/krpc/repl_tools.rb +12 -0
- data/lib/krpc/service.rb +96 -0
- data/lib/krpc/types.rb +237 -0
- metadata +105 -0
data/lib/krpc/service.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'krpc/gen'
|
2
|
+
require 'krpc/attributes'
|
3
|
+
require 'krpc/doc'
|
4
|
+
|
5
|
+
module KRPC
|
6
|
+
module Services
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def create_service(service_msg, client)
|
10
|
+
service_name = service_msg.name
|
11
|
+
|
12
|
+
# Create service class
|
13
|
+
service_class = Class.new(ServiceBase)
|
14
|
+
const_set(service_name, service_class)
|
15
|
+
|
16
|
+
# Create service' classes
|
17
|
+
service_msg.classes.map(&:name).each do |sc_name|
|
18
|
+
client.type_store.as_type("Class(#{service_name}.#{sc_name})")
|
19
|
+
end
|
20
|
+
|
21
|
+
# Create service' enums
|
22
|
+
service_msg.enumerations.each do |enum|
|
23
|
+
enum_type = client.type_store.as_type("Enum(#{service_name}.#{enum.name})")
|
24
|
+
enum_type.set_values(enum.values)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create service' procedures
|
28
|
+
service_msg.procedures.each do |proc|
|
29
|
+
if Attributes.is_a_class_method_or_property_accessor(proc.attributes)
|
30
|
+
class_name = Attributes.get_class_name(proc.attributes)
|
31
|
+
class_cls = client.type_store.as_type("Class(#{service_name}.#{class_name})").ruby_type
|
32
|
+
method_name = Attributes.get_class_method_or_property_name(proc.attributes)
|
33
|
+
if Attributes.is_a_class_property_accessor(proc.attributes) # service' class property
|
34
|
+
if Attributes.is_a_class_property_getter(proc.attributes)
|
35
|
+
Gen.add_rpc_method(class_cls, method_name, service_name, proc, client, :prepend_self_to_args)
|
36
|
+
else
|
37
|
+
Gen.add_rpc_method(class_cls, method_name + '=', service_name, proc, client, :prepend_self_to_args)
|
38
|
+
end
|
39
|
+
elsif Attributes.is_a_class_method(proc.attributes) # service' class method
|
40
|
+
Gen.add_rpc_method(class_cls, method_name, service_name, proc, client, :prepend_self_to_args)
|
41
|
+
else # service' static class method
|
42
|
+
Gen.add_rpc_method(class_cls, method_name, service_name, proc, client, :static)
|
43
|
+
end
|
44
|
+
elsif Attributes.is_a_property_accessor(proc.attributes) # service' property
|
45
|
+
property_name = Attributes.get_property_name(proc.attributes)
|
46
|
+
if Attributes.is_a_property_getter(proc.attributes)
|
47
|
+
Gen.add_rpc_method(service_class, property_name, service_name, proc, client)
|
48
|
+
elsif Attributes.is_a_property_setter(proc.attributes)
|
49
|
+
Gen.add_rpc_method(service_class, property_name + '=', service_name, proc, client)
|
50
|
+
end
|
51
|
+
else # plain procedure = method available to service class and its instance
|
52
|
+
Gen.add_rpc_method(service_class, proc.name, service_name, proc, client, :static)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Add methods available to class and instance in service class & service' classes
|
57
|
+
service_class.add_methods_available_to_class_and_instance
|
58
|
+
mod = Gen.service_gen_module(service_name)
|
59
|
+
service_classes = mod.constants.map{|c| mod.const_get(c)}.select {|c| c.is_a? Class}
|
60
|
+
service_classes.each(&:add_methods_available_to_class_and_instance)
|
61
|
+
|
62
|
+
# Return service class instance
|
63
|
+
service_class.new(client)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
class ServiceBase
|
69
|
+
extend Gen::AvailableToClassAndInstanceMethodsHandler
|
70
|
+
include Doc::SuffixMethods
|
71
|
+
|
72
|
+
attr_reader :client
|
73
|
+
|
74
|
+
def initialize(client)
|
75
|
+
@client = client
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class KRPC < ServiceBase
|
80
|
+
include Gen::RPCMethodGenerator
|
81
|
+
|
82
|
+
def initialize(client)
|
83
|
+
super(client)
|
84
|
+
unless respond_to? :get_status
|
85
|
+
include_rpc_method("get_status", "KRPC", "GetStatus", return_type: "KRPC.Status")
|
86
|
+
include_rpc_method("get_services", "KRPC", "GetServices", return_type: "KRPC.Services")
|
87
|
+
# TODO: implement me:
|
88
|
+
# include_rpc_method("add_stream", "KRPC", "AddStream", ...)
|
89
|
+
# include_rpc_method("remove_stream", "KRPC", "RemoveStream", ...)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
data/lib/krpc/types.rb
ADDED
@@ -0,0 +1,237 @@
|
|
1
|
+
require 'krpc/gen'
|
2
|
+
require 'krpc/attributes'
|
3
|
+
require 'krpc/protobuf_utils'
|
4
|
+
require 'krpc/error'
|
5
|
+
require 'krpc/core_extensions'
|
6
|
+
require 'set'
|
7
|
+
|
8
|
+
module KRPC
|
9
|
+
module Types
|
10
|
+
PROTOBUF_VALUE_TYPES = ["double", "float", "int32", "int64", "uint32", "uint64", "bool", "string", "bytes"]
|
11
|
+
RUBY_VALUE_TYPES = [Float, Integer, Boolean, String]
|
12
|
+
PROTOBUF_TO_RUBY_VALUE_TYPE = {
|
13
|
+
"double" => Float,
|
14
|
+
"float" => Float,
|
15
|
+
"int32" => Integer,
|
16
|
+
"int64" => Integer,
|
17
|
+
"uint32" => Integer,
|
18
|
+
"uint64" => Integer,
|
19
|
+
"bool" => Boolean,
|
20
|
+
"string" => String,
|
21
|
+
"bytes" => String
|
22
|
+
}
|
23
|
+
PROTOBUF_TO_MESSAGE_TYPE = ProtobufUtils.create_PB_to_PB_message_class_hash("KRPC")
|
24
|
+
|
25
|
+
class TypeStore
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@cache = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def as_type(type_string)
|
32
|
+
return @cache[type_string] if @cache.include? type_string
|
33
|
+
|
34
|
+
type =
|
35
|
+
if PROTOBUF_VALUE_TYPES.include? type_string then ValueType.new(type_string)
|
36
|
+
elsif type_string.start_with? "Class(" || type_string == "Class" then ClassType.new(type_string)
|
37
|
+
elsif type_string.start_with? "Enum(" || type_string == "Enum" then EnumType.new(type_string)
|
38
|
+
elsif type_string.start_with? "List(" || type_string == "List" then ListType.new(type_string, self)
|
39
|
+
elsif type_string.start_with? "Dictionary(" || type_string == "Dictionary" then DictionaryType.new(type_string, self)
|
40
|
+
elsif type_string.start_with? "Set(" || type_string == "Set" then SetType.new(type_string, self)
|
41
|
+
elsif type_string.start_with? "Tuple(" || type_string == "Tuple" then TupleType.new(type_string, self)
|
42
|
+
else # A message type (eg. type_string = "KRPC.List" or "KRPC.Services")
|
43
|
+
raise(ValueError, "\"#{type_string}\" is not a valid type string") unless /^[A-Za-z0-9_\.]+$/ =~ type_string
|
44
|
+
if PROTOBUF_TO_MESSAGE_TYPE.has_key? type_string
|
45
|
+
MessageType.new(type_string)
|
46
|
+
else
|
47
|
+
raise(ValueError, "\"#{type_string}\" is not a valid type string")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
@cache[type_string] = type
|
52
|
+
type
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_parameter_type(pos, type, attrs)
|
56
|
+
type_attrs = Attributes.get_parameter_type_attrs(pos, attrs)
|
57
|
+
type_attrs.each do |ta|
|
58
|
+
begin
|
59
|
+
return as_type(ta)
|
60
|
+
rescue ValueError
|
61
|
+
end
|
62
|
+
end
|
63
|
+
as_type(type)
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_return_type(type, attrs)
|
67
|
+
type_attrs = Attributes.get_return_type_attrs(attrs)
|
68
|
+
type_attrs.each do |ta|
|
69
|
+
begin
|
70
|
+
return as_type(ta)
|
71
|
+
rescue ValueError
|
72
|
+
end
|
73
|
+
end
|
74
|
+
as_type(type)
|
75
|
+
end
|
76
|
+
|
77
|
+
def coerce_to(value, type)
|
78
|
+
return value if type.is_a?(EnumType) && value.class == Symbol # Enum handling
|
79
|
+
return value if value.is_a?(type.ruby_type)
|
80
|
+
# A NilClass can be coerced to a ClassType
|
81
|
+
return nil if type.is_a?(ClassType) && value == nil
|
82
|
+
# Coerce identical class types from different client connections
|
83
|
+
if type.is_a?(ClassType) && value.is_a?(Gen::ClassBase) &&
|
84
|
+
type.ruby_type.service_name == value.class.service_name &&
|
85
|
+
type.ruby_type.name == value.class.name
|
86
|
+
return type.ruby_type.new(value.remote_oid)
|
87
|
+
end
|
88
|
+
# -- Collection types --
|
89
|
+
begin
|
90
|
+
# coerce "list" to array
|
91
|
+
if type.is_a?(ListType) && value.respond_to?(:map) && value.respond_to?(:to_a)
|
92
|
+
return type.ruby_type.new(value.map{|x| coerce_to(x, type.value_type) }.to_a)
|
93
|
+
end
|
94
|
+
# coerce "tuple" to array + check elements count
|
95
|
+
if type.is_a?(TupleType) && value.respond_to?(:map) && value.respond_to?(:to_a) && value.respond_to?(:size)
|
96
|
+
raise ValueError if value.size != type.value_types.size
|
97
|
+
return type.ruby_type.new(value.map.with_index{|x,i| coerce_to(x, type.value_types[i]) }.to_a)
|
98
|
+
end
|
99
|
+
rescue ValueError
|
100
|
+
raise(ValueError, "Failed to coerce value #{value.to_s} of type #{value.class} to type #{type}")
|
101
|
+
end
|
102
|
+
# Numeric types
|
103
|
+
if type.ruby_type == Float && value.respond_to?(:to_f)
|
104
|
+
return value.to_f
|
105
|
+
elsif type.ruby_type == Integer && value.respond_to?(:to_i)
|
106
|
+
return value.to_i
|
107
|
+
end
|
108
|
+
raise(ValueError, "Failed to coerce value #{value.to_s} of type #{value.class} to type #{type}")
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
class TypeBase
|
115
|
+
attr_reader :protobuf_type, :ruby_type
|
116
|
+
def initialize(protobuf_type, ruby_type)
|
117
|
+
@protobuf_type = protobuf_type
|
118
|
+
@ruby_type = ruby_type
|
119
|
+
end
|
120
|
+
|
121
|
+
protected
|
122
|
+
|
123
|
+
def parse_type_string(type)
|
124
|
+
raise ValueError.new if type == nil
|
125
|
+
result = ""
|
126
|
+
level = 0
|
127
|
+
type.each_char do |x|
|
128
|
+
break if level == 0 && x == ','
|
129
|
+
level += 1 if x == '('
|
130
|
+
level -= 1 if x == ')'
|
131
|
+
result += x
|
132
|
+
end
|
133
|
+
raise ValueError.new if level != 0
|
134
|
+
return [result, nil] if result == type
|
135
|
+
raise ValueError.new if type[result.length] != ','
|
136
|
+
[result, type[(result.length+1)..-1]]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class ValueType < TypeBase
|
141
|
+
def initialize(type_string)
|
142
|
+
raise(ValueError, "\"#{type_string}\" is not a valid type string for a value type") unless PROTOBUF_TO_RUBY_VALUE_TYPE.has_key? type_string
|
143
|
+
super(type_string, PROTOBUF_TO_RUBY_VALUE_TYPE[type_string])
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class MessageType < TypeBase
|
148
|
+
def initialize(type_string)
|
149
|
+
if PROTOBUF_TO_MESSAGE_TYPE.has_key? type_string
|
150
|
+
super(type_string, PROTOBUF_TO_MESSAGE_TYPE[type_string])
|
151
|
+
else
|
152
|
+
raise(ValueError, "\"#{type_string}\" is not a valid type string for a message type")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class ClassType < TypeBase
|
158
|
+
attr_reader :service_name, :class_name
|
159
|
+
def initialize(type_string)
|
160
|
+
m = /Class\(([^\.]+)\.([^\.]+)\)/.match type_string
|
161
|
+
raise(ValueError, "\"#{type_string}\" is not a valid type string for a class type") unless m
|
162
|
+
@service_name, @class_name = m[1..2]
|
163
|
+
super(type_string, Gen.generate_class(service_name, class_name))
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class EnumType < TypeBase
|
168
|
+
attr_reader :service_name, :enum_name
|
169
|
+
def initialize(type_string)
|
170
|
+
m = /Enum\(([^\.]+)\.([^\.]+)\)/.match type_string
|
171
|
+
raise(ValueError, "\"#{type_string}\" is not a valid type string for a enumeration type") unless m
|
172
|
+
@service_name, @enum_name = m[1..2]
|
173
|
+
# Sets ruby_type to nil, set_values must be called to set the ruby_type
|
174
|
+
super(type_string, nil)
|
175
|
+
end
|
176
|
+
|
177
|
+
def set_values(values)
|
178
|
+
@ruby_type = Gen.generate_enum(service_name, enum_name, values)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
class ListType < TypeBase
|
183
|
+
attr_reader :value_type
|
184
|
+
def initialize(type_string, type_store)
|
185
|
+
m = /^List\((.+)\)$/.match type_string
|
186
|
+
raise(ValueError, "\"#{type_string}\" is not a valid type string for a list type") unless m
|
187
|
+
@value_type = type_store.as_type(m[1])
|
188
|
+
super(type_string, Array)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
class DictionaryType < TypeBase
|
193
|
+
attr_reader :key_type, :value_type
|
194
|
+
def initialize(type_string, type_store)
|
195
|
+
m = /^Dictionary\((.+)\)$/.match type_string
|
196
|
+
raise(ValueError, "\"#{type_string}\" is not a valid type string for a dictionary type") unless m
|
197
|
+
|
198
|
+
key_string, type = parse_type_string(m[1])
|
199
|
+
value_string, type = parse_type_string(type)
|
200
|
+
raise(ValueError, "\"#{type_string}\" is not a valid type string for a dictionary type") if type != nil
|
201
|
+
@key_type = type_store.as_type(key_string)
|
202
|
+
@value_type = type_store.as_type(value_string)
|
203
|
+
|
204
|
+
super(type_string, Hash)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
class SetType < TypeBase
|
209
|
+
attr_reader :value_type
|
210
|
+
def initialize(type_string, type_store)
|
211
|
+
m = /^Set\((.+)\)$/.match type_string
|
212
|
+
raise(ValueError, "\"#{type_string}\" is not a valid type string for a set type") unless m
|
213
|
+
@value_type = type_store.as_type(m[1])
|
214
|
+
super(type_string, Set)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
class TupleType < TypeBase
|
219
|
+
attr_reader :value_types
|
220
|
+
def initialize(type_string, type_store)
|
221
|
+
m = /^Tuple\((.+)\)$/.match type_string
|
222
|
+
raise(ValueError, "\"#{type_string}\" is not a valid type string for a tuple type") unless m
|
223
|
+
|
224
|
+
@value_types = []
|
225
|
+
type = m[1]
|
226
|
+
while type != nil
|
227
|
+
value_type, type = parse_type_string(type)
|
228
|
+
@value_types << type_store.as_type(value_type)
|
229
|
+
end
|
230
|
+
|
231
|
+
super(type_string, Array)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: krpc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tomasz Więch
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ruby_protobuf
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: colorize
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.7'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.10'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.10'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- tewu.dev@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- Gemfile
|
64
|
+
- krpc.gemspec
|
65
|
+
- lib/krpc.rb
|
66
|
+
- lib/krpc/KRPC.pb.rb
|
67
|
+
- lib/krpc/attributes.rb
|
68
|
+
- lib/krpc/client.rb
|
69
|
+
- lib/krpc/connection.rb
|
70
|
+
- lib/krpc/core_extensions.rb
|
71
|
+
- lib/krpc/decoder.rb
|
72
|
+
- lib/krpc/doc.rb
|
73
|
+
- lib/krpc/encoder.rb
|
74
|
+
- lib/krpc/error.rb
|
75
|
+
- lib/krpc/gen.rb
|
76
|
+
- lib/krpc/protobuf_utils.rb
|
77
|
+
- lib/krpc/repl_tools.rb
|
78
|
+
- lib/krpc/service.rb
|
79
|
+
- lib/krpc/types.rb
|
80
|
+
homepage: https://github.com/TeWu/krpc-rb
|
81
|
+
licenses:
|
82
|
+
- GPL-3.0
|
83
|
+
metadata: {}
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 2.4.8
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: Client library for kRPC
|
104
|
+
test_files: []
|
105
|
+
has_rdoc:
|