gibson 1.0.3 → 1.0.4
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.
- data/README.md +1 -1
- data/lib/gibson/connection.rb +75 -101
- data/lib/gibson/gibson.rb +114 -144
- data/lib/gibson/protocol.rb +69 -95
- data/lib/gibson/version.rb +1 -27
- metadata +9 -7
- checksums.yaml +0 -15
data/README.md
CHANGED
data/lib/gibson/connection.rb
CHANGED
@@ -1,114 +1,88 @@
|
|
1
|
-
# Copyright (c) 2013, Simone Margaritelli <evilsocket at gmail dot com>
|
2
|
-
# All rights reserved.
|
3
|
-
#
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are met:
|
6
|
-
#
|
7
|
-
# * Redistributions of source code must retain the above copyright notice,
|
8
|
-
# this list of conditions and the following disclaimer.
|
9
|
-
# * Redistributions in binary form must reproduce the above copyright
|
10
|
-
# notice, this list of conditions and the following disclaimer in the
|
11
|
-
# documentation and/or other materials provided with the distribution.
|
12
|
-
# * Neither the name of Gibson nor the names of its contributors may be used
|
13
|
-
# to endorse or promote products derived from this software without
|
14
|
-
# specific prior written permission.
|
15
|
-
#
|
16
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
-
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
20
|
-
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
21
|
-
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
22
|
-
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
23
|
-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
24
|
-
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
25
|
-
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
26
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
27
1
|
module Gibson
|
28
|
-
|
29
|
-
|
2
|
+
require 'socket'
|
3
|
+
require 'timeout'
|
30
4
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
5
|
+
class Connection
|
6
|
+
##
|
7
|
+
# Connection default options.
|
8
|
+
DEFAULTS = {
|
9
|
+
# The UNIX socket path, if this option is set a UNIX socket connection will be used.
|
10
|
+
:socket => '/var/run/gibson.sock',
|
11
|
+
# The ip address to connect to, if this option is set a TCP socket connection will be used.
|
12
|
+
:address => nil,
|
13
|
+
# The tcp port to connect to.
|
14
|
+
:port => 10128,
|
15
|
+
# The connection and I/O timeout in milliseconds.
|
16
|
+
:timeout => 100,
|
17
|
+
# If a TCP connection will be used, set this to true to use the SO_KEEPALIVE flag on the socket.
|
18
|
+
:keepalive => false
|
19
|
+
}
|
46
20
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
##
|
60
|
-
# Return true if connection is enstablished, otherwise false.
|
61
|
-
def connected?
|
62
|
-
@connected
|
63
|
-
end
|
21
|
+
##
|
22
|
+
# Create a new Connection instance with custom options.
|
23
|
+
# If no options are specified, Connection.DEFAULTS will be used.
|
24
|
+
# For instance:
|
25
|
+
# Gibson::Client.new # will create a connection to the default /var/run/gibson.sock UNIX socket.
|
26
|
+
# Gibson::Client.new :address => '127.0.0.1' # will connect to localhost:10128
|
27
|
+
def initialize(opts = {})
|
28
|
+
@sock = nil
|
29
|
+
@connected = false
|
30
|
+
@options = DEFAULTS.merge(opts)
|
31
|
+
end
|
64
32
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
33
|
+
##
|
34
|
+
# Return true if connection is enstablished, otherwise false.
|
35
|
+
def connected?
|
36
|
+
@connected
|
37
|
+
end
|
77
38
|
|
78
|
-
|
79
|
-
|
39
|
+
##
|
40
|
+
# Attempt a connection with the specified options until @options[:timeout]
|
41
|
+
# is reached.
|
42
|
+
def connect
|
43
|
+
Timeout.timeout(@options[:timeout]) do
|
44
|
+
if @options[:address] != nil
|
45
|
+
@sock = TCPSocket.new( @options[:address], @options[:port] )
|
46
|
+
@sock.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true )
|
47
|
+
@sock.setsockopt( Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true ) if @options[:keepalive]
|
48
|
+
else
|
49
|
+
@sock = UNIXSocket.open( @options[:socket] )
|
80
50
|
end
|
81
51
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
@sock.close if connected?
|
86
|
-
end
|
52
|
+
@connected = true
|
53
|
+
end
|
54
|
+
end
|
87
55
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
56
|
+
##
|
57
|
+
# Close the connection.
|
58
|
+
def close
|
59
|
+
@sock.close if connected?
|
60
|
+
end
|
93
61
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
62
|
+
##
|
63
|
+
# Wait for the socket to be in a writable state for @options[:timeout] milliseconds.
|
64
|
+
def wait_writable
|
65
|
+
IO.select(nil, [@sock], nil, @options[:timeout] ) || raise(Timeout::Error, "IO timeout")
|
66
|
+
end
|
99
67
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
68
|
+
##
|
69
|
+
# Wait for the socket to be in a readable state for @options[:timeout] milliseconds.
|
70
|
+
def wait_readable
|
71
|
+
IO.select( [@sock], nil, nil, @options[:timeout] ) || raise(Timeout::Error, "IO timeout")
|
72
|
+
end
|
106
73
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
74
|
+
##
|
75
|
+
# Write data to the socket.
|
76
|
+
def write(data)
|
77
|
+
wait_writable
|
78
|
+
@sock.write data
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Read specified amount of data from the socket.
|
83
|
+
def read(n)
|
84
|
+
wait_readable
|
85
|
+
@sock.recv n
|
113
86
|
end
|
87
|
+
end
|
114
88
|
end
|
data/lib/gibson/gibson.rb
CHANGED
@@ -1,150 +1,120 @@
|
|
1
|
-
# Copyright (c) 2013, Simone Margaritelli <evilsocket at gmail dot com>
|
2
|
-
# All rights reserved.
|
3
|
-
#
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are met:
|
6
|
-
#
|
7
|
-
# * Redistributions of source code must retain the above copyright notice,
|
8
|
-
# this list of conditions and the following disclaimer.
|
9
|
-
# * Redistributions in binary form must reproduce the above copyright
|
10
|
-
# notice, this list of conditions and the following disclaimer in the
|
11
|
-
# documentation and/or other materials provided with the distribution.
|
12
|
-
# * Neither the name of Gibson nor the names of its contributors may be used
|
13
|
-
# to endorse or promote products derived from this software without
|
14
|
-
# specific prior written permission.
|
15
|
-
#
|
16
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
-
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
20
|
-
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
21
|
-
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
22
|
-
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
23
|
-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
24
|
-
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
25
|
-
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
26
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
27
1
|
require 'gibson/protocol'
|
28
2
|
require 'gibson/connection'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
##
|
6
|
+
# Define an utility instance method for the String core class.
|
7
|
+
class StringIO
|
8
|
+
##
|
9
|
+
# Read size bytes and return the first unpacked value given a format.
|
10
|
+
def read_unpacked size, format
|
11
|
+
read( size ).unpack( format )[0]
|
12
|
+
end
|
13
|
+
end
|
29
14
|
|
30
15
|
module Gibson
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
##
|
48
|
-
# Decode a REPL_VAL reply.
|
49
|
-
def decode_val( encoding, size, data )
|
50
|
-
# plain string
|
51
|
-
if encoding == Protocol::ENCODINGS[:plain]
|
52
|
-
data.unpack( 'Z' + size.to_s )[0]
|
53
|
-
# number
|
54
|
-
elsif encoding == Protocol::ENCODINGS[:number]
|
55
|
-
# 32 bit integer ?
|
56
|
-
if size == 4
|
57
|
-
data.unpack( 'l<' )[0]
|
58
|
-
else
|
59
|
-
data.unpack( 'q<' )[0]
|
60
|
-
end
|
61
|
-
else
|
62
|
-
raise 'Unknown data encoding.'
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
##
|
67
|
-
# Decode a REPL_KVAL reply.
|
68
|
-
def decode_kval( data, size )
|
69
|
-
left = size - 4
|
70
|
-
count, data = data.unpack( 'L<a' + left.to_s )
|
71
|
-
obj = {}
|
72
|
-
|
73
|
-
count.times do |i|
|
74
|
-
left -= 4
|
75
|
-
klen, data = data.unpack( 'L<a' + left.to_s )
|
76
|
-
|
77
|
-
left -= klen
|
78
|
-
key, data = data.unpack( 'a' + klen.to_s + 'a' + left.to_s )
|
79
|
-
|
80
|
-
left -= 1
|
81
|
-
enc, data = data.unpack( 'ca' + left.to_s )
|
82
|
-
|
83
|
-
left -= 4
|
84
|
-
vsize, data = data.unpack( 'L<a' + left.to_s )
|
85
|
-
|
86
|
-
left -= vsize
|
87
|
-
value, data = data.unpack( 'a' + vsize.to_s + 'a' + left.to_s )
|
88
|
-
|
89
|
-
obj[key] = decode Protocol::REPLIES[:val], enc, vsize, value
|
90
|
-
end
|
91
|
-
|
92
|
-
obj
|
93
|
-
end
|
94
|
-
|
95
|
-
##
|
96
|
-
# Reply decoding wrapper.
|
97
|
-
def decode( code, encoding, size, data )
|
98
|
-
if code == Protocol::REPLIES[:val]
|
99
|
-
decode_val encoding, size, data
|
100
|
-
|
101
|
-
elsif code == Protocol::REPLIES[:kval]
|
102
|
-
decode_kval data, size
|
103
|
-
|
104
|
-
elsif code == Protocol::REPLIES[:ok]
|
105
|
-
true
|
106
|
-
|
107
|
-
elsif Protocol.error? code
|
108
|
-
raise Protocol::ERRORS[code]
|
109
|
-
|
110
|
-
else
|
111
|
-
data
|
112
|
-
end
|
113
|
-
end
|
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.
|
119
|
-
def query( opcode, payload = '' )
|
120
|
-
connect if @connection == nil or not @connection.connected?
|
121
|
-
|
122
|
-
psize = payload.length
|
123
|
-
packet = [ 2 + psize, opcode, payload ].pack( 'L<S<Z' + psize.to_s )
|
124
|
-
|
125
|
-
@connection.write packet
|
126
|
-
|
127
|
-
code, encoding, size = @connection.read(7).unpack('S<cL<' )
|
128
|
-
data = @connection.read size
|
129
|
-
|
130
|
-
decode code, encoding, size, data
|
131
|
-
end
|
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'
|
142
|
-
def method_missing(name, *arguments)
|
143
|
-
if Protocol::COMMANDS.has_key? name
|
144
|
-
query Protocol::COMMANDS[name], arguments.join(' ')
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
private :decode_val, :decode_kval, :decode
|
16
|
+
class Client
|
17
|
+
##
|
18
|
+
# Create a new Gibson::Client instance, the options are passed to
|
19
|
+
# Gibson::Connection initialize method.
|
20
|
+
def initialize(opts = {})
|
21
|
+
@connection = nil
|
22
|
+
@options = opts
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Create the connection.
|
27
|
+
def connect
|
28
|
+
@connection = Connection.new( @options )
|
29
|
+
@connection.connect
|
149
30
|
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Decode a REPL_VAL reply.
|
34
|
+
def decode_val( encoding, size, io )
|
35
|
+
# plain string
|
36
|
+
if encoding == Protocol::ENCODINGS[:plain]
|
37
|
+
io.read_unpacked size, 'Z' + size.to_s
|
38
|
+
# number
|
39
|
+
elsif encoding == Protocol::ENCODINGS[:number]
|
40
|
+
unpacker = size == 4 ? 'l<' : 'q<'
|
41
|
+
io.read_unpacked size, unpacker
|
42
|
+
else
|
43
|
+
raise 'Unknown data encoding.'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Decode a REPL_KVAL reply.
|
49
|
+
def decode_kval( io, size )
|
50
|
+
count = io.read_unpacked 4, 'L<'
|
51
|
+
obj = {}
|
52
|
+
|
53
|
+
count.times do |i|
|
54
|
+
klen = io.read_unpacked 4, 'L<'
|
55
|
+
key = io.read_unpacked klen, 'a' + klen.to_s
|
56
|
+
enc = io.read_unpacked 1, 'c'
|
57
|
+
vsize = io.read_unpacked 4, 'L<'
|
58
|
+
|
59
|
+
obj[key] = decode Protocol::REPLIES[:val], enc, vsize, io
|
60
|
+
end
|
61
|
+
|
62
|
+
obj
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Reply decoding wrapper.
|
67
|
+
def decode( code, encoding, size, io )
|
68
|
+
if code == Protocol::REPLIES[:val]
|
69
|
+
decode_val encoding, size, io
|
70
|
+
|
71
|
+
elsif code == Protocol::REPLIES[:kval]
|
72
|
+
decode_kval io, size
|
73
|
+
|
74
|
+
elsif code == Protocol::REPLIES[:ok]
|
75
|
+
true
|
76
|
+
|
77
|
+
elsif Protocol.error? code
|
78
|
+
raise Protocol::ERRORS[code]
|
79
|
+
|
80
|
+
else
|
81
|
+
io
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Send a query to the server given its opcode and arguments payload.
|
87
|
+
# Return the decoded data, or raise one of the RuntimeErrors defined
|
88
|
+
# inside Gibson::Protocol.
|
89
|
+
def query( opcode, payload = '' )
|
90
|
+
connect if @connection == nil or not @connection.connected?
|
91
|
+
|
92
|
+
psize = payload.length
|
93
|
+
packet = [ 2 + psize, opcode, payload ].pack( 'L<S<Z' + psize.to_s )
|
94
|
+
|
95
|
+
@connection.write packet
|
96
|
+
|
97
|
+
code, encoding, size = @connection.read(7).unpack('S<cL<' )
|
98
|
+
data = @connection.read size
|
99
|
+
|
100
|
+
decode code, encoding, size, StringIO.new(data)
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# This method will be called for every undefined method call
|
105
|
+
# of Gibson::Client mapping the method to its opcode and creating
|
106
|
+
# its argument payload.
|
107
|
+
# For instance a call to:
|
108
|
+
# client = Gibson::Client.new
|
109
|
+
# client.set 0, 'foo', 'bar'
|
110
|
+
# Will be executed as:
|
111
|
+
# client.query Protocol::COMMANDS[:set], '0 foo bar'
|
112
|
+
def method_missing(name, *arguments)
|
113
|
+
if Protocol::COMMANDS.has_key? name
|
114
|
+
query Protocol::COMMANDS[name], arguments.join(' ')
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private :decode_val, :decode_kval, :decode
|
119
|
+
end
|
150
120
|
end
|
data/lib/gibson/protocol.rb
CHANGED
@@ -1,103 +1,77 @@
|
|
1
|
-
# Copyright (c) 2013, Simone Margaritelli <evilsocket at gmail dot com>
|
2
|
-
# All rights reserved.
|
3
|
-
#
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are met:
|
6
|
-
#
|
7
|
-
# * Redistributions of source code must retain the above copyright notice,
|
8
|
-
# this list of conditions and the following disclaimer.
|
9
|
-
# * Redistributions in binary form must reproduce the above copyright
|
10
|
-
# notice, this list of conditions and the following disclaimer in the
|
11
|
-
# documentation and/or other materials provided with the distribution.
|
12
|
-
# * Neither the name of Gibson nor the names of its contributors may be used
|
13
|
-
# to endorse or promote products derived from this software without
|
14
|
-
# specific prior written permission.
|
15
|
-
#
|
16
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
-
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
20
|
-
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
21
|
-
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
22
|
-
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
23
|
-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
24
|
-
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
25
|
-
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
26
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
27
1
|
module Gibson
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
2
|
+
# A generic protocol error.
|
3
|
+
class GenericError < RuntimeError; end
|
4
|
+
# Key or prefix not found.
|
5
|
+
class NotFoundError < RuntimeError; end
|
6
|
+
# Specified value is not a number.
|
7
|
+
class NaNError < RuntimeError; end
|
8
|
+
# The server is out of memory.
|
9
|
+
class OutOfMemoryError < RuntimeError; end
|
10
|
+
# The object is locked and can't be modified.
|
11
|
+
class LockedError < RuntimeError; end
|
38
12
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
13
|
+
class Protocol
|
14
|
+
# Query opcodes.
|
15
|
+
COMMANDS = {
|
16
|
+
:set => 1,
|
17
|
+
:ttl => 2,
|
18
|
+
:get => 3,
|
19
|
+
:del => 4,
|
20
|
+
:inc => 5,
|
21
|
+
:dec => 6,
|
22
|
+
:lock => 7,
|
23
|
+
:unlock => 8,
|
24
|
+
:mset => 9,
|
25
|
+
:mttl => 10,
|
26
|
+
:mget => 11,
|
27
|
+
:mdel => 12,
|
28
|
+
:minc => 13,
|
29
|
+
:mdec => 14,
|
30
|
+
:mlock => 15,
|
31
|
+
:munlock => 16,
|
32
|
+
:count => 17,
|
33
|
+
:stats => 18,
|
34
|
+
:ping => 19,
|
35
|
+
:meta => 20,
|
36
|
+
:keys => 21,
|
37
|
+
:end => 0xff
|
38
|
+
}
|
65
39
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
40
|
+
# Server replies opcodes.
|
41
|
+
REPLIES = {
|
42
|
+
:error => 0, # Generic error
|
43
|
+
:not_found => 1, # Key/Prefix not found
|
44
|
+
:nan => 2, # Not a number
|
45
|
+
:mem => 3, # Out of memory
|
46
|
+
:locked => 4, # Object is locked
|
47
|
+
:ok => 5, # Ok, no data follows
|
48
|
+
:val => 6, # Ok, scalar value follows
|
49
|
+
:kval => 7 # Ok, [ key => value, ... ] follows
|
50
|
+
}
|
77
51
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
52
|
+
# Error code to exception map.
|
53
|
+
ERRORS = {
|
54
|
+
0 => GenericError,
|
55
|
+
1 => NotFoundError,
|
56
|
+
2 => NaNError,
|
57
|
+
3 => OutOfMemoryError,
|
58
|
+
4 => LockedError
|
59
|
+
}
|
86
60
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
61
|
+
# Incoming data encodings.
|
62
|
+
ENCODINGS = {
|
63
|
+
# the item is in plain encoding and data points to its buffer
|
64
|
+
:plain => 0x00,
|
65
|
+
# PLAIN but compressed data with lzf
|
66
|
+
:lzf => 0x01,
|
67
|
+
# the item contains a number and data pointer is actually that number
|
68
|
+
:number => 0x02
|
69
|
+
}
|
96
70
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
end
|
71
|
+
##
|
72
|
+
# Return true if the specified code is an error code, otherwise false.
|
73
|
+
def self.error? (code)
|
74
|
+
code >= REPLIES[:error] && code <= REPLIES[:locked]
|
102
75
|
end
|
76
|
+
end
|
103
77
|
end
|
data/lib/gibson/version.rb
CHANGED
@@ -1,30 +1,4 @@
|
|
1
|
-
# Copyright (c) 2013, Simone Margaritelli <evilsocket at gmail dot com>
|
2
|
-
# All rights reserved.
|
3
|
-
#
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are met:
|
6
|
-
#
|
7
|
-
# * Redistributions of source code must retain the above copyright notice,
|
8
|
-
# this list of conditions and the following disclaimer.
|
9
|
-
# * Redistributions in binary form must reproduce the above copyright
|
10
|
-
# notice, this list of conditions and the following disclaimer in the
|
11
|
-
# documentation and/or other materials provided with the distribution.
|
12
|
-
# * Neither the name of Gibson nor the names of its contributors may be used
|
13
|
-
# to endorse or promote products derived from this software without
|
14
|
-
# specific prior written permission.
|
15
|
-
#
|
16
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
-
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
20
|
-
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
21
|
-
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
22
|
-
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
23
|
-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
24
|
-
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
25
|
-
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
26
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
27
1
|
module Gibson
|
28
|
-
|
2
|
+
VERSION = '1.0.4'
|
29
3
|
end
|
30
4
|
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gibson
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Simone Margaritelli
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2013-08-
|
12
|
+
date: 2013-08-14 00:00:00.000000000 Z
|
12
13
|
dependencies: []
|
13
14
|
description: High performance Gibson client for Ruby
|
14
15
|
email: evilsocket@gmail.com
|
@@ -16,11 +17,11 @@ executables: []
|
|
16
17
|
extensions: []
|
17
18
|
extra_rdoc_files: []
|
18
19
|
files:
|
20
|
+
- lib/gibson.rb
|
21
|
+
- lib/gibson/protocol.rb
|
19
22
|
- lib/gibson/connection.rb
|
20
23
|
- lib/gibson/gibson.rb
|
21
|
-
- lib/gibson/protocol.rb
|
22
24
|
- lib/gibson/version.rb
|
23
|
-
- lib/gibson.rb
|
24
25
|
- LICENSE
|
25
26
|
- README.md
|
26
27
|
- Rakefile
|
@@ -29,26 +30,27 @@ files:
|
|
29
30
|
homepage: http://gibson-db.in/
|
30
31
|
licenses:
|
31
32
|
- BSD
|
32
|
-
metadata: {}
|
33
33
|
post_install_message:
|
34
34
|
rdoc_options:
|
35
35
|
- --charset=UTF-8
|
36
36
|
require_paths:
|
37
37
|
- lib
|
38
38
|
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
39
40
|
requirements:
|
40
41
|
- - ! '>='
|
41
42
|
- !ruby/object:Gem::Version
|
42
43
|
version: '0'
|
43
44
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
44
46
|
requirements:
|
45
47
|
- - ! '>='
|
46
48
|
- !ruby/object:Gem::Version
|
47
49
|
version: '0'
|
48
50
|
requirements: []
|
49
51
|
rubyforge_project:
|
50
|
-
rubygems_version:
|
52
|
+
rubygems_version: 1.8.23
|
51
53
|
signing_key:
|
52
|
-
specification_version:
|
54
|
+
specification_version: 3
|
53
55
|
summary: High performance Gibson client for Ruby
|
54
56
|
test_files: []
|
checksums.yaml
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
---
|
2
|
-
!binary "U0hBMQ==":
|
3
|
-
metadata.gz: !binary |-
|
4
|
-
NDkwOWNiM2EzZDcwYjAxMWNhMzUyNjYwODA0OWVmZjc0YzFlMjgxNQ==
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
NmI3MzIzMWNlOTgyMDY2MWM5NWM1YWE5NjkyNmNiZGI2NjZkNDc1Mg==
|
7
|
-
!binary "U0hBNTEy":
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
Mjc3OGE1ZWI5YjYyMDllMGU1OTAyN2ZlZWRiMjQwYzViOWY2ZTQ5MmFlYTlh
|
10
|
-
OTNjYzFiZjkwZDI2ODg2NGMwZGY0N2QxOWJjODUyZjU0Yzk4ZWMxZDFiZjAw
|
11
|
-
MDVjMDk0ZGViOWMzOWJhMjI0YzQzODEzMDcwYWI5OTIyODYyMzU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
MGJkYTVhNGM5NDEyZTZjZGJjN2I0YmExMGI4ODcyMGM0NTdhN2QxYmVkN2Uy
|
14
|
-
ZDQ2Mzc1NzlhZDQzNDA4NmI4YzdjNWY0Njg0NzRiNWQ1ZGI0MjMzMGJlY2Ji
|
15
|
-
ZWY1N2E1YWRkYzkwMWQ2ZDA5MGJlMDQzMTBlYmJkMmI0YTg0ZmI=
|