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.
@@ -6,19 +6,20 @@ module KRPC
6
6
 
7
7
  class StreamsManager
8
8
  attr_reader :client
9
-
9
+
10
10
  def initialize(client)
11
11
  @client = client
12
12
  @streams = {}
13
13
  @streams_mutex = Mutex.new
14
14
  @streaming_thread = Thread.new {}
15
15
  end
16
-
17
- # Send a streaming request, create related Stream object and return it. If identical Stream
16
+
17
+ # Send the streaming request, create related Stream object and return it. If identical Stream
18
18
  # already exists, doesn't create new Stream and return the existing one.
19
- def create_stream(request, return_type, method, *args, **kwargs)
19
+ def create_stream(call, return_type, method, *args, **kwargs)
20
20
  raise RuntimeError("Cannot stream a property setter") if method.name.to_s.end_with? '='
21
- id = client.core.add_stream(request)
21
+ stream_msg = client.core.add_stream(call)
22
+ id = stream_msg.id
22
23
  @streams_mutex.synchronize do
23
24
  if @streams.include? id
24
25
  @streams[id]
@@ -28,9 +29,9 @@ module KRPC
28
29
  end
29
30
  end
30
31
  end
31
-
32
- # Remove a streaming request and deactivate the Stream object. Returns `true` if
33
- # streaming request is removed or `false` if passed Stream object is already inactive.
32
+
33
+ # Remove the streaming request and deactivate the Stream object. Returns `true` if the
34
+ # streaming request has been removed or `false` if passed Stream object is already inactive.
34
35
  def remove_stream(stream)
35
36
  return false unless stream.active?
36
37
  @streams_mutex.synchronize do
@@ -47,42 +48,41 @@ module KRPC
47
48
  def remove_all_streams
48
49
  @streams.each {|_,stream| remove_stream(stream)}
49
50
  end
50
-
51
+
51
52
  # Start streaming thread. It receives stream data, and updates Stream object's `value` attribute.
52
53
  def start_streaming_thread
53
54
  stop_streaming_thread
54
55
  @streaming_thread = Thread.new do
55
56
  connection = client.stream_connection
56
- stream_message_type = TypeStore["KRPC.StreamMessage"]
57
57
  loop do
58
58
  size = connection.recv_varint
59
59
  data = connection.recv(size)
60
- stream_msg = Decoder.decode(data, stream_message_type, client)
60
+ stream_msg = PB::StreamUpdate.decode(data)
61
61
  @streams_mutex.synchronize do
62
- stream_msg.responses.each do |stream_resp|
63
- next unless @streams.include? stream_resp.id
64
- stream = @streams[stream_resp.id]
65
- if stream_resp.response.has_error
66
- stream.value = RPCError.new(stream_resp.response.error)
62
+ stream_msg.results.each do |result|
63
+ next unless @streams.include? result.id
64
+ stream = @streams[result.id]
65
+ if result.result.field_empty? :error
66
+ stream.value = Decoder.decode(result.result.value, stream.return_type, client)
67
67
  else
68
- stream.value = Decoder.decode(stream_resp.response.return_value, stream.return_type, client)
68
+ stream.value = RPCError.new(result.result.error)
69
69
  end
70
70
  end
71
71
  end
72
72
  end
73
73
  end
74
74
  end
75
-
75
+
76
76
  # Stop streaming thread.
77
77
  def stop_streaming_thread
78
78
  @streaming_thread.terminate
79
79
  end
80
80
  end
81
-
81
+
82
82
  class Stream
83
83
  attr_reader :id, :method, :args, :kwargs, :return_type, :manager
84
84
  attr_writer :value
85
-
85
+
86
86
  def initialize(manager, id, return_type, value, method, *args, **kwargs)
87
87
  @manager = manager
88
88
  @id = id
@@ -90,7 +90,7 @@ module KRPC
90
90
  @method, @args, @kwargs = method, args, kwargs
91
91
  @active = true
92
92
  end
93
-
93
+
94
94
  # Get the current stream value. Has alias method `value`.
95
95
  def get
96
96
  raise @value if @value.is_a?(Exception)
@@ -103,18 +103,18 @@ module KRPC
103
103
  manager.remove_stream self
104
104
  end
105
105
  alias_method :close, :remove
106
-
106
+
107
107
  # Check if stream is active (i.e. not removed).
108
108
  def active?; @active end
109
109
 
110
110
  # Mark stream as inactive.
111
111
  # WARNING: This method does not remove the stream. To remove the stream call Stream#remove instead.
112
112
  def mark_as_inactive; @active = false end
113
-
113
+
114
114
  def to_s
