gibson 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OGM1OGIwOGQzM2Y5NzhlNWEzYjk5NTBlNGNkNjg5NzcyYWUwNWZkNw==
4
+ NDkwOWNiM2EzZDcwYjAxMWNhMzUyNjYwODA0OWVmZjc0YzFlMjgxNQ==
5
5
  data.tar.gz: !binary |-
6
- N2M4NzlhM2E0MDMzODcxZmUxZTUxYjI5MTBhZThiYjhjMzMxYzczMA==
6
+ NmI3MzIzMWNlOTgyMDY2MWM5NWM1YWE5NjkyNmNiZGI2NjZkNDc1Mg==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- NDk3ZjhjMDRmNTI1M2EyOTAwOGZjMDRmMTZiMDQwMzEzNGQ3MTBkMjc1NTYz
10
- OGEwNWU4NDcxZjYyYzVlYjBjN2QwNzU3MjZhYWIwMDA1OGQxMWQ4YTYwZmIz
11
- NTRkZDgxMzNkZDg4YzdjZGRhMTM1NGQyYjU4MDRhMzU0ODU2OTM=
9
+ Mjc3OGE1ZWI5YjYyMDllMGU1OTAyN2ZlZWRiMjQwYzViOWY2ZTQ5MmFlYTlh
10
+ OTNjYzFiZjkwZDI2ODg2NGMwZGY0N2QxOWJjODUyZjU0Yzk4ZWMxZDFiZjAw
11
+ MDVjMDk0ZGViOWMzOWJhMjI0YzQzODEzMDcwYWI5OTIyODYyMzU=
12
12
  data.tar.gz: !binary |-
13
- OWIzYzY1OGRkNDkyNDViMTY2MTg5NWMzNDNiNzE4NmFjMmIwNmY4YzAwMjRj
14
- NWM2YTkzNTk1MzAxYWRhNzUxZWM1M2JkOWFlMDJlYzI4MDliMmEyN2Y2MGY3
15
- OWI1YzBlN2FlNDQ4NTQxNmVhNWFiMmZjNGNjNDZlOWI2MWEyMjk=
13
+ MGJkYTVhNGM5NDEyZTZjZGJjN2I0YmExMGI4ODcyMGM0NTdhN2QxYmVkN2Uy
14
+ ZDQ2Mzc1NzlhZDQzNDA4NmI4YzdjNWY0Njg0NzRiNWQ1ZGI0MjMzMGJlY2Ji
15
+ ZWY1N2E1YWRkYzkwMWQ2ZDA5MGJlMDQzMTBlYmJkMmI0YTg0ZmI=
@@ -26,55 +26,86 @@
26
26
  # POSSIBILITY OF SUCH DAMAGE.
27
27
  module Gibson
28
28
  require 'socket'
29
-
29
+ require 'timeout'
30
+
30
31
  class Connection
32
+ ##
33
+ # Connection default options.
31
34
  DEFAULTS = {
35
+ # The UNIX socket path, if this option is set a UNIX socket connection will be used.
32
36
  :socket => '/var/run/gibson.sock',
37
+ # The ip address to connect to, if this option is set a TCP socket connection will be used.
33
38
  :address => nil,
39
+ # The tcp port to connect to.
34
40
  :port => 10128,
41
+ # The connection and I/O timeout in milliseconds.
35
42
  :timeout => 100,
43
+ # If a TCP connection will be used, set this to true to use the SO_KEEPALIVE flag on the socket.
36
44
  :keepalive => false
37
45
  }
38
46
 
47
+ ##
48
+ # Create a new Connection instance with custom options.
49
+ # If no options are specified, Connection.DEFAULTS will be used.
50
+ # For instance:
51
+ # Gibson::Client.new # will create a connection to the default /var/run/gibson.sock UNIX socket.
52
+ # Gibson::Client.new :address => '127.0.0.1' # will connect to localhost:10128
39
53
  def initialize(opts = {})
