bones-rpc 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-gemset +1 -1
- data/.ruby-version +1 -1
- data/bones-rpc.gemspec +1 -4
- data/lib/bones/rpc.rb +1 -1
- data/lib/bones/rpc/adapter.rb +44 -4
- data/lib/bones/rpc/adapter/json.rb +66 -0
- data/lib/bones/rpc/address.rb +6 -4
- data/lib/bones/rpc/backend.rb +31 -0
- data/lib/bones/rpc/backend/base.rb +30 -0
- data/lib/bones/rpc/backend/synchronous.rb +29 -0
- data/lib/bones/rpc/cluster.rb +18 -18
- data/lib/bones/rpc/connection.rb +19 -15
- data/lib/bones/rpc/connection/socket.rb +0 -2
- data/lib/bones/rpc/connection/socket/connectable.rb +15 -11
- data/lib/bones/rpc/context.rb +2 -2
- data/lib/bones/rpc/dns_resolver.rb +85 -0
- data/lib/bones/rpc/errors.rb +3 -0
- data/lib/bones/rpc/failover.rb +3 -3
- data/lib/bones/rpc/failover/disconnect.rb +2 -2
- data/lib/bones/rpc/failover/ignore.rb +2 -2
- data/lib/bones/rpc/failover/retry.rb +2 -2
- data/lib/bones/rpc/instrumentable.rb +3 -3
- data/lib/bones/rpc/instrumentable/log.rb +2 -2
- data/lib/bones/rpc/instrumentable/noop.rb +2 -2
- data/lib/bones/rpc/loggable.rb +8 -8
- data/lib/bones/rpc/node.rb +47 -37
- data/lib/bones/rpc/node/registry.rb +4 -0
- data/lib/bones/rpc/parser.rb +16 -5
- data/lib/bones/rpc/parser/buffer.rb +6 -2
- data/lib/bones/rpc/protocol/adapter_helper.rb +2 -2
- data/lib/bones/rpc/protocol/binary_helper.rb +2 -2
- data/lib/bones/rpc/read_preference.rb +3 -3
- data/lib/bones/rpc/read_preference/nearest.rb +3 -3
- data/lib/bones/rpc/read_preference/selectable.rb +4 -4
- data/lib/bones/rpc/readable.rb +4 -4
- data/lib/bones/rpc/session.rb +25 -16
- data/lib/bones/rpc/synchronous.rb +2 -0
- data/lib/bones/rpc/synchronous/connection.rb +36 -0
- data/lib/bones/rpc/synchronous/connection/reader.rb +59 -0
- data/lib/bones/rpc/synchronous/connection/socket.rb +4 -0
- data/lib/bones/rpc/synchronous/connection/socket/ssl.rb +57 -0
- data/lib/bones/rpc/synchronous/connection/socket/tcp.rb +30 -0
- data/lib/bones/rpc/synchronous/connection/writer.rb +86 -0
- data/lib/bones/rpc/synchronous/future.rb +91 -0
- data/lib/bones/rpc/synchronous/node.rb +45 -0
- data/lib/bones/rpc/uri.rb +20 -20
- data/lib/bones/rpc/version.rb +1 -1
- metadata +16 -52
- data/lib/bones/rpc/adapter/erlang.rb +0 -28
- data/lib/bones/rpc/adapter/msgpack.rb +0 -52
- data/lib/bones/rpc/connection/reader.rb +0 -49
- data/lib/bones/rpc/connection/socket/ssl.rb +0 -35
- data/lib/bones/rpc/connection/socket/tcp.rb +0 -28
- data/lib/bones/rpc/connection/writer.rb +0 -51
- data/lib/bones/rpc/future.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64b5fc8956bbbb066be3f8d398bc89cb2027f2be
|
4
|
+
data.tar.gz: 20261b3e59c98eb0693c7bc08f694c85af48f5c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84314e5a51a7723fd7455eeda8ced426375b5022b8ee2093ebdd50aecafc47345e3bea46d8b11f87c77f393d242e11942a249f0caac005a3112af7efa3fd3790
|
7
|
+
data.tar.gz: 32a75f9c693b9de01ffbb4f77d6ba25dcc799af9ded5f4686a5414c6b323c421813cf3597b3be7b27e4fc8ebe3d6bc9054f86c3057f35104b31c4648d4d720db
|
data/.ruby-gemset
CHANGED
@@ -1 +1 @@
|
|
1
|
-
bones
|
1
|
+
bones-rpc
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.0.0
|
1
|
+
ruby-2.0.0
|
data/bones-rpc.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = "bones-rpc"
|
8
8
|
spec.version = Bones::RPC::VERSION
|
9
9
|
spec.authors = ["Andrew Bennett"]
|
10
|
-
spec.email = ["andrew@
|
10
|
+
spec.email = ["andrew@pagodabox.com"]
|
11
11
|
spec.description = %q{Bones::RPC client for ruby}
|
12
12
|
spec.summary = %q{Bones::RPC client for ruby}
|
13
13
|
spec.homepage = ""
|
@@ -18,9 +18,6 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "celluloid-io", ">= 0.14.0"
|
22
|
-
spec.add_dependency "erlang-etf"
|
23
|
-
spec.add_dependency "msgpack"
|
24
21
|
spec.add_dependency "optionable"
|
25
22
|
|
26
23
|
spec.add_development_dependency "bundler", "~> 1.3"
|
data/lib/bones/rpc.rb
CHANGED
@@ -3,12 +3,12 @@ require 'logger'
|
|
3
3
|
require 'stringio'
|
4
4
|
require 'monitor'
|
5
5
|
require 'timeout'
|
6
|
-
require 'celluloid/io'
|
7
6
|
require 'optionable'
|
8
7
|
require 'bones/rpc/errors'
|
9
8
|
require 'bones/rpc/loggable'
|
10
9
|
require 'bones/rpc/uri'
|
11
10
|
require 'bones/rpc/adapter'
|
11
|
+
require 'bones/rpc/backend'
|
12
12
|
require 'bones/rpc/parser'
|
13
13
|
require 'bones/rpc/protocol'
|
14
14
|
require 'bones/rpc/session'
|
data/lib/bones/rpc/adapter.rb
CHANGED
@@ -27,6 +27,50 @@ module Bones
|
|
27
27
|
return adapter
|
28
28
|
end
|
29
29
|
|
30
|
+
def read_ext(buffer)
|
31
|
+
ext_code, = buffer.read(1).unpack('C')
|
32
|
+
ext_length, = case ext_code
|
33
|
+
when 0xC7
|
34
|
+
buffer.read(1).unpack('C')
|
35
|
+
when 0xC8
|
36
|
+
buffer.read(2).unpack('n')
|
37
|
+
when 0xC9
|
38
|
+
buffer.read(4).unpack('N')
|
39
|
+
end
|
40
|
+
ext_type, = buffer.read(1).unpack('c')
|
41
|
+
ext_data = buffer.read(ext_length)
|
42
|
+
return ext_data
|
43
|
+
end
|
44
|
+
|
45
|
+
def write_ext(head, data, buffer = "")
|
46
|
+
ext_length = data.bytesize + 1
|
47
|
+
ext_code = if ext_length <= 0xFF
|
48
|
+
0xC7
|
49
|
+
elsif ext_length <= 0xFFFF
|
50
|
+
0xC8
|
51
|
+
elsif ext_length <= 0xFFFFFFFF
|
52
|
+
0xC9
|
53
|
+
else
|
54
|
+
raise ArgumentError, "datasize too large: #{ext_length} (max #{0xFFFFFFFF} bytes)"
|
55
|
+
end
|
56
|
+
buffer << [ext_code].pack('C')
|
57
|
+
ext_length_packer = case ext_code
|
58
|
+
when 0xC7
|
59
|
+
'C'
|
60
|
+
when 0xC8
|
61
|
+
'n'
|
62
|
+
when 0xC9
|
63
|
+
'N'
|
64
|
+
else
|
65
|
+
raise ArgumentError, "bad ext_code: #{ext_code} (should be one of #{0xC7}, #{0xC8}, #{0xC9})"
|
66
|
+
end
|
67
|
+
buffer << [ext_length].pack(ext_length_packer)
|
68
|
+
ext_type = 0x0D
|
69
|
+
buffer << [ext_type].pack('c')
|
70
|
+
buffer << [head].pack('C')
|
71
|
+
buffer << data.force_encoding('BINARY')
|
72
|
+
end
|
73
|
+
|
30
74
|
private
|
31
75
|
|
32
76
|
def adapters
|
@@ -41,9 +85,5 @@ module Bones
|
|
41
85
|
end
|
42
86
|
|
43
87
|
require 'bones/rpc/adapter/parser'
|
44
|
-
|
45
88
|
require 'bones/rpc/adapter/base'
|
46
|
-
|
47
|
-
require 'bones/rpc/adapter/erlang'
|
48
89
|
require 'bones/rpc/adapter/json'
|
49
|
-
require 'bones/rpc/adapter/msgpack'
|
@@ -16,6 +16,72 @@ module Bones
|
|
16
16
|
::JSON.load(buffer)
|
17
17
|
end
|
18
18
|
|
19
|
+
def unpacker(data)
|
20
|
+
Unpacker.new(data)
|
21
|
+
end
|
22
|
+
|
23
|
+
def parser(data)
|
24
|
+
Adapter::Parser.new(self, data)
|
25
|
+
end
|
26
|
+
|
27
|
+
def unpacker_pos(parser)
|
28
|
+
parser.unpacker.buffer.pos
|
29
|
+
end
|
30
|
+
|
31
|
+
def unpacker_seek(parser, n)
|
32
|
+
parser.unpacker.buffer.seek(n)
|
33
|
+
return n
|
34
|
+
end
|
35
|
+
|
36
|
+
# I apologize for how nasty this unpacker is; Oj or Yajl would be better fits
|
37
|
+
class Unpacker
|
38
|
+
attr_reader :buffer
|
39
|
+
|
40
|
+
ARRAY_START = '['.freeze
|
41
|
+
|
42
|
+
def initialize(data)
|
43
|
+
@buffer = Bones::RPC::Parser::Buffer.new(data)
|
44
|
+
end
|
45
|
+
|
46
|
+
def read
|
47
|
+
if skip_to_array_start
|
48
|
+
unpack_stream("", buffer.pos)
|
49
|
+
else
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def unpack_stream(temp, pos)
|
57
|
+
if char = buffer.getc
|
58
|
+
temp << char
|
59
|
+
term = begin
|
60
|
+
::JSON.load(temp)
|
61
|
+
rescue ::JSON::ParserError
|
62
|
+
unpack_stream(temp, pos)
|
63
|
+
end
|
64
|
+
return term
|
65
|
+
else
|
66
|
+
buffer.seek(pos)
|
67
|
+
return nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def skip_to_array_start
|
72
|
+
i = buffer.pos
|
73
|
+
case buffer.getc
|
74
|
+
when ARRAY_START
|
75
|
+
buffer.seek(i)
|
76
|
+
return true
|
77
|
+
when nil
|
78
|
+
return false
|
79
|
+
else
|
80
|
+
skip_to_array_start
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
19
85
|
Adapter.register self
|
20
86
|
end
|
21
87
|
end
|
data/lib/bones/rpc/address.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
require 'bones/rpc/dns_resolver'
|
3
|
+
|
2
4
|
module Bones
|
3
5
|
module RPC
|
4
6
|
|
5
7
|
# Encapsulates behaviour around addresses and resolving dns.
|
6
8
|
#
|
7
|
-
# @since
|
9
|
+
# @since 0.0.1
|
8
10
|
class Address
|
9
11
|
|
10
12
|
# @!attribute host
|
@@ -26,7 +28,7 @@ module Bones
|
|
26
28
|
#
|
27
29
|
# @param [ String ] address The host:port pair as a string.
|
28
30
|
#
|
29
|
-
# @since
|
31
|
+
# @since 0.0.1
|
30
32
|
def initialize(address, port = nil)
|
31
33
|
if address.is_a?(Bones::RPC::Address)
|
32
34
|
@host = address.host
|
@@ -97,7 +99,7 @@ module Bones
|
|
97
99
|
#
|
98
100
|
# @return [ String ] The resolved address.
|
99
101
|
#
|
100
|
-
# @since
|
102
|
+
# @since 0.0.1
|
101
103
|
def resolve(node)
|
102
104
|
begin
|
103
105
|
resolve! unless valid?
|
@@ -151,7 +153,7 @@ module Bones
|
|
151
153
|
|
152
154
|
# Guess it's not an IP address, so let's try DNS
|
153
155
|
unless @ip
|
154
|
-
addrs = Array(::
|
156
|
+
addrs = Array(::Bones::RPC::DNSResolver.new.resolve(@host))
|
155
157
|
raise Resolv::ResolvError, "DNS result has no information for #{@host}" if addrs.empty?
|
156
158
|
|
157
159
|
# Pseudorandom round-robin DNS support :/
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Bones
|
3
|
+
module RPC
|
4
|
+
module Backend
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def get(backend_name)
|
8
|
+
backends[backend_name] || raise(Errors::InvalidBackend, "Unknown backend #{backend_name.inspect}")
|
9
|
+
end
|
10
|
+
|
11
|
+
def register(backend)
|
12
|
+
backend.send(:attr_reader, :backend_name)
|
13
|
+
backend.send(:include, Backend::Base)
|
14
|
+
backend.send(:extend, backend)
|
15
|
+
backends[backend] ||= backend
|
16
|
+
backends[backend.backend_name] ||= backend
|
17
|
+
backends[backend.backend_name.to_s] ||= backend
|
18
|
+
return backend
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def backends
|
24
|
+
@backends ||= {}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
require 'bones/rpc/backend/base'
|
31
|
+
require 'bones/rpc/backend/synchronous'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Bones
|
3
|
+
module RPC
|
4
|
+
module Backend
|
5
|
+
module Base
|
6
|
+
|
7
|
+
def backend_name
|
8
|
+
raise NotImplementedError, "Backend #{self.name} does not implement #backend_name"
|
9
|
+
end
|
10
|
+
|
11
|
+
def setup
|
12
|
+
raise NotImplementedError, "Backend #{self.name} does not implement #setup"
|
13
|
+
end
|
14
|
+
|
15
|
+
def connection_class
|
16
|
+
raise NotImplementedError, "Backend #{self.name} does not implement #connection_class"
|
17
|
+
end
|
18
|
+
|
19
|
+
def future_class
|
20
|
+
raise NotImplementedError, "Backend #{self.name} does not implement #future_class"
|
21
|
+
end
|
22
|
+
|
23
|
+
def node_class
|
24
|
+
raise NotImplementedError, "Backend #{self.name} does not implement #node_class"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Bones
|
3
|
+
module RPC
|
4
|
+
module Backend
|
5
|
+
module Synchronous
|
6
|
+
|
7
|
+
@backend_name = :synchronous
|
8
|
+
|
9
|
+
def setup
|
10
|
+
require 'bones/rpc/synchronous'
|
11
|
+
end
|
12
|
+
|
13
|
+
def connection_class
|
14
|
+
::Bones::RPC::Synchronous::Connection
|
15
|
+
end
|
16
|
+
|
17
|
+
def future_class
|
18
|
+
::Bones::RPC::Synchronous::Future
|
19
|
+
end
|
20
|
+
|
21
|
+
def node_class
|
22
|
+
::Bones::RPC::Synchronous::Node
|
23
|
+
end
|
24
|
+
|
25
|
+
Backend.register self
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/bones/rpc/cluster.rb
CHANGED
@@ -7,22 +7,22 @@ module Bones
|
|
7
7
|
# The cluster represents a cluster of MongoDB server nodes, either a single
|
8
8
|
# node, a replica set, or a mongos server.
|
9
9
|
#
|
10
|
-
# @since
|
10
|
+
# @since 0.0.1
|
11
11
|
class Cluster
|
12
12
|
|
13
13
|
# The default interval that a node would be flagged as "down".
|
14
14
|
#
|
15
|
-
# @since
|
15
|
+
# @since 0.0.1
|
16
16
|
DOWN_INTERVAL = 30
|
17
17
|
|
18
18
|
# The default interval that a node should be refreshed in.
|
19
19
|
#
|
20
|
-
# @since
|
20
|
+
# @since 0.0.1
|
21
21
|
REFRESH_INTERVAL = 300
|
22
22
|
|
23
23
|
# The default time to wait to retry an operation.
|
24
24
|
#
|
25
|
-
# @since
|
25
|
+
# @since 0.0.1
|
26
26
|
RETRY_INTERVAL = 0.25
|
27
27
|
|
28
28
|
# @!attribute options
|
@@ -39,7 +39,7 @@ module Bones
|
|
39
39
|
#
|
40
40
|
# @return [ true ] True if the disconnect succeeded.
|
41
41
|
#
|
42
|
-
# @since
|
42
|
+
# @since 0.0.1
|
43
43
|
def disconnect
|
44
44
|
nodes.each { |node| node.disconnect } and true
|
45
45
|
end
|
@@ -52,7 +52,7 @@ module Bones
|
|
52
52
|
#
|
53
53
|
# @return [ Integer ] The down interval.
|
54
54
|
#
|
55
|
-
# @since
|
55
|
+
# @since 0.0.1
|
56
56
|
def down_interval
|
57
57
|
@down_interval ||= options[:down_interval] || DOWN_INTERVAL
|
58
58
|
end
|
@@ -75,10 +75,10 @@ module Bones
|
|
75
75
|
# @option options [ Integer ] :timeout The time in seconds to wait for an
|
76
76
|
# operation to timeout. (5)
|
77
77
|
#
|
78
|
-
# @since
|
78
|
+
# @since 0.0.1
|
79
79
|
def initialize(session, hosts)
|
80
80
|
@session = session
|
81
|
-
@seeds = hosts.map { |host|
|
81
|
+
@seeds = hosts.map { |host| session.backend.node_class.new(self, Address.new(host)) }
|
82
82
|
@peers = []
|
83
83
|
end
|
84
84
|
|
@@ -89,7 +89,7 @@ module Bones
|
|
89
89
|
#
|
90
90
|
# @return [ String ] A nicely formatted string.
|
91
91
|
#
|
92
|
-
# @since
|
92
|
+
# @since 0.0.1
|
93
93
|
def inspect
|
94
94
|
"#<#{self.class.name}:#{object_id} @seeds=#{seeds.inspect}>"
|
95
95
|
end
|
@@ -102,7 +102,7 @@ module Bones
|
|
102
102
|
#
|
103
103
|
# @return [ Integer ] The max retries.
|
104
104
|
#
|
105
|
-
# @since
|
105
|
+
# @since 0.0.1
|
106
106
|
def max_retries
|
107
107
|
@max_retries ||= options[:max_retries] || seeds.size
|
108
108
|
end
|
@@ -116,7 +116,7 @@ module Bones
|
|
116
116
|
#
|
117
117
|
# @return [ Array<Node> ] the list of available nodes.
|
118
118
|
#
|
119
|
-
# @since
|
119
|
+
# @since 0.0.1
|
120
120
|
def nodes
|
121
121
|
# Find the nodes that were down but are ready to be refreshed, or those
|
122
122
|
# with stale connection information.
|
@@ -153,7 +153,7 @@ module Bones
|
|
153
153
|
#
|
154
154
|
# @return [ Array<Node> ] the available nodes
|
155
155
|
#
|
156
|
-
# @since
|
156
|
+
# @since 0.0.1
|
157
157
|
def refresh(nodes_to_refresh = seeds)
|
158
158
|
refreshed_nodes = []
|
159
159
|
seen = {}
|
@@ -184,7 +184,7 @@ module Bones
|
|
184
184
|
#
|
185
185
|
# @return [ Integer ] The refresh interval.
|
186
186
|
#
|
187
|
-
# @since
|
187
|
+
# @since 0.0.1
|
188
188
|
def refresh_interval
|
189
189
|
@refresh_interval ||= options[:refresh_interval] || REFRESH_INTERVAL
|
190
190
|
end
|
@@ -197,7 +197,7 @@ module Bones
|
|
197
197
|
#
|
198
198
|
# @return [ Integer ] The retry interval.
|
199
199
|
#
|
200
|
-
# @since
|
200
|
+
# @since 0.0.1
|
201
201
|
def retry_interval
|
202
202
|
@retry_interval ||= options[:retry_interval] || RETRY_INTERVAL
|
203
203
|
end
|
@@ -213,7 +213,7 @@ module Bones
|
|
213
213
|
#
|
214
214
|
# @return [ Time ] The down boundary.
|
215
215
|
#
|
216
|
-
# @since
|
216
|
+
# @since 0.0.1
|
217
217
|
def down_boundary
|
218
218
|
Time.new - down_interval
|
219
219
|
end
|
@@ -227,7 +227,7 @@ module Bones
|
|
227
227
|
#
|
228
228
|
# @return [ Time ] The refresh boundary.
|
229
229
|
#
|
230
|
-
# @since
|
230
|
+
# @since 0.0.1
|
231
231
|
def refresh_boundary
|
232
232
|
Time.new - refresh_interval
|
233
233
|
end
|
@@ -243,7 +243,7 @@ module Bones
|
|
243
243
|
#
|
244
244
|
# @param [ Node ] node The Node to check.
|
245
245
|
#
|
246
|
-
# @since
|
246
|
+
# @since 0.0.1
|
247
247
|
def refreshable?(node)
|
248
248
|
node.down? ? node.down_at < down_boundary : node.needs_refresh?(refresh_boundary)
|
249
249
|
end
|
@@ -257,7 +257,7 @@ module Bones
|
|
257
257
|
#
|
258
258
|
# @return [ Cluster ] The cloned cluster.
|
259
259
|
#
|
260
|
-
# @since
|
260
|
+
# @since 0.0.1
|
261
261
|
def initialize_copy(_)
|
262
262
|
@seeds = seeds.map(&:dup)
|
263
263
|
end
|