krpc 0.3.2 → 0.4.0.beta1

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.
@@ -3,49 +3,42 @@ require 'set'
3
3
 
4
4
  module KRPC
5
5
  module Decoder
6
- OK_LENGTH = 2
7
- OK_MESSAGE = "\x4F\x4B"
8
- GUID_LENGTH = 16
9
-
10
6
  class << self
11
-
7
+
12
8
  # Given a type object, and serialized data, decode the ruby value/object
13
9
  def decode(data, type, client)
14
- if type.is_a?(Types::MessageType) then decode_message(data, type)
10
+ if type.is_a?(Types::MessageType) then type.ruby_type.decode(data)
15
11
  elsif type.is_a?(Types::ValueType) then decode_value(data, type)
16
12
  elsif type.is_a?(Types::EnumType)
17
- v = decode_value(data, TypeStore["int32"])
13
+ v = decode_value(data, 'sint32')
18
14
  type.ruby_type.key(v)
19
15
  elsif type.is_a?(Types::ClassType)
20
- remote_oid = decode_value(data, TypeStore["uint64"])
16
+ remote_oid = decode_value(data, 'uint64')
21
17
  if remote_oid != 0
22
18
  type.ruby_type.new(client, remote_oid)
23
19
  else nil end
24
20
  elsif type.is_a?(Types::ListType)
25
- msg = decode_message(data, TypeStore["KRPC.List"])
21
+ msg = PB::List.decode(data)
26
22
  msg.items.map{|x| decode(x, type.value_type, client)}.to_a
27
23
  elsif type.is_a?(Types::DictionaryType)
28
- msg = decode_message(data, TypeStore["KRPC.Dictionary"])
24
+ msg = PB::Dictionary.decode(data)
29
25
  msg.entries.map{|e| [decode(e.key, type.key_type, client),
30
26
  decode(e.value, type.value_type, client)]}.to_h
31
27
  elsif type.is_a?(Types::SetType)
32
- msg = decode_message(data, TypeStore["KRPC.Set"])
28
+ msg = PB::Set.decode(data)
33
29
  Set.new(msg.items.map{|x| decode(x, type.value_type, client)}.to_a)
34
30
  elsif type.is_a?(Types::TupleType)
35
- msg = decode_message(data, TypeStore["KRPC.Tuple"])
31
+ msg = PB::Tuple.decode(data)
36
32
  msg.items.zip(type.value_types).map{|x,t| decode(x, t, client)}.to_a
37
- else raise RuntimeError.new("Cannot decode type #{type} from data: #{data}")
33
+ else raise(RuntimeError, "Cannot decode type #{type} from data: #{data}")
38
34
  end
39
35
  end
40
-
36
+
41
37
  def decode_value(data, type)
42
- ProtobufUtils::Decoder.decode(data, type.protobuf_type)
38
+ type_string = type.is_a?(String) ? type : type.protobuf_type.code.to_s.downcase
39
+ ProtobufUtils::Decoder.decode(data, type_string)
43
40
  end
44
-
45
- def decode_message(data, type)
46
- type.ruby_type.decode(data.to_s)
47
- end
48
-
41
+
49
42
  end
50
43
  end
51
44
  end
@@ -7,7 +7,7 @@ module KRPC
7
7
  @docstr_infos = {}
8
8
  @procedure_docstr_infos = {}
9
9
  class << self
10
-
10
+
11
11
  def docstring_for_method(method_owner, method_name, is_print_xmldoc_summary = true)
12
12
  is_static, class_cls = method_owner.class == Class ? [true, method_owner] : [false, method_owner.class]
13
13
  service_module_name, class_name = ruby_class_to_pb_module_class_pair(class_cls)
@@ -16,10 +16,10 @@ module KRPC
16
16
  construct_docstring(*@docstr_infos[key], true, is_static, is_print_xmldoc_summary)
17
17
  else