40
54
  @sock = nil
41
55
  @connected = false
42
56
  @options = DEFAULTS.merge(opts)
43
57
  end
44
58
 
59
+ ##
60
+ # Return true if connection is enstablished, otherwise false.
45
61
  def connected?
46
62
  @connected
47
63
  end
48
64
 
65
+ ##
66
+ # Attempt a connection with the specified options until @options[:timeout]
67
+ # is reached.
49
68
  def connect
50
- if @options[:address] != nil
51
- @sock = TCPSocket.new( @options[:address], @options[:port] )
52
- @sock.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true )
53
- @sock.setsockopt( Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true ) if @options[:keepalive]
54
- else
55
- @sock = UNIXSocket.open( @options[:socket] )
56
- end
69
+ Timeout.timeout(@options[:timeout]) do
70
+ if @options[:address] != nil
71
+ @sock = TCPSocket.new( @options[:address], @options[:port] )
72
+ @sock.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true )
73
+ @sock.setsockopt( Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true ) if @options[:keepalive]
74
+ else
75
+ @sock = UNIXSocket.open( @options[:socket] )
76
+ end
57
77
 
58
- @connected = true
78
+ @connected = true
79
+ end
59
80
  end
60
81
 
82
+ ##
83
+ # Close the connection.
61
84
  def close
62
- @sock.close
85
+ @sock.close if connected?
63
86
  end
64
87
 
88
+ ##
89
+ # Wait for the socket to be in a writable state for @options[:timeout] milliseconds.
65
90
  def wait_writable
66
91
  IO.select(nil, [@sock], nil, @options[:timeout] ) || raise(Timeout::Error, "IO timeout")
67
92
  end
68
93
 
94
+ ##
95
+ # Wait for the socket to be in a readable state for @options[:timeout] milliseconds.
69
96
  def wait_readable
70
97
  IO.select( [@sock], nil, nil, @options[:timeout] ) || raise(Timeout::Error, "IO timeout")
71
98
  end
72
99
 
100
+ ##
101
+ # Write data to the socket.
73
102
  def write(data)
74
103
  wait_writable
75
104
  @sock.write data
76
105
  end
77
106
 
107
+ ##
108
+ # Read specified amount of data from the socket.
78
109
  def read(n)
79
110
  wait_readable
80
111
  @sock.recv n
data/lib/gibson/gibson.rb CHANGED
@@ -29,16 +29,23 @@ require 'gibson/connection'
29
29
 
30
30
  module Gibson
31
31
  class Client
32
+ ##
33
+ # Create a new Gibson::Client instance, the options are passed to
34
+ # Gibson::Connection initialize method.
32
35
  def initialize(opts = {})
33
36
  @connection = nil
34
37
  @options = opts
35
38
  end
36
39
 
40
+ ##
41
+ # Create the connection.
37
42
  def connect
38
43
  @connection = Connection.new( @options )
39
44
  @connection.connect
40
45
  end
41
46
 
47
+ ##
48
+ # Decode a REPL_VAL reply.
42
49
  def decode_val( encoding, size, data )
43
50
  # plain string
44
51
  if encoding == Protocol::ENCODINGS[:plain]
@@ -56,6 +63,8 @@ module Gibson
56
63
  end
57
64
  end
58
65
 
66
+ ##
67
+ # Decode a REPL_KVAL reply.
59
68
  def decode_kval( data, size )
60
69
  left = size - 4
61
70
  count, data = data.unpack( 'L<a' + left.to_s )
@@ -83,6 +92,8 @@ module Gibson
83
92
  obj
84
93
  end
85
94
 
95
+ ##
96
+ # Reply decoding wrapper.
86
97
  def decode( code, encoding, size, data )
87
98
  if code == Protocol::REPLIES[:val]
88
99
  decode_val encoding, size, data