115
115
  inspect.gsub(/\n|\t/," ").squeeze(" ").uncolorize
116
116
  end
117
-
117
+
118
118
  def inspect
119
119
  def coderay(x)
120
120
  require 'coderay'
@@ -134,11 +134,11 @@ module KRPC
134
134
  ">".green
135
135
  end
136
136
  end
137
-
137
+
138
138
  module StreamConstructors
139
139
  STREAM_METHOD_SUFFIX = "_stream"
140
140
  STREAM_METHOD_REGEX = /^(.+)(?:#{STREAM_METHOD_SUFFIX})$/
141
-
141
+
142
142
  module ClassMethods
143
143
  def stream_constructors
144
144
  @stream_constructors ||= {}
@@ -149,7 +149,7 @@ module KRPC
149
149
  base.extend ClassMethods
150
150
  base.extend self
151
151
  end
152
-
152
+
153
153
  def method_missing(method, *args, **kwargs, &block)
154
154
  if STREAM_METHOD_REGEX =~ method.to_s
155
155
  if respond_to? $1.to_sym
@@ -159,7 +159,7 @@ module KRPC
159
159
  end
160
160
  super
161
161
  end
162
-
162
+
163
163
  def respond_to_missing?(method, *)
164
164
  if STREAM_METHOD_REGEX =~ method.to_s
165
165
  if respond_to? $1.to_sym
@@ -169,8 +169,8 @@ module KRPC
169
169
  end
170
170
  super
171
171
  end
172
-
172
+
173
173
  end
174
-
174
+
175
175
  end
176
176
  end
@@ -1,5 +1,4 @@
1
1
  require 'krpc/gen'
2
- require 'krpc/attributes'
3
2
  require 'krpc/protobuf_utils'
4
3
  require 'krpc/error'
5
4
  require 'krpc/core_extensions'
@@ -7,78 +6,40 @@ require 'set'
7
6
 
8
7
  module KRPC
9
8
  module Types
10
- PROTOBUF_VALUE_TYPES = ["double", "float", "int32", "int64", "uint32", "uint64", "bool", "string", "bytes"]
11
- RUBY_VALUE_TYPES = [Float, Integer, Boolean, String, Array]
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" => Array
9
+ PROTOBUF_TO_RUBY_VALUE_TYPES = {
10
+ DOUBLE: Float,
11
+ FLOAT: Float,
12
+ SINT32: Integer,
13
+ SINT64: Integer,
14
+ UINT32: Integer,
15
+ UINT64: Integer,
16
+ BOOL: Boolean,
17
+ STRING: String,
18
+ BYTES: Array
22
19
  }
23
- PROTOBUF_TO_MESSAGE_TYPE = ProtobufUtils.create_PB_to_PB_message_class_hash("KRPC")
24
-
20
+ PROTOBUF_TO_RUBY_MESSAGE_TYPES = {
21
+ PROCEDURE_CALL: PB::ProcedureCall,
22
+ STREAM: PB::Stream,
23
+ STATUS: PB::Status,
24
+ SERVICES: PB::Services
25
+ }
26
+
27
+
25
28
  class TypeStore
26
29
  @cache = {}
27
30
  class << self
28
-
29
- def [](type_string)
30
- return @cache[type_string] if @cache.include? type_string
31
-
32
- type =
33
- if PROTOBUF_VALUE_TYPES.include? type_string then ValueType.new(type_string)
34
- elsif type_string.start_with? "Class(" || type_string == "Class" then ClassType.new(type_string)
35
- elsif type_string.start_with? "Enum(" || type_string == "Enum" then EnumType.new(type_string)
36
- elsif type_string.start_with? "List(" || type_string == "List" then ListType.new(type_string)
37
- elsif type_string.start_with? "Dictionary(" || type_string == "Dictionary" then DictionaryType.new(type_string)
38
- elsif type_string.start_with? "Set(" || type_string == "Set" then SetType.new(type_string)
39
- elsif type_string.start_with? "Tuple(" || type_string == "Tuple" then TupleType.new(type_string)
40
- else # A message type (eg. type_string = "KRPC.List" or "KRPC.Services")
41
- raise(ValueError, "\"#{type_string}\" is not a valid type string") unless /^[A-Za-z0-9_\.]+$/ =~ type_string
42
- if PROTOBUF_TO_MESSAGE_TYPE.has_key? type_string
43
- MessageType.new(type_string)
44
- else
45
- raise(ValueError, "\"#{type_string}\" is not a valid type string")
46
- end
47
- end
48
-
49
- @cache[type_string] = type
50
- type
51
- end
52
-
53
- def get_parameter_type(pos, type, attrs)
54
- type_attrs = Attributes.get_parameter_type_attrs(pos, attrs)
55
- type_attrs.each do |ta|
56
- begin
57
- return self[ta]
58
- rescue ValueError
59
- end
60
- end
61
- self[type]
62
- end
63
-
64
- def get_return_type(type, attrs)
65
- type_attrs = Attributes.get_return_type_attrs(attrs)
66
- type_attrs.each do |ta|
67
- begin
68
- return self[ta]
69
- rescue ValueError
70
- end
71
- end
72
- self[type]
31
+
32
+ def [](protobuf_type)
33
+ @cache[protobuf_type.to_proto.hash] ||= PROTOBUF_TYPE_CODE_TO_TYPE_TYPE[protobuf_type.code].new(protobuf_type)
73
34
  end
74
-
35
+
75
36
  def coerce_to(value, type)
76
37
  return value if type.is_a?(EnumType) && value.class == Symbol # Enum handling
77
38
  return value if value.is_a?(type.ruby_type)
78
39
  # A NilClass can be coerced to a ClassType
79
40
  return nil if type.is_a?(ClassType) && value.nil?
80
41
  # Handle service' class instance
81
- if type.is_a?(ClassType) && value.is_a?(Gen::ClassBase) &&
42
+ if type.is_a?(ClassType) && value.is_a?(Gen::ClassBase) &&
82
43
  type.ruby_type == value.class
83
44
  return value
84
45
  end
@@ -103,138 +64,96 @@ module KRPC
103
64
  return value.to_i
104
65
  end
105
66
  # Convert value type to string
106
- if type.is_a?(ValueType) && type.ruby_type == String
67
+ if type.ruby_type == String
107
68
  return value.to_s
108
69
  end
109
70
  raise(ValueError, "Failed to coerce value #{value.to_s} of type #{value.class} to type #{type}")
110
71
  end
111
-
72
+
112
73
  end
113
74
  end
114
-
115
-
75
+
76
+
116
77
  class TypeBase
117
78
  attr_reader :protobuf_type, :ruby_type
118
79
  def initialize(protobuf_type, ruby_type)
119
80
  @protobuf_type = protobuf_type
120
81
  @ruby_type = ruby_type
121
82
  end
122
-
123
- protected
124
-
125
- def parse_type_string(type)
126
- raise ValueError.new if type.nil?
127
- result = ""
128
- level = 0
129
- type.each_char do |x|
130
- break if level == 0 && x == ','
131
- level += 1 if x == '('
132
- level -= 1 if x == ')'
133
- result += x
134
- end
135
- raise ValueError.new if level != 0
136
- return [result, nil] if result == type
137
- raise ValueError.new if type[result.length] != ','
138
- [result, type[(result.length+1)..-1]]
139
- end
140
83
  end
141
-
84
+
142
85
  class ValueType < TypeBase
143
- def initialize(type_string)
144
- raise(ValueError, "\"#{type_string}\" is not a valid type string for a value type") unless PROTOBUF_TO_RUBY_VALUE_TYPE.has_key? type_string
145
- super(type_string, PROTOBUF_TO_RUBY_VALUE_TYPE[type_string])
86
+ def initialize(pb_type)
87
+ super(pb_type, PROTOBUF_TO_RUBY_VALUE_TYPES[pb_type.code] || raise(ValueError, "#{pb_type.code} is not a valid type code for a value type"))
146
88
  end
147
89
  end
148
-
149
- class MessageType < TypeBase
150
- def initialize(type_string)
151
- if PROTOBUF_TO_MESSAGE_TYPE.has_key? type_string
152
- super(type_string, PROTOBUF_TO_MESSAGE_TYPE[type_string])
153
- else
154
- raise(ValueError, "\"#{type_string}\" is not a valid type string for a message type")
155
- end
156
- end
157
- end
158
-
90
+
159
91
  class ClassType < TypeBase
160
92
  attr_reader :service_name, :class_name
161
- def initialize(type_string)
162
- m = /Class\(([^\.]+)\.([^\.]+)\)/.match type_string
163
- raise(ValueError, "\"#{type_string}\" is not a valid type string for a class type") unless m
164
- @service_name, @class_name = m[1..2]
165
- super(type_string, Gen.generate_class(service_name, class_name))
93
+ def initialize(pb_type)
94
+ @service_name, @class_name = pb_type.service, pb_type.name
95
+ super(pb_type, Gen.generate_class(service_name, class_name))
166
96
  end
167
97
  end
168
-
98
+
169
99
  class EnumType < TypeBase
170
100
  attr_reader :service_name, :enum_name
171
- def initialize(type_string)
172
- m = /Enum\(([^\.]+)\.([^\.]+)\)/.match type_string
173
- raise(ValueError, "\"#{type_string}\" is not a valid type string for a enumeration type") unless m
174
- @service_name, @enum_name = m[1..2]
101
+ def initialize(pb_type)
102
+ @service_name, @enum_name = pb_type.service, pb_type.name
175
103
  # Sets ruby_type to nil, set_values must be called to set the ruby_type
176
- super(type_string, nil)
104
+ super(pb_type, nil)
177
105
  end
178
-
106
+
179
107
  def set_values(values)
180
108
  @ruby_type = Gen.generate_enum(service_name, enum_name, values)
181
109
  end
182
110
  end
183
-
111
+
184
112
  class ListType < TypeBase
185
113
  attr_reader :value_type
186
- def initialize(type_string)
187
- m = /^List\((.+)\)$/.match type_string
188
- raise(ValueError, "\"#{type_string}\" is not a valid type string for a list type") unless m
189
- @value_type = TypeStore[m[1]]
190
- super(type_string, Array)
114
+ def initialize(pb_type)
115
+ @value_type = TypeStore[pb_type.types.first]
116
+ super(pb_type, Array)
191
117
  end
192
118
  end
193
-
194
- class DictionaryType < TypeBase
195
- attr_reader :key_type, :value_type
196
- def initialize(type_string)
197
- m = /^Dictionary\((.+)\)$/.match type_string
198
- raise(ValueError, "\"#{type_string}\" is not a valid type string for a dictionary type") unless m
199
-
200
- key_string, type = parse_type_string(m[1])
201
- value_string, type = parse_type_string(type)
202
- raise(ValueError, "\"#{type_string}\" is not a valid type string for a dictionary type") unless type.nil?
203
- @key_type = TypeStore[key_string]
204
- @value_type = TypeStore[value_string]
205
-
206
- super(type_string, Hash)
207
- end
208
- end
209
-
119
+
210
120
  class SetType < TypeBase
211
121
  attr_reader :value_type
212
- def initialize(type_string)
213
- m = /^Set\((.+)\)$/.match type_string
214
- raise(ValueError, "\"#{type_string}\" is not a valid type string for a set type") unless m
215
- @value_type = TypeStore[m[1]]
216
- super(type_string, Set)
122
+ def initialize(pb_type)
123
+ @value_type = TypeStore[pb_type.types.first]
124
+ super(pb_type, Set)
217
125
  end
218
126
  end
219
-
127
+
220
128
  class TupleType < TypeBase
221
129
  attr_reader :value_types
222
- def initialize(type_string)
223
- m = /^Tuple\((.+)\)$/.match type_string
224
- raise(ValueError, "\"#{type_string}\" is not a valid type string for a tuple type") unless m
225
-
226
- @value_types = []
227
- type = m[1]
228
- until type.nil?
229
- value_type, type = parse_type_string(type)
230
- @value_types << TypeStore[value_type]
231
- end
232
-
233
- super(type_string, Array)
130
+ def initialize(pb_type)
131
+ @value_types = pb_type.types.map {|t| TypeStore[t] }
132
+ super(pb_type, Array)
234
133
  end
235
134
  end
236
-
135
+
136
+ class DictionaryType < TypeBase
137
+ attr_reader :key_type, :value_type
138
+ def initialize(pb_type)
139
+ @key_type, @value_type = pb_type.types.map {|t| TypeStore[t] }
140
+ super(pb_type, Hash)
141
+ end
142
+ end
143
+
144
+ class MessageType < TypeBase
145
+ def initialize(pb_type)
146
+ super(pb_type, PROTOBUF_TO_RUBY_MESSAGE_TYPES[pb_type.code] || raise(ValueError, "\"#{pb_type.code}\" is not a valid type code for a message type"))
147
+ end
148
+ end
149
+
150
+ PROTOBUF_TYPE_CODE_TO_TYPE_TYPE =
151
+ PROTOBUF_TO_RUBY_VALUE_TYPES.keys.inject({}) {|a,e| a[e] = ValueType; a }.merge(
152
+ PROTOBUF_TO_RUBY_MESSAGE_TYPES.keys.inject({}) {|a,e| a[e] = MessageType; a }).merge(
153
+ CLASS: ClassType, ENUMERATION: EnumType,
154
+ LIST: ListType, SET: SetType, TUPLE: TupleType, DICTIONARY: DictionaryType
155
+ )
237
156
  end
238
-
157
+
239
158
  TypeStore = Types::TypeStore
240
159
  end