bones-rpc 0.0.2 → 0.0.3
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 +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
|