ezmobius-redis-rb 0.0.3

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/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