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
@@ -6,7 +6,7 @@ module Bones
|
|
6
6
|
# Provides the shared behaviour for read preferences that can filter by a
|
7
7
|
# tag set or add query options.
|
8
8
|
#
|
9
|
-
# @since
|
9
|
+
# @since 0.0.1
|
10
10
|
module Selectable
|
11
11
|
|
12
12
|
# @!attribute tags
|
@@ -20,7 +20,7 @@ module Bones
|
|
20
20
|
#
|
21
21
|
# @param [ Array<Hash> ] tags The tag sets.
|
22
22
|
#
|
23
|
-
# @since
|
23
|
+
# @since 0.0.1
|
24
24
|
def initialize(tags = nil)
|
25
25
|
@tags = tags
|
26
26
|
end
|
@@ -34,7 +34,7 @@ module Bones
|
|
34
34
|
#
|
35
35
|
# @return [ Hash ] The options plus additional query options.
|
36
36
|
#
|
37
|
-
# @since
|
37
|
+
# @since 0.0.1
|
38
38
|
def query_options(options)
|
39
39
|
options[:flags] ||= []
|
40
40
|
options[:flags] |= [ :slave_ok ]
|
@@ -60,7 +60,7 @@ module Bones
|
|
60
60
|
#
|
61
61
|
# @return [ Object ] The result of the block.
|
62
62
|
#
|
63
|
-
# @since
|
63
|
+
# @since 0.0.1
|
64
64
|
def with_retry(cluster, retries = cluster.max_retries, &block)
|
65
65
|
begin
|
66
66
|
block.call
|
data/lib/bones/rpc/readable.rb
CHANGED
@@ -4,7 +4,7 @@ module Bones
|
|
4
4
|
|
5
5
|
# Provides behaviour around readable objects.
|
6
6
|
#
|
7
|
-
# @since
|
7
|
+
# @since 0.0.1
|
8
8
|
module Readable
|
9
9
|
|
10
10
|
private
|
@@ -18,7 +18,7 @@ module Bones
|
|
18
18
|
#
|
19
19
|
# @return [ Cluster ] The cluster.
|
20
20
|
#
|
21
|
-
# @since
|
21
|
+
# @since 0.0.1
|
22
22
|
def cluster
|
23
23
|
session.cluster
|
24
24
|
end
|
@@ -32,7 +32,7 @@ module Bones
|
|
32
32
|
#
|
33
33
|
# @return [ Object ] The session's read preference.
|
34
34
|
#
|
35
|
-
# @since
|
35
|
+
# @since 0.0.1
|
36
36
|
def read_preference
|
37
37
|
session.read_preference
|
38
38
|
end
|
@@ -48,7 +48,7 @@ module Bones
|
|
48
48
|
#
|
49
49
|
# @return [ Hash ] The new query options.
|
50
50
|
#
|
51
|
-
# @since
|
51
|
+
# @since 0.0.1
|
52
52
|
def query_options(options = {})
|
53
53
|
read_preference.query_options(options)
|
54
54
|
end
|
data/lib/bones/rpc/session.rb
CHANGED
@@ -28,7 +28,7 @@ module Bones
|
|
28
28
|
# session = Bones::RPC::Session.new %w[127.0.0.1:27017],
|
29
29
|
# session.with(database: "admin").login("admin", "s3cr3t")
|
30
30
|
#
|
31
|
-
# @since
|
31
|
+
# @since 0.0.1
|
32
32
|
class Session
|
33
33
|
include Optionable
|
34
34
|
|
@@ -38,13 +38,17 @@ module Bones
|
|
38
38
|
# @return [ Hash ] The configuration options.
|
39
39
|
attr_reader :cluster, :options
|
40
40
|
|
41
|
+
def backend
|
42
|
+
@backend ||= Backend.get(options[:backend] || :synchronous).tap(&:setup)
|
43
|
+
end
|
44
|
+
|
41
45
|
# Run +command+ on the current database.
|
42
46
|
#
|
43
47
|
# @param (see Bones::RPC::Database#command)
|
44
48
|
#
|
45
49
|
# @return (see Bones::RPC::Database#command)
|
46
50
|
#
|
47
|
-
# @since
|
51
|
+
# @since 0.0.1
|
48
52
|
def command(op)
|
49
53
|
current_database.command(op)
|
50
54
|
end
|
@@ -59,7 +63,7 @@ module Bones
|
|
59
63
|
#
|
60
64
|
# @return [ true ] True if the disconnect succeeded.
|
61
65
|
#
|
62
|
-
# @since
|
66
|
+
# @since 0.0.1
|
63
67
|
def disconnect
|
64
68
|
cluster.disconnect
|
65
69
|
end
|
@@ -75,51 +79,56 @@ module Bones
|
|
75
79
|
#
|
76
80
|
# @return [ String ] The string inspection.
|
77
81
|
#
|
78
|
-
# @since
|
82
|
+
# @since 0.0.1
|
79
83
|
def inspect
|
80
84
|
"<#{self.class.name} seeds=#{cluster.seeds}>"
|
81
85
|
end
|
82
86
|
|
83
87
|
# Setup validation of allowed read preference options.
|
84
88
|
#
|
85
|
-
# @since
|
89
|
+
# @since 0.0.1
|
86
90
|
option(:read).allow(
|
87
91
|
:nearest
|
88
92
|
)
|
89
93
|
|
90
|
-
# Setup validation of allowed
|
94
|
+
# Setup validation of allowed adapter options. (Any string or symbol)
|
91
95
|
#
|
92
|
-
# @since
|
96
|
+
# @since 0.0.1
|
93
97
|
option(:adapter).allow(Optionable.any(String), Optionable.any(Symbol), Optionable.any(Module))
|
94
98
|
|
99
|
+
# Setup validation of allowed backend options, (Any string or symbol)
|
100
|
+
#
|
101
|
+
# @since 0.0.1
|
102
|
+
option(:backend).allow(Optionable.any(String), Optionable.any(Symbol), Optionable.any(Module))
|
103
|
+
|
95
104
|
# Setup validation of allowed max retry options. (Any integer)
|
96
105
|
#
|
97
|
-
# @since
|
106
|
+
# @since 0.0.1
|
98
107
|
option(:max_retries).allow(Optionable.any(Integer))
|
99
108
|
|
100
109
|
# Setup validation of allowed pool size options. (Any integer)
|
101
110
|
#
|
102
|
-
# @since
|
111
|
+
# @since 0.0.1
|
103
112
|
option(:pool_size).allow(Optionable.any(Integer))
|
104
113
|
|
105
114
|
# Setup validation of allowed retry interval options. (Any numeric)
|
106
115
|
#
|
107
|
-
# @since
|
116
|
+
# @since 0.0.1
|
108
117
|
option(:retry_interval).allow(Optionable.any(Numeric))
|
109
118
|
|
110
119
|
# Setup validation of allowed reap interval options. (Any numeric)
|
111
120
|
#
|
112
|
-
# @since
|
121
|
+
# @since 0.0.1
|
113
122
|
option(:reap_interval).allow(Optionable.any(Numeric))
|
114
123
|
|
115
124
|
# Setup validation of allowed ssl options. (Any boolean)
|
116
125
|
#
|
117
|
-
# @since
|
126
|
+
# @since 0.0.1
|
118
127
|
option(:ssl).allow(true, false)
|
119
128
|
|
120
129
|
# Setup validation of allowed timeout options. (Any numeric)
|
121
130
|
#
|
122
|
-
# @since
|
131
|
+
# @since 0.0.1
|
123
132
|
option(:timeout).allow(Optionable.any(Numeric))
|
124
133
|
|
125
134
|
# Initialize a new database session.
|
@@ -132,7 +141,7 @@ module Bones
|
|
132
141
|
#
|
133
142
|
# @see Above options validations for allowed values in the options hash.
|
134
143
|
#
|
135
|
-
# @since
|
144
|
+
# @since 0.0.1
|
136
145
|
def initialize(seeds, options = {}, &callback)
|
137
146
|
validate_strict(options)
|
138
147
|
@options = options
|
@@ -152,7 +161,7 @@ module Bones
|
|
152
161
|
#
|
153
162
|
# @return [ Object ] The read preference.
|
154
163
|
#
|
155
|
-
# @since
|
164
|
+
# @since 0.0.1
|
156
165
|
def read_preference
|
157
166
|
@read_preference ||= ReadPreference.get(options[:read] || :nearest)
|
158
167
|
end
|
@@ -176,7 +185,7 @@ module Bones
|
|
176
185
|
#
|
177
186
|
# @return [ Session ] The new session.
|
178
187
|
#
|
179
|
-
# @since
|
188
|
+
# @since 0.0.1
|
180
189
|
def connect(uri, &block)
|
181
190
|
uri = Uri.new(uri)
|
182
191
|
session = new(*uri.bones_rpc_arguments, &block)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'bones/rpc/connection'
|
3
|
+
require 'monitor'
|
4
|
+
|
5
|
+
module Bones
|
6
|
+
module RPC
|
7
|
+
module Synchronous
|
8
|
+
|
9
|
+
# This class contains behaviour of Bones::RPC socket connections.
|
10
|
+
#
|
11
|
+
# @since 0.0.1
|
12
|
+
class Connection < ::Bones::RPC::Connection
|
13
|
+
|
14
|
+
require 'bones/rpc/synchronous/connection/reader'
|
15
|
+
require 'bones/rpc/synchronous/connection/socket'
|
16
|
+
require 'bones/rpc/synchronous/connection/writer'
|
17
|
+
|
18
|
+
writer_class ::Bones::RPC::Synchronous::Connection::Writer
|
19
|
+
|
20
|
+
def write(operations)
|
21
|
+
with_connection do |socket|
|
22
|
+
proxy = writer.write(operations)
|
23
|
+
if proxy
|
24
|
+
Timeout::timeout(timeout) do
|
25
|
+
while not proxy.registry_empty?
|
26
|
+
writer.reader.read(proxy)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Bones
|
3
|
+
module RPC
|
4
|
+
module Synchronous
|
5
|
+
class Connection
|
6
|
+
class Reader
|
7
|
+
def initialize(connection, socket, adapter, writer)
|
8
|
+
@connection = connection
|
9
|
+
@socket = socket
|
10
|
+
@adapter = adapter
|
11
|
+
@writer = writer
|
12
|
+
@alive = true
|
13
|
+
@buffer = ""
|
14
|
+
end
|
15
|
+
|
16
|
+
def alive?
|
17
|
+
!!@alive
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse(data, proxy)
|
21
|
+
@buffer << data
|
22
|
+
if @buffer.empty?
|
23
|
+
read(proxy)
|
24
|
+
else
|
25
|
+
parser = Bones::RPC::Parser.new(@buffer, @adapter)
|
26
|
+
begin
|
27
|
+
loop { send parser.read, proxy }
|
28
|
+
rescue EOFError
|
29
|
+
@buffer.replace(parser.buffer.to_str)
|
30
|
+
end
|
31
|
+
return if @buffer.empty?
|
32
|
+
read(proxy)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def read(proxy)
|
37
|
+
parse @socket.readpartial(4096), proxy
|
38
|
+
rescue EOFError, Errors::ConnectionFailure => e
|
39
|
+
Loggable.warn(" BONES-RPC:", "#{@connection.node.address.resolved} Reader terminating: #{e.message}", "n/a")
|
40
|
+
terminate
|
41
|
+
raise e
|
42
|
+
end
|
43
|
+
|
44
|
+
def send(message, proxy)
|
45
|
+
proxy.handle_message(message)
|
46
|
+
end
|
47
|
+
|
48
|
+
def terminate
|
49
|
+
return if not alive?
|
50
|
+
@alive = false
|
51
|
+
@buffer.clear
|
52
|
+
@writer.terminate
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
module Bones
|
5
|
+
module RPC
|
6
|
+
module Synchronous
|
7
|
+
class Connection
|
8
|
+
module Socket
|
9
|
+
|
10
|
+
# This is a wrapper around a tcp socket.
|
11
|
+
class SSL < ::OpenSSL::SSL::SSLSocket
|
12
|
+
include ::Bones::RPC::Connection::Socket::Connectable
|
13
|
+
|
14
|
+
attr_reader :socket
|
15
|
+
|
16
|
+
# Initialize the new TCPSocket with SSL.
|
17
|
+
#
|
18
|
+
# @example Initialize the socket.
|
19
|
+
# SSL.new("127.0.0.1", 27017)
|
20
|
+
#
|
21
|
+
# @param [ String ] host The host.
|
22
|
+
# @param [ Integer ] port The port.
|
23
|
+
#
|
24
|
+
# @since 0.0.1
|
25
|
+
def initialize(remote_host, remote_port, local_host = nil, local_port = nil)
|
26
|
+
@host, @port = remote_host.to_s, remote_port
|
27
|
+
handle_socket_errors do
|
28
|
+
@socket = TCPSocket.new(@host, remote_port, local_host, local_port)
|
29
|
+
super(socket)
|
30
|
+
self.sync_close = true
|
31
|
+
connect
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Set the encoding of the underlying socket.
|
36
|
+
#
|
37
|
+
# @param [ String ] string The encoding.
|
38
|
+
#
|
39
|
+
# @since 0.0.1
|
40
|
+
def set_encoding(string)
|
41
|
+
socket.set_encoding(string)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Set a socket option on the underlying socket.
|
45
|
+
#
|
46
|
+
# @param [ Array<Object> ] args The option arguments.
|
47
|
+
#
|
48
|
+
# @since 0.0.1
|
49
|
+
def setsockopt(*args)
|
50
|
+
socket.setsockopt(*args)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Bones
|
3
|
+
module RPC
|
4
|
+
module Synchronous
|
5
|
+
class Connection
|
6
|
+
module Socket
|
7
|
+
|
8
|
+
# This is a wrapper around a tcp socket.
|
9
|
+
class TCP < ::TCPSocket
|
10
|
+
include ::Bones::RPC::Connection::Socket::Connectable
|
11
|
+
|
12
|
+
# Initialize the new TCPSocket.
|
13
|
+
#
|
14
|
+
# @example Initialize the socket.
|
15
|
+
# TCP.new("127.0.0.1", 27017)
|
16
|
+
#
|
17
|
+
# @param [ String ] remote_host The host.
|
18
|
+
# @param [ Integer ] remote_port The port.
|
19
|
+
#
|
20
|
+
# @since 0.0.1
|
21
|
+
def initialize(remote_host, remote_port, local_host = nil, local_port = nil)
|
22
|
+
@host, @port = remote_host.to_s, remote_port
|
23
|
+
handle_socket_errors { super(@host, port, local_host, local_port) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Bones
|
3
|
+
module RPC
|
4
|
+
module Synchronous
|
5
|
+
class Connection
|
6
|
+
class Writer
|
7
|
+
attr_reader :reader
|
8
|
+
|
9
|
+
def initialize(connection, socket, adapter)
|
10
|
+
@connection = connection
|
11
|
+
@socket = socket
|
12
|
+
@adapter = adapter
|
13
|
+
@resolved = @connection.node.address.resolved
|
14
|
+
@alive = true
|
15
|
+
@buffer = ""
|
16
|
+
@reader = Reader.new(@connection, @socket, @adapter, self)
|
17
|
+
end
|
18
|
+
|
19
|
+
def alive?
|
20
|
+
!!@alive
|
21
|
+
end
|
22
|
+
|
23
|
+
def async
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def write(operations)
|
28
|
+
proxy = NodeProxy.new(@connection.node)
|
29
|
+
operations.each do |message, future|
|
30
|
+
message.serialize(@buffer, @adapter)
|
31
|
+
message.attach(proxy, future) if future
|
32
|
+
end
|
33
|
+
@socket.write(@buffer)
|
34
|
+
@buffer = ""
|
35
|
+
return proxy
|
36
|
+
rescue EOFError, Errors::ConnectionFailure => e
|
37
|
+
Loggable.warn(" BONES-RPC:", "#{@resolved} Writer terminating: #{e.message}", "n/a")
|
38
|
+
terminate
|
39
|
+
raise e
|
40
|
+
end
|
41
|
+
|
42
|
+
def terminate
|
43
|
+
return if not alive?
|
44
|
+
@alive = false
|
45
|
+
@reader.terminate
|
46
|
+
@connection.cleanup_socket(@socket)
|
47
|
+
end
|
48
|
+
|
49
|
+
class NodeProxy < ::BasicObject
|
50
|
+
def attach(channel, id, future)
|
51
|
+
@registry.set(channel, id, future)
|
52
|
+
end
|
53
|
+
|
54
|
+
def detach(channel, id)
|
55
|
+
@registry.get(channel, id)
|
56
|
+
end
|
57
|
+
|
58
|
+
def handle_message(message)
|
59
|
+
logging(message) do
|
60
|
+
if future = message.get(self)
|
61
|
+
message.signal(future)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def initialize(node)
|
67
|
+
@node = node
|
68
|
+
@registry = Node::Registry.new
|
69
|
+
end
|
70
|
+
|
71
|
+
def registry_empty?
|
72
|
+
@registry.empty?
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
|
77
|
+
def method_missing(name, *args, &block)
|
78
|
+
@node.__send__(name, *args, &block)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|