1 # Tcl clinet library - used by test-redis.tcl script for now
2 # Copyright (C) 2009 Salvatore Sanfilippo
3 # Released under the BSD license like Redis itself
7 # set r [redis 127.0.0.1 6379]
10 # $r lrange mylist 0 -1
13 package provide redis
0.1
15 namespace eval redis
{}
17 array set ::redis::fd {}
18 array set ::redis::bulkarg {}
19 array set ::redis::multibulkarg {}
21 # Flag commands requiring last argument as a bulk write operation
22 foreach redis_bulk_cmd
{
23 set setnx rpush lpush
lset lrem sadd srem sismember echo getset smove zadd zrem zscore
25 set ::redis::bulkarg($redis_bulk_cmd) {}
28 # Flag commands requiring last argument as a bulk write operation
29 foreach redis_multibulk_cmd
{
32 set ::redis::multibulkarg($redis_multibulk_cmd) {}
36 unset redis_multibulk_cmd
38 proc redis
{{server
127.0.0.1} {port
6379}} {
39 set fd
[socket $server $port]
40 fconfigure $fd -translation binary
41 set id
[incr ::redis::id]
42 set ::redis::fd($id) $fd
43 interp alias
{} ::redis::redisHandle$id {} ::redis::__dispatch__ $id
46 proc ::redis::__dispatch__ {id method args
} {
47 set fd
$::redis::fd($id)
48 if {[info command
::redis::__method__$method] eq
{}} {
49 if {[info exists
::redis::bulkarg($method)]} {
51 append cmd
[join [lrange $args 0 end-1
]]
52 append cmd
" [string length [lindex $args end]]\r\n"
53 append cmd
[lindex $args end
]
54 ::redis::redis_writenl $fd $cmd
55 } elseif
{[info exists
::redis::multibulkarg($method)]} {
56 set cmd
"*[expr {[llength $args]+1}]\r\n"
57 append cmd
"$[string length $method]\r\n$method\r\n"
59 append cmd
"$[string length $a]\r\n$a\r\n"
61 ::redis::redis_write $fd $cmd
65 append cmd
[join $args]
66 ::redis::redis_writenl $fd $cmd
68 ::redis::redis_read_reply $fd
70 uplevel 1 [list ::redis::__method__$method $id $fd] $args
74 proc ::redis::__method__close {id fd
} {
76 catch {unset ::redis::fd($id)}
77 catch {interp alias
{} ::redis::redisHandle$id {}}
80 proc ::redis::__method__channel {id fd
} {
84 proc ::redis::redis_write {fd buf
} {
85 puts -nonewline $fd $buf
88 proc ::redis::redis_writenl {fd buf
} {
90 redis_write
$fd "\r\n"
94 proc ::redis::redis_readnl {fd len
} {
95 set buf
[read $fd $len]
96 read $fd 2 ; # discard CR LF
100 proc ::redis::redis_bulk_read {fd
} {
101 set count
[redis_read_line
$fd]
102 if {$count == -1} return {}
103 set buf
[redis_readnl
$fd $count]
107 proc ::redis::redis_multi_bulk_read fd
{
108 set count
[redis_read_line
$fd]
109 if {$count == -1} return {}
111 for {set i
0} {$i < $count} {incr i
} {
112 lappend l
[redis_read_reply
$fd]
117 proc ::redis::redis_read_line fd
{
118 string trim
[gets $fd]
121 proc ::redis::redis_read_reply fd
{
122 set type
[read $fd 1]
123 switch -exact -- $type {
125 + {redis_read_line
$fd}
126 - {return -code error [redis_read_line
$fd]}
127 $ {redis_bulk_read
$fd}
128 * {redis_multi_bulk_read
$fd}
129 default {return -code error "Bad protocol, $type as reply type byte"}