18
18
  "No docstring for #{class_cls.name}#{calc_separator(is_static)}#{method_name.to_s} method" +
19
- (method_owner.respond_to?(method_name) ? "" : "\nThere is no such method -- maybe a typo?")
19
+ (method_owner.respond_to?(method_name) ? "" : "\nThere is no such method -- maybe a typo")
20
20
  end
21
21
  end
22
-
22
+
23
23
  def docstring_for_procedure(service_name, procedure_name, is_print_xmldoc_summary = true)
24
24
  key = [service_name, procedure_name].hash
25
25
  if @procedure_docstr_infos.has_key? key
@@ -40,30 +40,30 @@ module KRPC
40
40
  @docstr_infos[key2] = val
41
41
  end
42
42
  end
43
-
43
+
44
44
  def add_special_docstring_info(key, value)
45
45
  @docstr_infos[key] = value
46
46
  end
47
-
47
+
48
48
  private #----------------------------------
49
-
49
+
50
50
  def ruby_class_to_pb_module_class_pair(ruby_class)
51
51
  return ["", Client.class_name] if ruby_class == Client
52
52
  rest, _, pb_class_name = ruby_class.name.rpartition("::")
53
53
  _, _, pb_service_name = rest.rpartition("::")
54
54
  [pb_service_name, pb_class_name]
55
55
  end
56
-
56
+
57
57
  def calc_separator(is_static)
58
58
  is_static ? '.' : '#'
59
59
  end
60
-
60
+
61
61
  def construct_docstring(namespace, separator, name, param_names, param_types, param_default, return_type, xmldoc, is_hide_this_param, is_prepend_client_param, is_print_xmldoc_summary)
62
62
  xmldoc = Nokogiri::XML(xmldoc)
63
63
  xmldoc_summary = xmlElements2str(xmldoc.xpath("doc/summary").children, :light_blue, :light_green, :light_red)
64
64
 
65
65
  xmldoc_returns = xmlElements2str(xmldoc.xpath("doc/returns").children, :blue, :green, :light_red)
66
- xmldoc_returns = "- ".blue + xmldoc_returns unless xmldoc_returns.empty?
66
+ xmldoc_returns = "- ".blue + xmldoc_returns unless xmldoc_returns.empty?
67
67
 
68
68
  xmldoc_params = {}
69
69
  xmldoc.xpath("doc/param").each do |e|
@@ -76,10 +76,10 @@ module KRPC
76
76
  end
77
77
  end
78
78
  end
79
-
79
+
80
80
  param_infos = param_names.zip(param_types.map{|x| type2str(x)}, param_default)
81
81
  param_infos.shift if is_hide_this_param && param_names[0] == "this"
82
- param_infos.unshift ["client", "Client", :no_default_value] if is_prepend_client_param
82
+ param_infos.unshift ["client", "Client", :no_default_value] if is_prepend_client_param
83
83
  if param_infos.empty?
84
84
  params = ""
85
85
  else
@@ -92,14 +92,14 @@ module KRPC
92
92
  "#{namespace.cyan}#{separator.cyan}#{name.bold}(#{params}) :#{type2str(return_type).light_red} #{xmldoc_returns}" \
93
93
  + (is_print_xmldoc_summary ? "\n\n#{xmldoc_summary}" : "")
94
94
  end
95
-
95
+
96
96
  def type2str(type)
97
97
  return "nil" if type.nil?
98
98
  return type.class_name if type.class == Class
99
99
  rt = type.ruby_type
100
100
  if type.is_a?(Types::EnumType) then "Enum" + rt.keys.to_s
101
101
  elsif type.is_a?(Types::ListType) ||
102
- type.is_a?(Types::SetType)
102
+ type.is_a?(Types::SetType)
103
103
  "#{rt.class_name}[#{type2str(type.value_type)}]"
104
104
  elsif type.is_a?(Types::DictionaryType)
