2009-05-20 10:36:12 -04:00
|
|
|
# RubyRedis is an alternative implementatin of Ruby client library written
|
|
|
|
# by Salvatore Sanfilippo.
|
|
|
|
#
|
|
|
|
# The aim of this library is to create an alternative client library that is
|
|
|
|
# much simpler and does not implement every command explicitly but uses
|
|
|
|
# method_missing instead.
|
|
|
|
|
|
|
|
require 'socket'
|
|
|
|
|
|
|
|
class RedisClient
|
|
|
|
BulkCommands = {
|
|
|
|
"set"=>true, "setnx"=>true, "rpush"=>true, "lpush"=>true, "lset"=>true,
|
|
|
|
"lrem"=>true, "sadd"=>true, "srem"=>true, "sismember"=>true,
|
|
|
|
"echo"=>true, "getset"=>true, "smove"=>true
|
|
|
|
}
|
|
|
|
|
2009-05-21 07:22:20 -04:00
|
|
|
ConvertToBool = lambda{|r| r == 0 ? false : r}
|
|
|
|
|
|
|
|
ReplyProcessor = {
|
|
|
|
"exists" => ConvertToBool,
|
|
|
|
"sismember"=> ConvertToBool,
|
|
|
|
"sadd"=> ConvertToBool,
|
|
|
|
"srem"=> ConvertToBool,
|
|
|
|
"smove"=> ConvertToBool,
|
|
|
|
"move"=> ConvertToBool,
|
|
|
|
"setnx"=> ConvertToBool,
|
|
|
|
"del"=> ConvertToBool,
|
|
|
|
"renamenx"=> ConvertToBool,
|
|
|
|
"expire"=> ConvertToBool,
|
|
|
|
"keys" => lambda{|r| r.split(" ")},
|
|
|
|
"info" => lambda{|r|
|
|
|
|
info = {}
|
|
|
|
r.each_line {|kv|
|
|
|
|
k,v = kv.split(':', 2)
|
|
|
|
k,v = k.chomp, v = v.chomp
|
|
|
|
info[k.to_sym] = v
|
|
|
|
}
|
|
|
|
info
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-20 10:36:12 -04:00
|
|
|
def initialize(opts={})
|
|
|
|
opts = {:host => 'localhost', :port => '6379', :db => 0}.merge(opts)
|
|
|
|
@host = opts[:host]
|
|
|
|
@port = opts[:port]
|
|
|
|
@db = opts[:db]
|
2009-05-20 11:52:47 -04:00
|
|
|
connect_to_server
|
2009-05-20 10:36:12 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def to_s
|
|
|
|
"Redis Client connected to #{@host}:#{@port} against DB #{@db}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def connect_to_server
|
2009-05-20 11:52:47 -04:00
|
|
|
@sock = TCPSocket.new(@host, @port, 0)
|
|
|
|
call_command(["select",@db]) if @db != 0
|
2009-05-20 10:36:12 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def method_missing(*argv)
|
|
|
|
call_command(argv)
|
|
|
|
end
|
|
|
|
|
|
|
|
def call_command(argv)
|
2009-05-20 11:52:47 -04:00
|
|
|
# this wrapper to raw_call_command handle reconnection on socket
|
|
|
|
# error. We try to reconnect just one time, otherwise let the error
|
|
|
|
# araise.
|
|
|
|
begin
|
|
|
|
raw_call_command(argv)
|
|
|
|
rescue Errno::ECONNRESET
|
|
|
|
@sock.close
|
|
|
|
connect_to_server
|
|
|
|
raw_call_command(argv)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def raw_call_command(argv)
|
2009-05-20 10:36:12 -04:00
|
|
|
bulk = nil
|
|
|
|
argv[0] = argv[0].to_s.downcase
|
|
|
|
if BulkCommands[argv[0]]
|
2009-05-21 07:22:20 -04:00
|
|
|
bulk = argv[-1].to_s
|
2009-05-20 10:36:12 -04:00
|
|
|
argv[-1] = bulk.length
|
|
|
|
end
|
|
|
|
@sock.write(argv.join(" ")+"\r\n")
|
|
|
|
@sock.write(bulk+"\r\n") if bulk
|
2009-05-21 07:22:20 -04:00
|
|
|
|
|
|
|
# Post process the reply if needed
|
|
|
|
processor = ReplyProcessor[argv[0]]
|
|
|
|
processor ? processor.call(read_reply) : read_reply
|
2009-05-20 10:36:12 -04:00
|
|
|
end
|
|
|
|
|
2009-05-20 11:22:29 -04:00
|
|
|
def select(*args)
|
|
|
|
raise "SELECT not allowed, use the :db option when creating the object"
|
|
|
|
end
|
|
|
|
|
2009-05-20 11:34:20 -04:00
|
|
|
def [](key)
|
|
|
|
get(key)
|
|
|
|
end
|
|
|
|
|
|
|
|
def []=(key,value)
|
|
|
|
set(key,value)
|
|
|
|
end
|
|
|
|
|
2009-05-20 10:36:12 -04:00
|
|
|
def read_reply
|
|
|
|
line = @sock.gets
|
2009-05-20 11:52:47 -04:00
|
|
|
raise Errno::ECONNRESET,"Connection lost" if !line
|
2009-05-20 10:36:12 -04:00
|
|
|
case line[0..0]
|
|
|
|
when "-"
|
|
|
|
raise line.strip
|
|
|
|
when "+"
|
|
|
|
line[1..-1].strip
|
|
|
|
when ":"
|
|
|
|
line[1..-1].to_i
|
|
|
|
when "$"
|
|
|
|
bulklen = line[1..-1].to_i
|
|
|
|
return nil if bulklen == -1
|
|
|
|
data = @sock.read(bulklen)
|
|
|
|
@sock.read(2) # CRLF
|
|
|
|
data
|
|
|
|
when "*"
|
|
|
|
objects = line[1..-1].to_i
|
|
|
|
return nil if bulklen == -1
|
|
|
|
res = []
|
|
|
|
objects.times {
|
|
|
|
res << read_reply
|
|
|
|
}
|
|
|
|
res
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|