krpc 0.3.2 → 0.4.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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