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.
@@ -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