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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dd2789a9c287acf5c0102288bf37d79551d85bf1
|
4
|
+
data.tar.gz: c4135dc71e1b1e11ee8b75978ebeaf0d014e779d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 45bab162e5b7402b9553fc2e4fef9a1bbb8a048c40985e14b9fb53f1fe69580ae84da35813709b1cd8424100bdb67b1e2a5d2a304fda27efab38c5ef66110bb7
|
7
|
+
data.tar.gz: c2c5c2cf56506d4cb0df4940ed87945a464f64610aed0d47443dd0d3a1b74669f832f77e84256a2e33fb3fec5e6a6f8478e436d714bd4ddd75099d6a724ac81a
|
data/Gemfile
ADDED
data/krpc.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "krpc"
|
8
|
+
s.version = "0.1.0"
|
9
|
+
s.authors = ["Tomasz Więch"]
|
10
|
+
s.email = ["tewu.dev@gmail.com"]
|
11
|
+
|
12
|
+
s.summary = "Client library for kRPC"
|
13
|
+
s.homepage = "https://github.com/TeWu/krpc-rb"
|
14
|
+
s.license = "GPL-3.0"
|
15
|
+
|
16
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
s.add_runtime_dependency "ruby_protobuf", "~> 0.4"
|
20
|
+
s.add_runtime_dependency "colorize", "~> 0.7"
|
21
|
+
|
22
|
+
s.add_development_dependency "bundler", "~> 1.10"
|
23
|
+
end
|
24
|
+
|
data/lib/krpc.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'krpc/client'
|
data/lib/krpc/KRPC.pb.rb
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
|
2
|
+
### Generated by rprotoc. DO NOT EDIT!
|
3
|
+
|
4
|
+
require 'protobuf/message/message'
|
5
|
+
require 'protobuf/message/enum'
|
6
|
+
require 'protobuf/message/service'
|
7
|
+
require 'protobuf/message/extend'
|
8
|
+
|
9
|
+
module KRPC
|
10
|
+
module PB
|
11
|
+
class Request < ::Protobuf::Message
|
12
|
+
defined_in __FILE__
|
13
|
+
required :string, :service, 1
|
14
|
+
required :string, :procedure, 2
|
15
|
+
repeated :Argument, :arguments, 3
|
16
|
+
end
|
17
|
+
class Argument < ::Protobuf::Message
|
18
|
+
defined_in __FILE__
|
19
|
+
required :uint32, :position, 1
|
20
|
+
required :bytes, :value, 2
|
21
|
+
end
|
22
|
+
class Response < ::Protobuf::Message
|
23
|
+
defined_in __FILE__
|
24
|
+
required :double, :time, 1
|
25
|
+
optional :string, :error, 2
|
26
|
+
optional :bytes, :return_value, 3
|
27
|
+
end
|
28
|
+
class StreamMessage < ::Protobuf::Message
|
29
|
+
defined_in __FILE__
|
30
|
+
repeated :StreamResponse, :responses, 1
|
31
|
+
end
|
32
|
+
class StreamResponse < ::Protobuf::Message
|
33
|
+
defined_in __FILE__
|
34
|
+
required :uint32, :id, 1
|
35
|
+
required :Response, :response, 2
|
36
|
+
end
|
37
|
+
class Services < ::Protobuf::Message
|
38
|
+
defined_in __FILE__
|
39
|
+
repeated :Service, :services, 1
|
40
|
+
end
|
41
|
+
class Service < ::Protobuf::Message
|
42
|
+
defined_in __FILE__
|
43
|
+
required :string, :name, 1
|
44
|
+
repeated :Procedure, :procedures, 2
|
45
|
+
repeated :Class, :classes, 3
|
46
|
+
repeated :Enumeration, :enumerations, 4
|
47
|
+
optional :string, :documentation, 5
|
48
|
+
end
|
49
|
+
class Procedure < ::Protobuf::Message
|
50
|
+
defined_in __FILE__
|
51
|
+
required :string, :name, 1
|
52
|
+
repeated :Parameter, :parameters, 2
|
53
|
+
optional :string, :return_type, 3
|
54
|
+
repeated :string, :attributes, 4
|
55
|
+
optional :string, :documentation, 5
|
56
|
+
end
|
57
|
+
class Parameter < ::Protobuf::Message
|
58
|
+
defined_in __FILE__
|
59
|
+
required :string, :name, 1
|
60
|
+
required :string, :type, 2
|
61
|
+
optional :bytes, :default_argument, 3
|
62
|
+
end
|
63
|
+
class Class < ::Protobuf::Message
|
64
|
+
defined_in __FILE__
|
65
|
+
required :string, :name, 1
|
66
|
+
optional :string, :documentation, 2
|
67
|
+
end
|
68
|
+
class Enumeration < ::Protobuf::Message
|
69
|
+
defined_in __FILE__
|
70
|
+
required :string, :name, 1
|
71
|
+
repeated :EnumerationValue, :values, 2
|
72
|
+
optional :string, :documentation, 3
|
73
|
+
end
|
74
|
+
class EnumerationValue < ::Protobuf::Message
|
75
|
+
defined_in __FILE__
|
76
|
+
required :string, :name, 1
|
77
|
+
required :int32, :value, 2
|
78
|
+
optional :string, :documentation, 3
|
79
|
+
end
|
80
|
+
class List < ::Protobuf::Message
|
81
|
+
defined_in __FILE__
|
82
|
+
repeated :bytes, :items, 1
|
83
|
+
end
|
84
|
+
class Dictionary < ::Protobuf::Message
|
85
|
+
defined_in __FILE__
|
86
|
+
repeated :DictionaryEntry, :entries, 1
|
87
|
+
end
|
88
|
+
class DictionaryEntry < ::Protobuf::Message
|
89
|
+
defined_in __FILE__
|
90
|
+
required :bytes, :key, 1
|
91
|
+
required :bytes, :value, 2
|
92
|
+
end
|
93
|
+
class Set < ::Protobuf::Message
|
94
|
+
defined_in __FILE__
|
95
|
+
repeated :bytes, :items, 1
|
96
|
+
end
|
97
|
+
class Tuple < ::Protobuf::Message
|
98
|
+
defined_in __FILE__
|
99
|
+
repeated :bytes, :items, 1
|
100
|
+
end
|
101
|
+
class Status < ::Protobuf::Message
|
102
|
+
defined_in __FILE__
|
103
|
+
required :string, :version, 1
|
104
|
+
required :uint64, :bytes_read, 2
|
105
|
+
required :uint64, :bytes_written, 3
|
106
|
+
required :float, :bytes_read_rate, 4
|
107
|
+
required :float, :bytes_written_rate, 5
|
108
|
+
required :uint64, :rpcs_executed, 6
|
109
|
+
required :float, :rpc_rate, 7
|
110
|
+
required :bool, :one_rpc_per_update, 8
|
111
|
+
required :uint32, :max_time_per_update, 9
|
112
|
+
required :bool, :adaptive_rate_control, 10
|
113
|
+
required :bool, :blocking_recv, 11
|
114
|
+
required :uint32, :recv_timeout, 12
|
115
|
+
required :float, :time_per_rpc_update, 13
|
116
|
+
required :float, :poll_time_per_rpc_update, 14
|
117
|
+
required :float, :exec_time_per_rpc_update, 15
|
118
|
+
required :uint32, :stream_rpcs, 16
|
119
|
+
required :uint64, :stream_rpcs_executed, 17
|
120
|
+
required :float, :stream_rpc_rate, 18
|
121
|
+
required :float, :time_per_stream_update, 19
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'krpc/error'
|
2
|
+
|
3
|
+
module KRPC
|
4
|
+
module Attributes
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def is_any_start_with?(attrs, prefix)
|
8
|
+
attrs.any?{|a| a.start_with? prefix }
|
9
|
+
end
|
10
|
+
alias_method :asw?, :is_any_start_with?
|
11
|
+
|
12
|
+
def is_a_property_accessor(attrs) asw?(attrs,"Property.") end
|
13
|
+
def is_a_property_getter(attrs) asw?(attrs,"Property.Get(") end
|
14
|
+
def is_a_property_setter(attrs) asw?(attrs,"Property.Set(") end
|
15
|
+
def is_a_class_method_or_property_accessor(attrs) asw?(attrs,"Class.") end
|
16
|
+
def is_a_class_method(attrs) asw?(attrs,"Class.Method(") end
|
17
|
+
def is_a_class_static_method(attrs) asw?(attrs,"Class.StaticMethod(") end
|
18
|
+
def is_a_class_property_accessor(attrs) asw?(attrs,"Class.Property.") end
|
19
|
+
def is_a_class_property_getter(attrs) asw?(attrs,"Class.Property.Get(") end
|
20
|
+
def is_a_class_property_setter(attrs) asw?(attrs,"Class.Property.Set(") end
|
21
|
+
|
22
|
+
def get_service_name(attrs)
|
23
|
+
if is_a_class_method(attrs) || is_a_class_static_method(attrs)
|
24
|
+
attrs.each do |a|
|
25
|
+
return $1 if /^Class\.(?:Static)?Method\(([^,\.]+)\.[^,]+,[^,]+\)$/ =~ a
|
26
|
+
end
|
27
|
+
elsif is_a_class_property_accessor(attrs)
|
28
|
+
attrs.each do |a|
|
29
|
+
return $1 if /^Class\.Property.(?:Get|Set)\(([^,\.]+)\.[^,]+,[^,]+\)$/ =~ a
|
30
|
+
end
|
31
|
+
end
|
32
|
+
raise(ValueError, "Procedure attributes are not a class method or property accessor")
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_class_name(attrs)
|
36
|
+
if is_a_class_method(attrs) || is_a_class_static_method(attrs)
|
37
|
+
attrs.each do |a|
|
38
|
+
return $1 if /^Class\.(?:Static)?Method\([^,\.]+\.([^,\.]+),[^,]+\)$/ =~ a
|
39
|
+
end
|
40
|
+
elsif is_a_class_property_accessor(attrs)
|
41
|
+
attrs.each do |a|
|
42
|
+
return $1 if /^Class\.Property.(?:Get|Set)\([^,\.]+\.([^,]+),[^,]+\)$/ =~ a
|
43
|
+
end
|
44
|
+
end
|
45
|
+
raise(ValueError, "Procedure attributes are not a class method or property accessor")
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_property_name(attrs)
|
49
|
+
if is_a_property_accessor(attrs)
|
50
|
+
attrs.each do |a|
|
51
|
+
return $1 if /^Property\.(?:Get|Set)\((.+)\)$/ =~ a
|
52
|
+
end
|
53
|
+
end
|
54
|
+
raise(ValueError, "Procedure attributes are not a property accessor")
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_class_method_or_property_name(attrs)
|
58
|
+
if is_a_class_method(attrs) || is_a_class_static_method(attrs) || is_a_class_property_accessor(attrs)
|
59
|
+
attrs.each do |a|
|
60
|
+
return $1 if /^Class\.(?:(?:Static)?Method|Property\.(?:Get|Set))\([^,]+,([^,]+)\)$/ =~ a
|
61
|
+
end
|
62
|
+
end
|
63
|
+
raise(ValueError, "Procedure attributes are not a class method or class property accessor")
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_parameter_type_attrs(pos, attrs)
|
67
|
+
attrs.map do |a|
|
68
|
+
(/^ParameterType\(#{pos}\).(.+)$/ =~ a) ? $1 : nil
|
69
|
+
end.compact
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_return_type_attrs(attrs)
|
73
|
+
attrs.map do |a|
|
74
|
+
(/^ReturnType.(.+)$/ =~ a) ? $1 : nil
|
75
|
+
end.compact
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
data/lib/krpc/client.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'krpc/connection'
|
2
|
+
require 'krpc/service'
|
3
|
+
require 'krpc/types'
|
4
|
+
require 'krpc/encoder'
|
5
|
+
require 'krpc/decoder'
|
6
|
+
require 'krpc/error'
|
7
|
+
require 'krpc/core_extensions'
|
8
|
+
require 'krpc/KRPC.pb'
|
9
|
+
|
10
|
+
module KRPC
|
11
|
+
class Client
|
12
|
+
DEFAULT_NAME = ""
|
13
|
+
|
14
|
+
include Doc::SuffixMethods
|
15
|
+
|
16
|
+
attr_reader :name, :rpc_connection, :stream_connection, :type_store, :krpc
|
17
|
+
|
18
|
+
def initialize(name = DEFAULT_NAME, host = Connection::DEFAULT_SERVER_HOST, rpc_port = Connection::DEFAULT_SERVER_RPC_PORT, stream_port = Connection::DEFAULT_SERVER_STREAM_PORT)
|
19
|
+
@name = name
|
20
|
+
@rpc_connection = RPCConncetion.new(name, host, rpc_port)
|
21
|
+
@stream_connection = StreamConncetion.new(rpc_connection, host, stream_port)
|
22
|
+
@type_store = Types::TypeStore.new
|
23
|
+
@krpc = Services::KRPC.new(self)
|
24
|
+
Doc.add_docstring_info(false, self.class, "krpc", return_type: @krpc.class)
|
25
|
+
end
|
26
|
+
|
27
|
+
def connect
|
28
|
+
rpc_connection.connect
|
29
|
+
stream_connection.connect
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def connect!
|
34
|
+
connect
|
35
|
+
generate_services_api!
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def close
|
40
|
+
stream_connection.close
|
41
|
+
rpc_connection.close
|
42
|
+
end
|
43
|
+
|
44
|
+
def connected?
|
45
|
+
rpc_connection.connected?
|
46
|
+
end
|
47
|
+
|
48
|
+
def generate_services_api!
|
49
|
+
return self if services_api_generated?
|
50
|
+
raise(Exception, "Can't generate services API while not connected to server -- call Client#connect! to connect to server and generate services API in one call") if not connected?
|
51
|
+
|
52
|
+
resp = krpc.get_services
|
53
|
+
resp.services.each do |service_msg|
|
54
|
+
next if service_msg.name == "KRPC"
|
55
|
+
service = Services.create_service(service_msg, self)
|
56
|
+
method_name = service.class.class_name.underscore
|
57
|
+
self.class.instance_eval do
|
58
|
+
define_method method_name do service end
|
59
|
+
end
|
60
|
+
Doc.add_docstring_info(false, self.class, method_name, return_type: service.class)
|
61
|
+
end
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
def services_api_generated?
|
66
|
+
respond_to? :space_center
|
67
|
+
end
|
68
|
+
|
69
|
+
def rpc(service, procedure, args=[], kwargs={}, param_names=[], param_types=[], required_params_count=0, param_default=[], return_type: nil)
|
70
|
+
# Send request
|
71
|
+
req = build_request(service, procedure, args, kwargs, param_names, param_types, required_params_count, param_default)
|
72
|
+
rpc_connection.send Encoder.encode_request(req)
|
73
|
+
# Receive response
|
74
|
+
resp_length = rpc_connection.recv_varint
|
75
|
+
resp_data = rpc_connection.recv resp_length
|
76
|
+
resp = PB::Response.new
|
77
|
+
resp.parse_from_string resp_data
|
78
|
+
# Check for an error response
|
79
|
+
raise(RPCError, resp.error) if resp.has_field? "error"
|
80
|
+
# Optionally decode and return the response' return value
|
81
|
+
if return_type == nil
|
82
|
+
nil
|
83
|
+
else
|
84
|
+
Decoder.decode(resp.return_value, return_type, type_store)
|
85
|
+
end
|
86
|
+
rescue IOError => e
|
87
|
+
raise(Exception, "RPC call attempt while not connected to server -- call Client#connect first") if not connected?
|
88
|
+
raise e
|
89
|
+
end
|
90
|
+
|
91
|
+
protected #----------------------------------
|
92
|
+
|
93
|
+
def build_request(service, procedure, args=[], kwargs={}, param_names=[], param_types=[], required_params_count=0, param_default=[])
|
94
|
+
begin
|
95
|
+
raise(ArgumentError, "param_names and param_types should be equal length\n\tparam_names = #{param_names}\n\tparam_types = #{param_types}") unless param_names.size == param_types.size
|
96
|
+
raise ArgumentsNumberErrorSig.new(args.count, required_params_count..param_names.count) unless args.count <= param_names.count
|
97
|
+
kwargs_remaining = kwargs.count
|
98
|
+
|
99
|
+
param_names_symbols = param_names.map(&:to_sym)
|
100
|
+
req_args = param_names_symbols.map.with_index do |name,i|
|
101
|
+
is_kwarg = kwargs.has_key? name
|
102
|
+
raise ArgumentErrorSig.new("there are both positional and keyword arguments for parameter \"#{name}\"") if is_kwarg && i < args.count
|
103
|
+
kwargs_remaining -= 1 if is_kwarg
|
104
|
+
unless i >= required_params_count &&
|
105
|
+
(!is_kwarg && i >= args.count ||
|
106
|
+
!is_kwarg && args[i] == param_default[i] ||
|
107
|
+
is_kwarg && kwargs[name] == param_default[i])
|
108
|
+
arg = if is_kwarg then kwargs[name]
|
109
|
+
elsif i < args.count then args[i]
|
110
|
+
else raise ArgumentErrorSig.new("missing argument for parameter \"#{name}\"")
|
111
|
+
end
|
112
|
+
begin
|
113
|
+
arg = type_store.coerce_to(arg, param_types[i])
|
114
|
+
rescue ValueError
|
115
|
+
raise ArgumentErrorSig.new("argument for parameter \"#{name}\" must be a #{param_types[i].ruby_type} -- got #{args[i]} of type #{args[i].class}")
|
116
|
+
end
|
117
|
+
v = Encoder.encode(arg, param_types[i], type_store)
|
118
|
+
PB::Argument.new(position: i, value: v)
|
119
|
+
end
|
120
|
+
end.compact
|
121
|
+
raise ArgumentErrorSig.new("keyword arguments for non existing parameters: #{(kwargs.keys - param_names_symbols).join(", ")}") unless kwargs_remaining == 0
|
122
|
+
rescue ArgumentErrorSig => err
|
123
|
+
raise err.with_signature(Doc.docstring_for_procedure(service, procedure))
|
124
|
+
end
|
125
|
+
PB::Request.new(service: service, procedure: procedure, arguments: req_args)
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'krpc/encoder'
|
2
|
+
require 'krpc/decoder'
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
module KRPC
|
6
|
+
|
7
|
+
class Connection
|
8
|
+
DEFAULT_SERVER_HOST = "127.0.0.1"
|
9
|
+
DEFAULT_SERVER_RPC_PORT = 50000
|
10
|
+
DEFAULT_SERVER_STREAM_PORT = 50001
|
11
|
+
|
12
|
+
attr_reader :host, :port, :socket
|
13
|
+
|
14
|
+
def initialize(host, port)
|
15
|
+
@host, @port = host, port
|
16
|
+
end
|
17
|
+
|
18
|
+
def connect
|
19
|
+
if connected? then raise(ConnectionError, "Already connected")
|
20
|
+
else
|
21
|
+
@socket = TCPSocket.open(host, port)
|
22
|
+
begin
|
23
|
+
handshake
|
24
|
+
rescue Exception => e
|
25
|
+
close
|
26
|
+
raise e
|
27
|
+
end
|
28
|
+
end
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def close
|
33
|
+
if connected?
|
34
|
+
socket.close
|
35
|
+
cleanup
|
36
|
+
true
|
37
|
+
else false end
|
38
|
+
end
|
39
|
+
|
40
|
+
def connected?
|
41
|
+
!socket.nil? && !socket.closed?
|
42
|
+
end
|
43
|
+
|
44
|
+
def handshake; end
|
45
|
+
def cleanup; end
|
46
|
+
|
47
|
+
def send(msg) @socket.send(msg,0) end
|
48
|
+
def recv(maxlen = 1) @socket.recv(maxlen) end
|
49
|
+
|
50
|
+
def recv_varint
|
51
|
+
int_val = 0
|
52
|
+
shift = 0
|
53
|
+
loop do
|
54
|
+
byte = recv.ord
|
55
|
+
int_val |= (byte & 0b0111_1111) << shift
|
56
|
+
return int_val if (byte & 0b1000_0000) == 0
|
57
|
+
shift += 7
|
58
|
+
raise(RuntimeError, "too many bytes when decoding varint") if shift >= 64
|
59
|
+
sleep 0.1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
protected #----------------------------------
|
64
|
+
|
65
|
+
def trim_fill(str, len, fill_char = "\x00")
|
66
|
+
str = str.encode("UTF-8")[0,len]
|
67
|
+
str + fill_char*(len-str.length)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class RPCConncetion < Connection
|
72
|
+
attr_reader :name, :client_id
|
73
|
+
|
74
|
+
def initialize(name, host = DEFAULT_SERVER_HOST, port = DEFAULT_SERVER_RPC_PORT)
|
75
|
+
super host, port
|
76
|
+
@name = name
|
77
|
+
end
|
78
|
+
|
79
|
+
def handshake
|
80
|
+
send Encoder::RPC_HELLO_MESSAGE
|
81
|
+
send trim_fill(name, Encoder::NAME_LENGTH)
|
82
|
+
@client_id = recv Decoder::GUID_LENGTH
|
83
|
+
end
|
84
|
+
|
85
|
+
def cleanup
|
86
|
+
@client_id = nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class StreamConncetion < Connection
|
91
|
+
attr_reader :rpc_connection
|
92
|
+
|
93
|
+
def initialize(rpc_connection, host = DEFAULT_SERVER_HOST, port = DEFAULT_SERVER_STREAM_PORT)
|
94
|
+
super host, port
|
95
|
+
@rpc_connection = rpc_connection
|
96
|
+
end
|
97
|
+
|
98
|
+
def handshake
|
99
|
+
raise(ConnectionError, "RPC connection must optain client_id before stream connection can perform valid handshake - closing stream connection") if rpc_connection.client_id.nil?
|
100
|
+
send Encoder::STREAM_HELLO_MESSAGE
|
101
|
+
send rpc_connection.client_id
|
102
|
+
resp = recv Decoder::OK_LENGTH
|
103
|
+
raise ConnectionError unless resp == Decoder::OK_MESSAGE
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|