krpc 0.1.0
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 +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:
|