ezmobius-redis-rb 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/redis.rb ADDED
@@ -0,0 +1,472 @@
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', :db => 0}.merge(opts)
23
+ $debug = @opts[:debug]
24
+ @db = @opts[:db]
25
+ @server = Server.new(@opts[:host], @opts[:port])
26
+ end
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
+
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
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
66
+ end
67
+ end
68
+
69
+ def quit
70
+ write "QUIT\r\n"
71
+ end
72
+
73
+ def select_db(index)
74
+ @db = index
75
+ write "SELECT #{index}\r\n"
76
+ get_response
77
+ end
78
+
79
+ def flush_db
80
+ write "FLUSHDB\r\n"
81
+ get_response == OK
82
+ end
83
+
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
+
94
+ def last_save
95
+ write "LASTSAVE\r\n"
96
+ get_response.to_i
97
+ end
98
+
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
108
+ x.each do |kv|
109
+ k,v = kv.split(':', 2)
110
+ k,v = k.chomp, v = v.chomp
111
+ info[k.to_sym] = v
112
+ end
113
+ info
114
+ end
115
+
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
126
+ end
127
+
128
+ def write(data)
129
+ with_socket_management(@server) do |socket|
130
+ puts "writing: #{data}" if $debug
131
+ socket.write(data)
132
+ end
133
+ end
134
+
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
150
+ end
151
+
152
+ def keys(glob)
153
+ write "KEYS #{glob}\r\n"
154
+ get_response.split(' ')
155
+ end
156
+
157
+ def rename!(oldkey, newkey)
158
+ write "RENAME #{oldkey} #{newkey}\r\n"
159
+ get_response
160
+ end
161
+
162
+ def rename(oldkey, newkey)
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
175
+
176
+ def key?(key)
177
+ write "EXISTS #{key}\r\n"
178
+ get_response == 1
179
+ end
180
+
181
+ def delete(key)
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
193
+ end
194
+
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
211
+ write "DECRBY #{key} #{decrement}\r\n"
212
+ else
213
+ write "DECR #{key}\r\n"
214
+ end
215
+ get_response
216
+ end
217
+
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
+
233
+ def type?(key)
234
+ write "TYPE #{key}\r\n"
235
+ get_response
236
+ end
237
+
238
+ def push_tail(key, string)
239
+ write "RPUSH #{key} #{string.to_s.size}\r\n#{string.to_s}\r\n"
240
+ get_response
241
+ end
242
+
243
+ def push_head(key, string)
244
+ write "LPUSH #{key} #{string.to_s.size}\r\n#{string.to_s}\r\n"
245
+ get_response
246
+ end
247
+
248
+ def pop_head(key)
249
+ write "LPOP #{key}\r\n"
250
+ get_response
251
+ end
252
+
253
+ def pop_tail(key)
254
+ write "RPOP #{key}\r\n"
255
+ get_response
256
+ end
257
+
258
+ def list_set(key, index, val)
259
+ write "LSET #{key} #{index} #{val.to_s.size}\r\n#{val}\r\n"
260
+ get_response == OK
261
+ end
262
+
263
+ def list_length(key)
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
271
+ end
272
+
273
+ def list_range(key, start, ending)
274
+ write "LRANGE #{key} #{start} #{ending}\r\n"
275
+ get_response
276
+ end
277
+
278
+ def list_trim(key, start, ending)
279
+ write "LTRIM #{key} #{start} #{ending}\r\n"
280
+ get_response
281
+ end
282
+
283
+ def list_index(key, index)
284
+ write "LINDEX #{key} #{index}\r\n"
285
+ get_response
286
+ end
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
+
300
+ def set_add(key, member)
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
310
+ end
311
+
312
+ def set_delete(key, member)
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
322
+ end
323
+
324
+ def set_count(key)
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
332
+ end
333
+
334
+ def set_member?(key, member)
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
344
+ end
345
+
346
+ def set_members(key)
347
+ write "SMEMBERS #{key}\r\n"
348
+ Set.new(get_response)
349
+ end
350
+
351
+ def set_intersect(*keys)
352
+ write "SINTER #{keys.join(' ')}\r\n"
353
+ Set.new(get_response)
354
+ end
355
+
356
+ def set_inter_store(destkey, *keys)
357
+ write "SINTERSTORE #{destkey} #{keys.join(' ')}\r\n"
358
+ get_response
359
+ end
360
+
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"
371
+ write(cmd)
372
+ get_response
373
+ end
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
384
+ end
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
394
+ end
395
+ r
396
+ end
397
+
398
+ def []=(key, val)
399
+ set(key,val)
400
+ end
401
+
402
+
403
+ def set(key, val, expiry=nil)
404
+ write("SET #{key} #{val.to_s.size}\r\n#{val}\r\n")
405
+ get_response == OK
406
+ end
407
+
408
+ def set_unless_exists(key, val)
409
+ write "SETNX #{key} #{val.to_s.size}\r\n#{val}\r\n"
410
+ get_response == 1
411
+ end
412
+
413
+ def status_code_reply
414
+ begin
415
+ res = read_proto
416
+ if res.index('-') == 0
417
+ raise RedisError, res
418
+ else
419
+ true
420
+ end
421
+ rescue RedisError
422
+ raise RedisError
423
+ end
424
+ end
425
+
426
+ def get_response
427
+ begin
428
+ rtype = get_reply
429
+ rescue => e
430
+ raise RedisError, e.inspect
431
+ end
432
+ puts "reply_type is #{rtype.inspect}" if $debug
433
+ case rtype
434
+ when SINGLE
435
+ single_line
436
+ when BULK
437
+ bulk_reply
438
+ when MULTI
439
+ multi_bulk
440
+ when INT
441
+ integer_reply
442
+ when ERR
443
+ raise RedisError, single_line
444
+ else
445
+ raise RedisError, "Unknown response.."
446
+ end
447
+ end
448
+
449
+ def integer_reply
450
+ Integer(read_proto)
451
+ end
452
+
453
+ def single_line
454
+ buff = ""
455
+ while buff[-2..-1] != "\r\n"
456
+ buff << read(1)
457
+ end
458
+ puts "single_line value is #{buff[0..-3].inspect}" if $debug
459
+ buff[0..-3]
460
+ end
461
+
462
+ def read_proto
463
+ with_socket_management(@server) do |socket|
464
+ if res = socket.gets
465
+ x = res.chomp
466
+ puts "read_proto is #{x.inspect}\n\n" if $debug
467
+ x.to_i
468
+ end
469
+ end
470
+ end
471
+
472
+ end