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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-gemset +1 -1
  3. data/.ruby-version +1 -1
  4. data/bones-rpc.gemspec +1 -4
  5. data/lib/bones/rpc.rb +1 -1
  6. data/lib/bones/rpc/adapter.rb +44 -4
  7. data/lib/bones/rpc/adapter/json.rb +66 -0
  8. data/lib/bones/rpc/address.rb +6 -4
  9. data/lib/bones/rpc/backend.rb +31 -0
  10. data/lib/bones/rpc/backend/base.rb +30 -0
  11. data/lib/bones/rpc/backend/synchronous.rb +29 -0
  12. data/lib/bones/rpc/cluster.rb +18 -18
  13. data/lib/bones/rpc/connection.rb +19 -15
  14. data/lib/bones/rpc/connection/socket.rb +0 -2
  15. data/lib/bones/rpc/connection/socket/connectable.rb +15 -11
  16. data/lib/bones/rpc/context.rb +2 -2
  17. data/lib/bones/rpc/dns_resolver.rb +85 -0
  18. data/lib/bones/rpc/errors.rb +3 -0
  19. data/lib/bones/rpc/failover.rb +3 -3
  20. data/lib/bones/rpc/failover/disconnect.rb +2 -2
  21. data/lib/bones/rpc/failover/ignore.rb +2 -2
  22. data/lib/bones/rpc/failover/retry.rb +2 -2
  23. data/lib/bones/rpc/instrumentable.rb +3 -3
  24. data/lib/bones/rpc/instrumentable/log.rb +2 -2
  25. data/lib/bones/rpc/instrumentable/noop.rb +2 -2
  26. data/lib/bones/rpc/loggable.rb +8 -8
  27. data/lib/bones/rpc/node.rb +47 -37
  28. data/lib/bones/rpc/node/registry.rb +4 -0
  29. data/lib/bones/rpc/parser.rb +16 -5
  30. data/lib/bones/rpc/parser/buffer.rb +6 -2
  31. data/lib/bones/rpc/protocol/adapter_helper.rb +2 -2
  32. data/lib/bones/rpc/protocol/binary_helper.rb +2 -2
  33. data/lib/bones/rpc/read_preference.rb +3 -3
  34. data/lib/bones/rpc/read_preference/nearest.rb +3 -3
  35. data/lib/bones/rpc/read_preference/selectable.rb +4 -4
  36. data/lib/bones/rpc/readable.rb +4 -4
  37. data/lib/bones/rpc/session.rb +25 -16
  38. data/lib/bones/rpc/synchronous.rb +2 -0
  39. data/lib/bones/rpc/synchronous/connection.rb +36 -0
  40. data/lib/bones/rpc/synchronous/connection/reader.rb +59 -0
  41. data/lib/bones/rpc/synchronous/connection/socket.rb +4 -0
  42. data/lib/bones/rpc/synchronous/connection/socket/ssl.rb +57 -0
  43. data/lib/bones/rpc/synchronous/connection/socket/tcp.rb +30 -0
  44. data/lib/bones/rpc/synchronous/connection/writer.rb +86 -0
  45. data/lib/bones/rpc/synchronous/future.rb +91 -0
  46. data/lib/bones/rpc/synchronous/node.rb +45 -0
  47. data/lib/bones/rpc/uri.rb +20 -20
  48. data/lib/bones/rpc/version.rb +1 -1
  49. metadata +16 -52
  50. data/lib/bones/rpc/adapter/erlang.rb +0 -28
  51. data/lib/bones/rpc/adapter/msgpack.rb +0 -52
  52. data/lib/bones/rpc/connection/reader.rb +0 -49
  53. data/lib/bones/rpc/connection/socket/ssl.rb +0 -35
  54. data/lib/bones/rpc/connection/socket/tcp.rb +0 -28
  55. data/lib/bones/rpc/connection/writer.rb +0 -51
  56. data/lib/bones/rpc/future.rb +0 -26
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cbf1eca258ffb6071f1299db7578fbcc9d98f121
4
- data.tar.gz: fe15de1e247f1ef12bdc24520a2b9cf520fadbb8
3
+ metadata.gz: 64b5fc8956bbbb066be3f8d398bc89cb2027f2be
4
+ data.tar.gz: 20261b3e59c98eb0693c7bc08f694c85af48f5c5
5
5
  SHA512:
6
- metadata.gz: 8e2ac1a8610ccfd42c5c9a257cc6cc21e0b2242b1e3582ee9ee0bbd3a73d2f902b29597c88676dc7767e51c2836ce20fd60cb5b1a70875f93dacbed56fe2ae67
7
- data.tar.gz: 6acdf3a32e6ab6a2df2a8643f3230e8bf0bd35255ffb7f1b8352fc0ca1a11be8b6d587740533f304587e69fc8c0d6f3917677c72111bc8a2c973ab1b744f6d91
6
+ metadata.gz: 84314e5a51a7723fd7455eeda8ced426375b5022b8ee2093ebdd50aecafc47345e3bea46d8b11f87c77f393d242e11942a249f0caac005a3112af7efa3fd3790
7
+ data.tar.gz: 32a75f9c693b9de01ffbb4f77d6ba25dcc799af9ded5f4686a5414c6b323c421813cf3597b3be7b27e4fc8ebe3d6bc9054f86c3057f35104b31c4648d4d720db
@@ -1 +1 @@
1
- bones
1
+ bones-rpc
@@ -1 +1 @@
1
- ruby-2.0.0
1
+ ruby-2.0.0
@@ -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@delorum.com"]
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"
@@ -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'
@@ -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
@@ -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 2.0.0
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 2.0.0
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 2.0.0
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(::Celluloid::IO::DNSResolver.new.resolve(@host))
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
@@ -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 1.0.0
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 2.0.0
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 2.0.0
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 2.0.0
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 1.2.0
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 1.2.7
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 1.0.0
78
+ # @since 0.0.1
79
79
  def initialize(session, hosts)
80
80
  @session = session
81
- @seeds = hosts.map { |host| Node.new(self, Address.new(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 1.0.0
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 1.2.7
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 1.0.0
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 1.0.0
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 1.2.7
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 1.2.7
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 2.0.0
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 2.0.0
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 2.0.0
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 1.0.0
260
+ # @since 0.0.1
261
261
  def initialize_copy(_)
262
262
  @seeds = seeds.map(&:dup)
263
263
  end