]> git.saurik.com Git - redis.git/blame - client-libraries/ruby/lib/redis.rb
Ruby client updated
[redis.git] / client-libraries / ruby / lib / redis.rb
CommitLineData
ed9b544e 1require 'socket'
ed9b544e 2require 'set'
29fac617 3require File.join(File.dirname(__FILE__),'server')
4
ed9b544e 5
6class RedisError < StandardError
7end
29fac617 8class RedisRenameError < StandardError
9end
ed9b544e 10class Redis
29fac617 11 ERR = "-".freeze
12 OK = 'OK'.freeze
13 SINGLE = '+'.freeze
14 BULK = '$'.freeze
15 MULTI = '*'.freeze
16 INT = ':'.freeze
17
18 attr_reader :server
19
20
21 def initialize(opts={})
9495122b 22 @opts = {:host => 'localhost', :port => '6379', :db => 0}.merge(opts)
29fac617 23 $debug = @opts[:debug]
9495122b 24 @db = @opts[:db]
29fac617 25 @server = Server.new(@opts[:host], @opts[:port])
26 end
ed9b544e 27
28 def to_s
29 "#{host}:#{port}"
30 end
31
32 def port
33 @opts[:port]
34 end
35
36 def host
37 @opts[:host]
38 end
39
29fac617 40 def with_socket_management(server, &block)
41 begin
42 block.call(server.socket)
43 #Timeout or server down
44 rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNREFUSED => e
45 server.close
46 puts "Client (#{server.inspect}) disconnected from server: #{e.inspect}\n" if $debug
47 retry
48 #Server down
49 rescue NoMethodError => e
50 puts "Client (#{server.inspect}) tryin server that is down: #{e.inspect}\n Dying!" if $debug
9495122b 51 raise Errno::ECONNREFUSED
52 #exit
53 end
54 end
55
56 def monitor
57 with_socket_management(@server) do |socket|
58 trap("INT") { puts "\nGot ^C! Dying!"; exit }
59 write "MONITOR\r\n"
60 puts "Now Monitoring..."
61 socket.read(12)
62 loop do
63 x = socket.gets
64 puts x unless x.nil?
65 end
29fac617 66 end
67 end
68
69 def quit
70 write "QUIT\r\n"
ed9b544e 71 end
72
29fac617 73 def select_db(index)
9495122b 74 @db = index
29fac617 75 write "SELECT #{index}\r\n"
76 get_response
ed9b544e 77 end
78
29fac617 79 def flush_db
80 write "FLUSHDB\r\n"
81 get_response == OK
82 end
83
9495122b 84 def flush_all
85 ensure_retry do
86 puts "Warning!\nFlushing *ALL* databases!\n5 Seconds to Hit ^C!"
87 trap('INT') {quit; return false}
88 sleep 5
89 write "FLUSHALL\r\n"
90 get_response == OK
91 end
92 end
93
29fac617 94 def last_save
95 write "LASTSAVE\r\n"
96 get_response.to_i
ed9b544e 97 end
98
29fac617 99 def bgsave
100 write "BGSAVE\r\n"
101 get_response == OK
102 end
103
104 def info
105 info = {}
106 write("INFO\r\n")
107 x = get_response
9495122b 108 x.each do |kv|
29fac617 109 k,v = kv.split(':', 2)
110 k,v = k.chomp, v = v.chomp
111 info[k.to_sym] = v
112 end
113 info
ed9b544e 114 end
115
29fac617 116
117 def bulk_reply
118 begin
119 x = read.chomp
120 puts "bulk_reply read value is #{x.inspect}" if $debug
121 return x
122 rescue => e
123 puts "error in bulk_reply #{e}" if $debug
124 nil
125 end
ed9b544e 126 end
ed9b544e 127
29fac617 128 def write(data)
129 with_socket_management(@server) do |socket|
130 puts "writing: #{data}" if $debug
131 socket.write(data)
132 end
ed9b544e 133 end
134
29fac617 135 def fetch(len)
136 with_socket_management(@server) do |socket|
137 len = [0, len.to_i].max
138 res = socket.read(len + 2)
139 res = res.chomp if res
140 res
141 end
142 end
143
144 def read(length = read_proto)
145 with_socket_management(@server) do |socket|
146 res = socket.read(length)
147 puts "read is #{res.inspect}" if $debug
148 res
149 end
ed9b544e 150 end
151
29fac617 152 def keys(glob)
153 write "KEYS #{glob}\r\n"
154 get_response.split(' ')
ed9b544e 155 end
29fac617 156
157 def rename!(oldkey, newkey)
158 write "RENAME #{oldkey} #{newkey}\r\n"
159 get_response
160 end
ed9b544e 161
ed9b544e 162 def rename(oldkey, newkey)
29fac617 163 write "RENAMENX #{oldkey} #{newkey}\r\n"
164 case get_response
165 when -1
166 raise RedisRenameError, "source key: #{oldkey} does not exist"
167 when 0
168 raise RedisRenameError, "target key: #{oldkey} already exists"
169 when -3
170 raise RedisRenameError, "source and destination keys are the same"
171 when 1
172 true
173 end
174 end
ed9b544e 175
ed9b544e 176 def key?(key)
29fac617 177 write "EXISTS #{key}\r\n"
178 get_response == 1
179 end
ed9b544e 180
ed9b544e 181 def delete(key)
29fac617 182 write "DEL #{key}\r\n"
183 get_response == 1
184 end
185
186 def [](key)
187 get(key)
188 end
189
190 def get(key)
191 write "GET #{key}\r\n"
192 get_response
ed9b544e 193 end
194
29fac617 195 def mget(*keys)
196 write "MGET #{keys.join(' ')}\r\n"
197 get_response
198 end
199
200 def incr(key, increment=nil)
201 if increment
202 write "INCRBY #{key} #{increment}\r\n"
203 else
204 write "INCR #{key}\r\n"
205 end
206 get_response
207 end
208
209 def decr(key, decrement=nil)
210 if decrement
9495122b 211 write "DECRBY #{key} #{decrement}\r\n"
29fac617 212 else
213 write "DECR #{key}\r\n"
214 end
215 get_response
ed9b544e 216 end
217
29fac617 218 def randkey
219 write "RANDOMKEY\r\n"
220 get_response
221 end
222
223 def list_length(key)
224 write "LLEN #{key}\r\n"
225 case i = get_response
226 when -2
227 raise RedisError, "key: #{key} does not hold a list value"
228 else
229 i
230 end
231 end
232
ed9b544e 233 def type?(key)
29fac617 234 write "TYPE #{key}\r\n"
235 get_response
ed9b544e 236 end
237
ed9b544e 238 def push_tail(key, string)
29fac617 239 write "RPUSH #{key} #{string.to_s.size}\r\n#{string.to_s}\r\n"
240 get_response
241 end
242
ed9b544e 243 def push_head(key, string)
29fac617 244 write "LPUSH #{key} #{string.to_s.size}\r\n#{string.to_s}\r\n"
245 get_response
ed9b544e 246 end
247
ed9b544e 248 def pop_head(key)
29fac617 249 write "LPOP #{key}\r\n"
250 get_response
ed9b544e 251 end
29fac617 252
ed9b544e 253 def pop_tail(key)
29fac617 254 write "RPOP #{key}\r\n"
255 get_response
256 end
257
ed9b544e 258 def list_set(key, index, val)
29fac617 259 write "LSET #{key} #{index} #{val.to_s.size}\r\n#{val}\r\n"
260 get_response == OK
ed9b544e 261 end
29fac617 262
ed9b544e 263 def list_length(key)
29fac617 264 write "LLEN #{key}\r\n"
265 case i = get_response
266 when -2
267 raise RedisError, "key: #{key} does not hold a list value"
268 else
269 i
270 end
ed9b544e 271 end
29fac617 272
ed9b544e 273 def list_range(key, start, ending)
29fac617 274 write "LRANGE #{key} #{start} #{ending}\r\n"
275 get_response
ed9b544e 276 end
277
ed9b544e 278 def list_trim(key, start, ending)
29fac617 279 write "LTRIM #{key} #{start} #{ending}\r\n"
280 get_response
ed9b544e 281 end
29fac617 282
ed9b544e 283 def list_index(key, index)
29fac617 284 write "LINDEX #{key} #{index}\r\n"
285 get_response
ed9b544e 286 end
29fac617 287
288 def list_rm(key, count, value)
289 write "LREM #{key} #{count} #{value.to_s.size}\r\n#{value}\r\n"
290 case num = get_response
291 when -1
292 raise RedisError, "key: #{key} does not exist"
293 when -2
294 raise RedisError, "key: #{key} does not hold a list value"
295 else
296 num
297 end
298 end
299
ed9b544e 300 def set_add(key, member)
29fac617 301 write "SADD #{key} #{member.to_s.size}\r\n#{member}\r\n"
302 case get_response
303 when 1
304 true
305 when 0
306 false
307 when -2
308 raise RedisError, "key: #{key} contains a non set value"
309 end
ed9b544e 310 end
29fac617 311
ed9b544e 312 def set_delete(key, member)
29fac617 313 write "SREM #{key} #{member.to_s.size}\r\n#{member}\r\n"
314 case get_response
315 when 1
316 true
317 when 0
318 false
319 when -2
320 raise RedisError, "key: #{key} contains a non set value"
321 end
ed9b544e 322 end
29fac617 323
ed9b544e 324 def set_count(key)
29fac617 325 write "SCARD #{key}\r\n"
326 case i = get_response
327 when -2
328 raise RedisError, "key: #{key} contains a non set value"
329 else
330 i
331 end
ed9b544e 332 end
29fac617 333
ed9b544e 334 def set_member?(key, member)
29fac617 335 write "SISMEMBER #{key} #{member.to_s.size}\r\n#{member}\r\n"
336 case get_response
337 when 1
338 true
339 when 0
340 false
341 when -2
342 raise RedisError, "key: #{key} contains a non set value"
343 end
ed9b544e 344 end
29fac617 345
346 def set_members(key)
347 write "SMEMBERS #{key}\r\n"
348 Set.new(get_response)
349 end
350
ed9b544e 351 def set_intersect(*keys)
29fac617 352 write "SINTER #{keys.join(' ')}\r\n"
353 Set.new(get_response)
ed9b544e 354 end
29fac617 355
ed9b544e 356 def set_inter_store(destkey, *keys)
29fac617 357 write "SINTERSTORE #{destkey} #{keys.join(' ')}\r\n"
358 get_response
ed9b544e 359 end
29fac617 360
ed9b544e 361 def sort(key, opts={})
362 cmd = "SORT #{key}"
363 cmd << " BY #{opts[:by]}" if opts[:by]
364 cmd << " GET #{opts[:get]}" if opts[:get]
365 cmd << " INCR #{opts[:incr]}" if opts[:incr]
366 cmd << " DEL #{opts[:del]}" if opts[:del]
367 cmd << " DECR #{opts[:decr]}" if opts[:decr]
368 cmd << " #{opts[:order]}" if opts[:order]
369 cmd << " LIMIT #{opts[:limit].join(' ')}" if opts[:limit]
370 cmd << "\r\n"
29fac617 371 write(cmd)
372 get_response
ed9b544e 373 end
29fac617 374
375 def multi_bulk
376 res = read_proto
377 puts "mb res is #{res.inspect}" if $debug
378 list = []
379 Integer(res).times do
380 vf = get_response
381 puts "curren vf is #{vf.inspect}" if $debug
382 list << vf
383 puts "current list is #{list.inspect}" if $debug
ed9b544e 384 end
29fac617 385 list
386 end
387
388 def get_reply
389 begin
390 r = read(1)
391 raise RedisError if (r == "\r" || r == "\n")
392 rescue RedisError
393 retry
ed9b544e 394 end
29fac617 395 r
ed9b544e 396 end
29fac617 397
398 def []=(key, val)
399 set(key,val)
ed9b544e 400 end
401
29fac617 402
403 def set(key, val, expiry=nil)
404 write("SET #{key} #{val.to_s.size}\r\n#{val}\r\n")
9495122b 405 s = get_response == OK
406 return expire(key, expiry) if s && expiry
407 s
408 end
409
410 def expire(key, expiry=nil)
411 write("EXPIRE #{key} #{expiry}\r\n")
412 get_response == 1
ed9b544e 413 end
29fac617 414
415 def set_unless_exists(key, val)
416 write "SETNX #{key} #{val.to_s.size}\r\n#{val}\r\n"
417 get_response == 1
418 end
ed9b544e 419
29fac617 420 def status_code_reply
421 begin
422 res = read_proto
423 if res.index('-') == 0
424 raise RedisError, res
425 else
426 true
427 end
428 rescue RedisError
429 raise RedisError
ed9b544e 430 end
431 end
432
29fac617 433 def get_response
434 begin
435 rtype = get_reply
436 rescue => e
437 raise RedisError, e.inspect
438 end
439 puts "reply_type is #{rtype.inspect}" if $debug
440 case rtype
441 when SINGLE
442 single_line
443 when BULK
444 bulk_reply
445 when MULTI
446 multi_bulk
447 when INT
448 integer_reply
449 when ERR
450 raise RedisError, single_line
451 else
452 raise RedisError, "Unknown response.."
ed9b544e 453 end
454 end
455
29fac617 456 def integer_reply
457 Integer(read_proto)
ed9b544e 458 end
459
29fac617 460 def single_line
ed9b544e 461 buff = ""
29fac617 462 while buff[-2..-1] != "\r\n"
463 buff << read(1)
ed9b544e 464 end
29fac617 465 puts "single_line value is #{buff[0..-3].inspect}" if $debug
ed9b544e 466 buff[0..-3]
467 end
468
29fac617 469 def read_proto
470 with_socket_management(@server) do |socket|
471 if res = socket.gets
472 x = res.chomp
473 puts "read_proto is #{x.inspect}\n\n" if $debug
474 x.to_i
475 end
ed9b544e 476 end
477 end
478
27dd1526 479end