105
105
  %Q{#{rt.class_name}[#{type2str(type.key_type)} => #{type2str(type.value_type)}]}
@@ -107,7 +107,7 @@ module KRPC
107
107
  %Q{#{rt.class_name}[#{type.value_types.map{|x| type2str(x)}.join(", ")}]}
108
108
  else rt.class_name end
109
109
  end
110
-
110
+
111
111
  def xmlElements2str(elements, main_color, paramref_color, value_color, error_color = :red)
112
112
  elements.map do |elem|
113
113
  if elem.is_a?(Nokogiri::XML::Text)
@@ -138,13 +138,13 @@ module KRPC
138
138
  elem.text.gsub("null","nil").colorize(value_color)
139
139
  else elem.to_s.colorize(error_color)
140
140
  end
141
- rescue RuntimeException
141
+ rescue RuntimeException => exc
142
142
  elem.to_s.colorize(error_color)
143
143
  end
144
144
  end
145
145
  end.join.gsub("\n"," ").gsub("!n!","\n").squeeze(' ').strip.gsub("!s!"," ")
146
146
  end
147
-
147
+
148
148
  def is_method_defined(path_array)
149
149
  method_name = path_array[-1].underscore
150
150
  begin
@@ -154,18 +154,23 @@ module KRPC
154
154
  false
155
155
  end
156
156
  end
157
-
157
+
158
158
  end
159
-
160
-
159
+
160
+
161
161
  module SuffixMethods
162
162
  DOCSTRING_SUFFIX = "_doc"
163
163
  DOCSTRING_SUFFIX_REGEX = /^(.+)(?:#{DOCSTRING_SUFFIX}(=)?)$/
164
-
164
+
165
165
  def self.included(base)
166
- base.extend self, ClassMethods
166
+ base.extend self
167
+ class << base
168
+ def krpc_name
169
+ class_name
170
+ end
171
+ end
167
172
  end
168
-
173
+
169
174
  def method_missing(method, *args, &block)
170
175
  if DOCSTRING_SUFFIX_REGEX =~ method.to_s
171
176
  documented_method_name = $1 + $2.to_s
@@ -175,20 +180,14 @@ module KRPC
175
180
  end
176
181
  super
177
182
  end
178
-
183
+
179
184
  def respond_to_missing?(method, *)
180
185
  if DOCSTRING_SUFFIX_REGEX =~ method.to_s
181
186
  return true if respond_to? ($1 + $2.to_s).to_sym
182
187
  end
183
188
  super
184
189
  end
185
-
186
- module ClassMethods
187
- def krpc_name
188
- class_name
189
- end
190
- end
191
190
  end
192
-
191
+
193
192
  end
194
193
  end
@@ -3,67 +3,55 @@ require 'krpc/types'
3
3
 
4
4
  module KRPC
5
5
  module Encoder
6
- RPC_HELLO_MESSAGE = "\x48\x45\x4C\x4C\x4F\x2D\x52\x50\x43\x00\x00\x00"
7
- STREAM_HELLO_MESSAGE = "\x48\x45\x4C\x4C\x4F\x2D\x53\x54\x52\x45\x41\x4D"
8
- NAME_LENGTH = 32
9
-
10
6
  class << self
11
-
7
+
12
8
  # Given a type object, and ruby object, encode the ruby object
13
9
  def encode(obj, type)
14
10
  if type.is_a?(Types::MessageType) then type.ruby_type.encode(obj)
15
11
  elsif type.is_a?(Types::ValueType) then encode_value(obj, type)
16
12
  elsif type.is_a?(Types::EnumType)
17
13
  enum_value = type.ruby_type[obj]
18
- encode_value(enum_value, TypeStore["int32"])
14
+ encode_value(enum_value, 'sint32')
19
15
  elsif type.is_a?(Types::ClassType)
20
- remote_oid = if obj == nil then 0 else obj.remote_oid end
21
- encode_value(remote_oid, TypeStore["uint64"])
16
+ remote_oid = obj.nil? ? 0 : obj.remote_oid
17
+ encode_value(remote_oid, 'uint64')
22
18
  elsif type.is_a?(Types::ListType)
23
- ruby_type = TypeStore["KRPC.List"].ruby_type
24
- msg = ruby_type.new(
19
+ PB::List.encode(PB::List.new(
25
20
  items: obj.map{|x| encode(TypeStore.coerce_to(x, type.value_type), type.value_type)}.to_a
26
- )
27
- ruby_type.encode(msg)
21
+ ))
28
22
  elsif type.is_a?(Types::DictionaryType)
29
- ruby_type = TypeStore["KRPC.Dictionary"].ruby_type
30
- entry_type = TypeStore["KRPC.DictionaryEntry"].ruby_type
31
23
  entries = obj.map do |k,v|
32
- entry_type.new(
24
+ PB::DictionaryEntry.new(
33
25
  key: encode(TypeStore.coerce_to(k, type.key_type), type.key_type),
34
26
  value: encode(TypeStore.coerce_to(v, type.value_type), type.value_type)
35
27
  )
36
28
  end
37
- msg = ruby_type.new(entries: entries)
38
- ruby_type.encode(msg)
29
+ PB::Dictionary.encode(PB::Dictionary.new(entries: entries))
39
30
  elsif type.is_a?(Types::SetType)
40
- ruby_type = TypeStore["KRPC.Set"].ruby_type
41
- msg = ruby_type.new(
31
+ PB::Set.encode(PB::Set.new(
42
32
  items: obj.map{|x| encode( TypeStore.coerce_to(x, type.value_type), type.value_type )}.to_a
43
- )
44
- ruby_type.encode(msg)
33
+ ))
45
34
  elsif type.is_a?(Types::TupleType)
46
- ruby_type = TypeStore["KRPC.Tuple"].ruby_type
47
- msg = ruby_type.new(
35
+ PB::Tuple.encode(PB::Tuple.new(
48
36
  items: obj.zip(type.value_types).map{|x,t| encode( TypeStore.coerce_to(x, t), t )}.to_a
49
- )
50
- ruby_type.encode(msg)
37
+ ))
51
38
  else raise(RuntimeError, "Cannot encode object #{obj} of type #{type}")
52
39
  end
53
40
  end
54
-
41
+
55
42
  def encode_value(value, type)
56
- ProtobufUtils::Encoder.encode(value, type.protobuf_type)
43
+ type_string = type.is_a?(String) ? type : type.protobuf_type.code.to_s.downcase
44
+ ProtobufUtils::Encoder.encode(value, type_string)
57
45
  end
58
-
59
- def encode_request(req)
60
- data = PB::Request.encode(req)
46
+
47
+ def encode_message_with_size(msg)
48
+ data = msg.class.encode(msg)
61
49
  length = ProtobufUtils::Encoder.encode_nonnegative_varint(data.length)
62
50
  length + data
63
51
  end
64
52
 
65
53
  def hash_to_enumeration_values(hash)
66
- hash.map {|k,v| PB::EnumerationValue.new(name: k.to_s, value: v) }
54
+ hash.map {|k,v| PB::EnumerationValue.new(name: k.to_s, value: v)}
67
55
  end
68
56
 
69
57
  end
@@ -4,6 +4,7 @@ module KRPC
4
4
  class ConnectionError < Exception; end
5
5
  class RPCError < Exception; end
6
6
  class ValueError < Exception; end
7
+ class ProcedureNameParserError < Exception; end
7
8
 
8
9
 
9
10
  class ArgumentErrorSig < ArgumentError
@@ -31,7 +32,7 @@ module KRPC
31
32
  def with_arguments_count_incremented_by(args_count_increment)
32
33
  self.class.new(args_count + args_count_increment, (valid_params_count_range.min + args_count_increment)..(valid_params_count_range.max + args_count_increment), signature)
33
34
  end
34
-
35
+
35
36
  def with_signature(sig)
36
37
  self.class.new(args_count, valid_params_count_range, sig)
37
38
  end
@@ -6,10 +6,10 @@ require 'colorize'
6
6
  module KRPC
7
7
  module Gen
8
8
  class << self
9
- def service_gen_module(service_name)
9
+ def service_gen_module(service_name)
10
10
  const_get_or_create(service_name, Module.new)
11
11
  end
12
-
12
+
13
13
  def generate_class(service_name, class_name)
14
14
  mod = service_gen_module(service_name)
15
15
  mod.const_get_or_create(class_name) do
@@ -19,7 +19,7 @@ module KRPC
19
19
  end
20
20
  end
21
21
  end
22
-
22
+
23
23
  def generate_enum(service_name, enum_name, values)
24
24
  mod = service_gen_module(service_name)
25
25
  mod.const_get_or_create(enum_name) do
@@ -27,16 +27,18 @@ module KRPC
27
27
  end
28
28
  end
29
29
 
30
- def add_rpc_method(cls, method_name, service_name, proc, *switches, **options)
31
- is_static = switches.include? :static
32
- prepend_self_to_args = switches.include? :prepend_self_to_args
30
+ def add_rpc_method(cls, service_name, proc, **options)
31
+ method_name = proc.member_name.underscore
32
+ method_name += '=' if proc.setter?
33
+
33
34
  param_names, param_types, param_default, return_type = parse_procedure(proc)
34
- method_name = method_name.underscore
35
+ is_static = proc.type == :class_static_method || proc.type == :plain_procedure
36
+ prepend_self_to_args = proc.class_member? && proc.type != :class_static_method
35
37
  args = [cls, method_name, param_default, param_names, param_types, prepend_self_to_args, proc, return_type, service_name]
36
38
 
37
39
  define_rpc_method(*args)
38
40
  define_static_rpc_method(*args) if is_static
39
- add_stream_constructing_proc(*args) unless switches.include? :no_stream
41
+ add_stream_constructing_proc(*args) unless proc.setter?
40
42
  Doc.add_docstring_info(is_static, cls, method_name, options[:doc_service_name] || service_name, proc.name, param_names, param_types, param_default, return_type: return_type, xmldoc: proc.documentation)
41
43
  end
42
44
 
@@ -52,15 +54,15 @@ module KRPC
52
54
  raise err.with_signature(Doc.docstring_for_method(method_owner, method_name, false))
53
55
  end
54
56
  end
55
-
57
+
56
58
  private #----------------------------------
57
-
59
+
58
60
  def define_static_rpc_method(cls, method_name, param_default, param_names, param_types, prepend_self_to_args, proc, return_type, service_name)
59
61
  cls.instance_eval do
60
62
  define_singleton_method method_name do |*args|
61
63
  Gen.transform_exceptions(cls, method_name, prepend_self_to_args) do
62
64
  raise ArgumentErrorSig.new("missing argument for parameter \"client\"") if args.count < 1
63
- raise ArgumentErrorSig.new("argument for parameter \"client\" must be a #{::KRPC::Client.name} -- got #{args.first.inspect} of type #{args.first.class}") unless args.first.is_a?(::KRPC::Client)
65
+ raise ArgumentErrorSig.new("argument for parameter \"client\" must be a #{KRPC::Client.name} -- got #{args.first.inspect} of type #{args.first.class}") unless args.first.is_a?(KRPC::Client)
64
66
  client = args.shift
65
67
  kwargs = args.extract_kwargs!
66
68
  client.execute_rpc(service_name, proc.name, args, kwargs, param_names, param_types, param_default, return_type: return_type)
@@ -85,52 +87,49 @@ module KRPC
85
87
  cls.stream_constructors[method_name] = Proc.new do |this, *args, **kwargs|
86
88
  Gen.transform_exceptions(this, method_name, prepend_self_to_args) do
87
89
  req_args = prepend_self_to_args ? [this] + args : args
88
- request = this.client.build_request(service_name, proc.name, req_args, kwargs, param_names, param_types, param_default)
89
- this.client.streams_manager.create_stream(request, return_type, this.method(method_name), *args, **kwargs)
90
+ call = this.client.build_procedure_call(service_name, proc.name, req_args, kwargs, param_names, param_types, param_default)
91
+ this.client.streams_manager.create_stream(call, return_type, this.method(method_name), *args, **kwargs)
90
92
  end
91
93
  end
92
94
  end
93
-
95
+
94
96
  def parse_procedure(proc)
95
- param_names = proc.parameters.map{|p| p.name.underscore}
96
- param_types = proc.parameters.map.with_index do |p,i|
97
- TypeStore.get_parameter_type(i, p.type, proc.attributes)
98
- end
97
+ param_names = proc.parameters.map{|p| p.name.underscore }
98
+ param_types = proc.parameters.map{|p| TypeStore[p.type] }
99
99
  param_default = proc.parameters.zip(param_types).map do |param, type|
100
- if param.has_default_value
101
- Decoder.decode(param.default_value, type, :clientless)
102
- else :no_default_value
103
- end
100
+ param.field_empty?(:default_value) ? :no_default_value : Decoder.decode(param.default_value, type, :clientless)
104
101
  end
105
- return_type = if proc.has_return_type
106
- TypeStore.get_return_type(proc.return_type, proc.attributes)
107
- else nil end
102
+ return_type = if proc.field_empty?(:return_type) || proc.return_type.code == :NONE
103
+ nil
104
+ else
105
+ TypeStore[proc.return_type]
106
+ end
108
107
  [param_names, param_types, param_default, return_type]
109
108
  end
110
109
  end
111
-
110
+
112
111
  module RPCMethodGenerator
113
- def include_rpc_method(method_name, service_name, procedure_name, params: [], return_type: nil, attributes: [], xmldoc: "", switches: [], options: {})
114
- Gen.add_rpc_method(self.class, method_name, service_name, PB::Procedure.new(name: procedure_name, parameters: params, has_return_type: return_type != nil, return_type: return_type != nil ? return_type : "", attributes: attributes, documentation: xmldoc), *switches, **options)
112
+ def include_rpc_method(service_name, procedure_name, params: [], return_type: nil, xmldoc: "", **options)
113
+ Gen.add_rpc_method(self.class, service_name, PB::Procedure.new(name: procedure_name, parameters: params, return_type: return_type, documentation: xmldoc), **options)
115
114
  end
116
115
  end
117
-
116
+
118
117
  ##
119
118
  # Base class for service-defined class types.
120
119
  class ClassBase
121
120
  include Doc::SuffixMethods
122
121
  include Streaming::StreamConstructors
123
-
122
+
124
123
  attr_reader :client, :remote_oid
125
-
124
+
126
125
  def self.krpc_name
127
126
  name[11..-1]
128
127
  end
129
-
128
+
130
129
  def initialize(client, remote_oid)
131
130
  @client, @remote_oid = client, remote_oid
132
131
  end
133
-
132
+
134
133
  alias_method :eql?, :==
135
134
  def ==(other)
136
135
  other.class == self.class and other.remote_oid == remote_oid
@@ -138,15 +137,15 @@ module KRPC
138
137
  def hash
139
138
  remote_oid.hash
140
139
  end
141
-
140
+
142
141
  def to_s
143
142
  "#<#{self.class} @remote_oid=#{remote_oid}>"
144
143
  end
145
-
144
+
146
145
  def inspect
147
146
  "#<#{self.class} ".green + "@remote_oid" + "=".green + remote_oid.to_s.bold.blue + ">".green
148
147
  end
149
148
  end
150
-
151
- end
149
+
150
+ end
152
151
  end