@@ -101,6 +112,10 @@ module Gibson
101
112
  end
102
113
  end
103
114
 
115
+ ##
116
+ # Send a query to the server given its opcode and arguments payload.
117
+ # Return the decoded data, or raise one of the RuntimeErrors defined
118
+ # inside Gibson::Protocol.
104
119
  def query( opcode, payload = '' )
105
120
  connect if @connection == nil or not @connection.connected?
106
121
 
@@ -115,10 +130,21 @@ module Gibson
115
130
  decode code, encoding, size, data
116
131
  end
117
132
 
133
+ ##
134
+ # This method will be called for every undefined method call
135
+ # of Gibson::Client mapping the method to its opcode and creating
136
+ # its argument payload.
137
+ # For instance a call to:
138
+ # client = Gibson::Client.new
139
+ # client.set 0, 'foo', 'bar'
140
+ # Will be executed as:
141
+ # client.query Protocol::COMMANDS[:set], '0 foo bar'
118
142
  def method_missing(name, *arguments)
119
143
  if Protocol::COMMANDS.has_key? name
120
144
  query Protocol::COMMANDS[name], arguments.join(' ')
121
145
  end
122
146
  end
147
+
148
+ private :decode_val, :decode_kval, :decode
123
149
  end
124
150
  end
@@ -25,13 +25,19 @@
25
25
  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
26
  # POSSIBILITY OF SUCH DAMAGE.
27
27
  module Gibson
28
+ # A generic protocol error.
28
29
  class GenericError < RuntimeError; end
30
+ # Key or prefix not found.
29
31
  class NotFoundError < RuntimeError; end
32
+ # Specified value is not a number.
30
33
  class NaNError < RuntimeError; end
34
+ # The server is out of memory.
31
35
  class OutOfMemoryError < RuntimeError; end
36
+ # The object is locked and can't be modified.
32
37
  class LockedError < RuntimeError; end
33
38
 
34
39
  class Protocol
40
+ # Query opcodes.
35
41
  COMMANDS = {
36
42
  :set => 1,
37
43
  :ttl => 2,
@@ -57,6 +63,7 @@ module Gibson
57
63
  :end => 0xff
58
64
  }
59
65
 
66
+ # Server replies opcodes.
60
67
  REPLIES = {
61
68
  :error => 0, # Generic error
62
69
  :not_found => 1, # Key/Prefix not found
@@ -68,6 +75,7 @@ module Gibson
68
75
  :kval => 7 # Ok, [ key => value, ... ] follows
69
76
  }
70
77
 
78
+ # Error code to exception map.
71
79
  ERRORS = {
72
80
  0 => GenericError,
73
81
  1 => NotFoundError,
@@ -76,12 +84,18 @@ module Gibson
76
84
  4 => LockedError
77
85
  }
78
86
 
87
+ # Incoming data encodings.
79
88
  ENCODINGS = {
80
- :plain => 0x00, # the item is in plain encoding and data points to its buffer
81
- :lzf => 0x01, # PLAIN but compressed data with lzf
82
- :number => 0x02 # the item contains a number and data pointer is actually that number
89
+ # the item is in plain encoding and data points to its buffer
90
+ :plain => 0x00,
91
+ # PLAIN but compressed data with lzf
92
+ :lzf => 0x01,
93
+ # the item contains a number and data pointer is actually that number
94
+ :number => 0x02
83
95
  }
84
96
 
97
+ ##
98
+ # Return true if the specified code is an error code, otherwise false.
85
99
  def self.error? (code)
86
100
  code >= REPLIES[:error] && code <= REPLIES[:locked]
87
101
  end
@@ -25,6 +25,6 @@
25
25
  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
26
  # POSSIBILITY OF SUCH DAMAGE.
27
27
  module Gibson
28
- VERSION = '1.0.2'
28
+ VERSION = '1.0.3'
29
29
  end
30
30
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gibson
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simone Margaritelli