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