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