Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
G
go-ipfs
概览
概览
详情
活动
周期分析
版本库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
jihao
go-ipfs
Commits
8f62ac82
提交
8f62ac82
authored
2月 06, 2015
作者:
Brian Tiger Chow
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
vendor: fzzy/radix/redis
上级
de34261b
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
8 个修改的文件
包含
1051 行增加
和
0 行删除
+1051
-0
Godeps.json
Godeps/Godeps.json
+5
-0
client.go
Godeps/_workspace/src/github.com/fzzy/radix/redis/client.go
+244
-0
client_test.go
..._workspace/src/github.com/fzzy/radix/redis/client_test.go
+106
-0
doc.go
Godeps/_workspace/src/github.com/fzzy/radix/redis/doc.go
+87
-0
reply.go
Godeps/_workspace/src/github.com/fzzy/radix/redis/reply.go
+275
-0
reply_test.go
.../_workspace/src/github.com/fzzy/radix/redis/reply_test.go
+125
-0
resp.go
...s/_workspace/src/github.com/fzzy/radix/redis/resp/resp.go
+0
-0
resp_test.go
...rkspace/src/github.com/fzzy/radix/redis/resp/resp_test.go
+209
-0
没有找到文件。
Godeps/Godeps.json
浏览文件 @
8f62ac82
...
...
@@ -109,6 +109,11 @@
"Rev"
:
"50e7633d5f27d81490026a13e5b92d2e42d8c6bb"
},
{
"ImportPath"
:
"github.com/fzzy/radix/redis"
,
"Comment"
:
"v0.5.1"
,
"Rev"
:
"27a863cdffdb0998d13e1e11992b18489aeeaa25"
},
{
"ImportPath"
:
"github.com/gorilla/context"
,
"Rev"
:
"14f550f51af52180c2eefed15e5fd18d63c0a64a"
},
...
...
Godeps/_workspace/src/github.com/fzzy/radix/redis/client.go
0 → 100644
浏览文件 @
8f62ac82
package
redis
import
(
"bufio"
"errors"
"net"
"strings"
"time"
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/fzzy/radix/redis/resp"
)
const
(
bufSize
int
=
4096
)
//* Common errors
var
LoadingError
error
=
errors
.
New
(
"server is busy loading dataset in memory"
)
var
PipelineQueueEmptyError
error
=
errors
.
New
(
"pipeline queue empty"
)
//* Client
// Client describes a Redis client.
type
Client
struct
{
// The connection the client talks to redis over. Don't touch this unless
// you know what you're doing.
Conn
net
.
Conn
timeout
time
.
Duration
reader
*
bufio
.
Reader
pending
[]
*
request
completed
[]
*
Reply
}
// request describes a client's request to the redis server
type
request
struct
{
cmd
string
args
[]
interface
{}
}
// Dial connects to the given Redis server with the given timeout, which will be
// used as the read/write timeout when communicating with redis
func
DialTimeout
(
network
,
addr
string
,
timeout
time
.
Duration
)
(
*
Client
,
error
)
{
// establish a connection
conn
,
err
:=
net
.
Dial
(
network
,
addr
)
if
err
!=
nil
{
return
nil
,
err
}
c
:=
new
(
Client
)
c
.
Conn
=
conn
c
.
timeout
=
timeout
c
.
reader
=
bufio
.
NewReaderSize
(
conn
,
bufSize
)
return
c
,
nil
}
// Dial connects to the given Redis server.
func
Dial
(
network
,
addr
string
)
(
*
Client
,
error
)
{
return
DialTimeout
(
network
,
addr
,
time
.
Duration
(
0
))
}
//* Public methods
// Close closes the connection.
func
(
c
*
Client
)
Close
()
error
{
return
c
.
Conn
.
Close
()
}
// Cmd calls the given Redis command.
func
(
c
*
Client
)
Cmd
(
cmd
string
,
args
...
interface
{})
*
Reply
{
err
:=
c
.
writeRequest
(
&
request
{
cmd
,
args
})
if
err
!=
nil
{
return
&
Reply
{
Type
:
ErrorReply
,
Err
:
err
}
}
return
c
.
ReadReply
()
}
// Append adds the given call to the pipeline queue.
// Use GetReply() to read the reply.
func
(
c
*
Client
)
Append
(
cmd
string
,
args
...
interface
{})
{
c
.
pending
=
append
(
c
.
pending
,
&
request
{
cmd
,
args
})
}
// GetReply returns the reply for the next request in the pipeline queue.
// Error reply with PipelineQueueEmptyError is returned,
// if the pipeline queue is empty.
func
(
c
*
Client
)
GetReply
()
*
Reply
{
if
len
(
c
.
completed
)
>
0
{
r
:=
c
.
completed
[
0
]
c
.
completed
=
c
.
completed
[
1
:
]
return
r
}
c
.
completed
=
nil
if
len
(
c
.
pending
)
==
0
{
return
&
Reply
{
Type
:
ErrorReply
,
Err
:
PipelineQueueEmptyError
}
}
nreqs
:=
len
(
c
.
pending
)
err
:=
c
.
writeRequest
(
c
.
pending
...
)
c
.
pending
=
nil
if
err
!=
nil
{
return
&
Reply
{
Type
:
ErrorReply
,
Err
:
err
}
}
r
:=
c
.
ReadReply
()
c
.
completed
=
make
([]
*
Reply
,
nreqs
-
1
)
for
i
:=
0
;
i
<
nreqs
-
1
;
i
++
{
c
.
completed
[
i
]
=
c
.
ReadReply
()
}
return
r
}
//* Private methods
func
(
c
*
Client
)
setReadTimeout
()
{
if
c
.
timeout
!=
0
{
c
.
Conn
.
SetReadDeadline
(
time
.
Now
()
.
Add
(
c
.
timeout
))
}
}
func
(
c
*
Client
)
setWriteTimeout
()
{
if
c
.
timeout
!=
0
{
c
.
Conn
.
SetWriteDeadline
(
time
.
Now
()
.
Add
(
c
.
timeout
))
}
}
// This will read a redis reply off of the connection without sending anything
// first (useful after you've sent a SUSBSCRIBE command). This will block until
// a reply is received or the timeout is reached. On timeout an ErrorReply will
// be returned, you can check if it's a timeout like so:
//
// r := conn.ReadReply()
// if r.Err != nil {
// if t, ok := r.Err.(*net.OpError); ok && t.Timeout() {
// // Is timeout
// } else {
// // Not timeout
// }
// }
//
// Note: this is a more low-level function, you really shouldn't have to
// actually use it unless you're writing your own pub/sub code
func
(
c
*
Client
)
ReadReply
()
*
Reply
{
c
.
setReadTimeout
()
return
c
.
parse
()
}
func
(
c
*
Client
)
writeRequest
(
requests
...*
request
)
error
{
c
.
setWriteTimeout
()
for
i
:=
range
requests
{
req
:=
make
([]
interface
{},
0
,
len
(
requests
[
i
]
.
args
)
+
1
)
req
=
append
(
req
,
requests
[
i
]
.
cmd
)
req
=
append
(
req
,
requests
[
i
]
.
args
...
)
err
:=
resp
.
WriteArbitraryAsFlattenedStrings
(
c
.
Conn
,
req
)
if
err
!=
nil
{
c
.
Close
()
return
err
}
}
return
nil
}
func
(
c
*
Client
)
parse
()
*
Reply
{
m
,
err
:=
resp
.
ReadMessage
(
c
.
reader
)
if
err
!=
nil
{
if
t
,
ok
:=
err
.
(
*
net
.
OpError
);
!
ok
||
!
t
.
Timeout
()
{
// close connection except timeout
c
.
Close
()
}
return
&
Reply
{
Type
:
ErrorReply
,
Err
:
err
}
}
r
,
err
:=
messageToReply
(
m
)
if
err
!=
nil
{
return
&
Reply
{
Type
:
ErrorReply
,
Err
:
err
}
}
return
r
}
// The error return parameter is for bubbling up parse errors and the like, if
// the error is sent by redis itself as an Err message type, then it will be
// sent back as an actual Reply (wrapped in a CmdError)
func
messageToReply
(
m
*
resp
.
Message
)
(
*
Reply
,
error
)
{
r
:=
&
Reply
{}
switch
m
.
Type
{
case
resp
.
Err
:
errMsg
,
err
:=
m
.
Err
()
if
err
!=
nil
{
return
nil
,
err
}
if
strings
.
HasPrefix
(
errMsg
.
Error
(),
"LOADING"
)
{
err
=
LoadingError
}
else
{
err
=
&
CmdError
{
errMsg
}
}
r
.
Type
=
ErrorReply
r
.
Err
=
err
case
resp
.
SimpleStr
:
status
,
err
:=
m
.
Bytes
()
if
err
!=
nil
{
return
nil
,
err
}
r
.
Type
=
StatusReply
r
.
buf
=
status
case
resp
.
Int
:
i
,
err
:=
m
.
Int
()
if
err
!=
nil
{
return
nil
,
err
}
r
.
Type
=
IntegerReply
r
.
int
=
i
case
resp
.
BulkStr
:
b
,
err
:=
m
.
Bytes
()
if
err
!=
nil
{
return
nil
,
err
}
r
.
Type
=
BulkReply
r
.
buf
=
b
case
resp
.
Nil
:
r
.
Type
=
NilReply
case
resp
.
Array
:
ms
,
err
:=
m
.
Array
()
if
err
!=
nil
{
return
nil
,
err
}
r
.
Type
=
MultiReply
r
.
Elems
=
make
([]
*
Reply
,
len
(
ms
))
for
i
:=
range
ms
{
r
.
Elems
[
i
],
err
=
messageToReply
(
ms
[
i
])
if
err
!=
nil
{
return
nil
,
err
}
}
}
return
r
,
nil
}
Godeps/_workspace/src/github.com/fzzy/radix/redis/client_test.go
0 → 100644
浏览文件 @
8f62ac82
package
redis
import
(
"bufio"
"bytes"
"github.com/stretchr/testify/assert"
.
"testing"
"time"
)
func
dial
(
t
*
T
)
*
Client
{
client
,
err
:=
DialTimeout
(
"tcp"
,
"127.0.0.1:6379"
,
10
*
time
.
Second
)
assert
.
Nil
(
t
,
err
)
return
client
}
func
TestCmd
(
t
*
T
)
{
c
:=
dial
(
t
)
v
,
_
:=
c
.
Cmd
(
"echo"
,
"Hello, World!"
)
.
Str
()
assert
.
Equal
(
t
,
"Hello, World!"
,
v
)
// Test that a bad command properly returns a *CmdError
err
:=
c
.
Cmd
(
"non-existant-cmd"
)
.
Err
assert
.
NotEqual
(
t
,
""
,
err
.
(
*
CmdError
)
.
Error
())
// Test that application level errors propagate correctly
c
.
Cmd
(
"sadd"
,
"foo"
,
"bar"
)
_
,
err
=
c
.
Cmd
(
"get"
,
"foo"
)
.
Str
()
assert
.
NotEqual
(
t
,
""
,
err
.
(
*
CmdError
)
.
Error
())
}
func
TestPipeline
(
t
*
T
)
{
c
:=
dial
(
t
)
c
.
Append
(
"echo"
,
"foo"
)
c
.
Append
(
"echo"
,
"bar"
)
c
.
Append
(
"echo"
,
"zot"
)
v
,
_
:=
c
.
GetReply
()
.
Str
()
assert
.
Equal
(
t
,
"foo"
,
v
)
v
,
_
=
c
.
GetReply
()
.
Str
()
assert
.
Equal
(
t
,
"bar"
,
v
)
v
,
_
=
c
.
GetReply
()
.
Str
()
assert
.
Equal
(
t
,
"zot"
,
v
)
r
:=
c
.
GetReply
()
assert
.
Equal
(
t
,
ErrorReply
,
r
.
Type
)
assert
.
Equal
(
t
,
PipelineQueueEmptyError
,
r
.
Err
)
}
func
TestParse
(
t
*
T
)
{
c
:=
dial
(
t
)
parseString
:=
func
(
b
string
)
*
Reply
{
c
.
reader
=
bufio
.
NewReader
(
bytes
.
NewBufferString
(
b
))
return
c
.
parse
()
}
// missing \n trailing
r
:=
parseString
(
"foo"
)
assert
.
Equal
(
t
,
ErrorReply
,
r
.
Type
)
assert
.
NotNil
(
t
,
r
.
Err
)
// error reply
r
=
parseString
(
"-ERR unknown command 'foobar'
\r\n
"
)
assert
.
Equal
(
t
,
ErrorReply
,
r
.
Type
)
assert
.
Equal
(
t
,
"ERR unknown command 'foobar'"
,
r
.
Err
.
Error
())
// LOADING error
r
=
parseString
(
"-LOADING Redis is loading the dataset in memory
\r\n
"
)
assert
.
Equal
(
t
,
ErrorReply
,
r
.
Type
)
assert
.
Equal
(
t
,
LoadingError
,
r
.
Err
)
// status reply
r
=
parseString
(
"+OK
\r\n
"
)
assert
.
Equal
(
t
,
StatusReply
,
r
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
"OK"
),
r
.
buf
)
// integer reply
r
=
parseString
(
":1337
\r\n
"
)
assert
.
Equal
(
t
,
IntegerReply
,
r
.
Type
)
assert
.
Equal
(
t
,
int64
(
1337
),
r
.
int
)
// null bulk reply
r
=
parseString
(
"$-1
\r\n
"
)
assert
.
Equal
(
t
,
NilReply
,
r
.
Type
)
// bulk reply
r
=
parseString
(
"$6
\r\n
foobar
\r\n
"
)
assert
.
Equal
(
t
,
BulkReply
,
r
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
"foobar"
),
r
.
buf
)
// null multi bulk reply
r
=
parseString
(
"*-1
\r\n
"
)
assert
.
Equal
(
t
,
NilReply
,
r
.
Type
)
// multi bulk reply
r
=
parseString
(
"*5
\r\n
:0
\r\n
:1
\r\n
:2
\r\n
:3
\r\n
$6
\r\n
foobar
\r\n
"
)
assert
.
Equal
(
t
,
MultiReply
,
r
.
Type
)
assert
.
Equal
(
t
,
5
,
len
(
r
.
Elems
))
for
i
:=
0
;
i
<
4
;
i
++
{
assert
.
Equal
(
t
,
int64
(
i
),
r
.
Elems
[
i
]
.
int
)
}
assert
.
Equal
(
t
,
[]
byte
(
"foobar"
),
r
.
Elems
[
4
]
.
buf
)
}
Godeps/_workspace/src/github.com/fzzy/radix/redis/doc.go
0 → 100644
浏览文件 @
8f62ac82
// A simple client for connecting and interacting with redis.
//
// To import inside your package do:
//
// import "github.com/fzzy/radix/redis"
//
// Connecting
//
// Use either Dial or DialTimeout:
//
// client, err := redis.Dial("tcp", "localhost:6379")
// if err != nil {
// // handle err
// }
//
// Make sure to call Close on the client if you want to clean it up before the
// end of the program.
//
// Cmd and Reply
//
// The Cmd method returns a Reply, which has methods for converting to various
// types. Each of these methods returns an error which can either be a
// connection error (e.g. timeout), an application error (e.g. key is wrong
// type), or a conversion error (e.g. cannot convert to integer). You can also
// directly check the error using the Err field:
//
// foo, err := client.Cmd("GET", "foo").Str()
// if err != nil {
// // handle err
// }
//
// // Checking Err field directly
//
// err = client.Cmd("PING").Err
// if err != nil {
// // handle err
// }
//
// Multi Replies
//
// The elements to Multi replies can be accessed as strings using List or
// ListBytes, or you can use the Elems field for more low-level access:
//
// r := client.Cmd("MGET", "foo", "bar", "baz")
//
// // This:
// for _, elemStr := range r.List() {
// fmt.Println(elemStr)
// }
//
// // is equivalent to this:
// for i := range r.Elems {
// elemStr, _ := r.Elems[i].Str()
// fmt.Println(elemStr)
// }
//
// Pipelining
//
// Pipelining is when the client sends a bunch of commands to the server at
// once, and only once all the commands have been sent does it start reading the
// replies off the socket. This is supported using the Append and GetReply
// methods. Append will simply append the command to a buffer without sending
// it, the first time GetReply is called it will send all the commands in the
// buffer and return the Reply for the first command that was sent. Subsequent
// calls to GetReply return Replys for subsequent commands:
//
// client.Append("GET", "foo")
// client.Append("SET", "bar", "foo")
// client.Append("DEL", "baz")
//
// // Read GET foo reply
// foo, err := client.GetReply().Str()
// if err != nil {
// // handle err
// }
//
// // Read SET bar foo reply
// if err := client.GetReply().Err; err != nil {
// // handle err
// }
//
// // Read DEL baz reply
// if err := client.GetReply().Err; err != nil {
// // handle err
// }
//
package
redis
Godeps/_workspace/src/github.com/fzzy/radix/redis/reply.go
0 → 100644
浏览文件 @
8f62ac82
package
redis
import
(
"errors"
"strconv"
"strings"
)
// A CmdError implements the error interface and is what is returned when the
// server returns an error on the application level (e.g. key doesn't exist or
// is the wrong type), as opposed to a connection/transport error.
//
// You can test if a reply is a CmdError like so:
//
// r := conn.Cmd("GET", "key-which-isnt-a-string")
// if r.Err != nil {
// if cerr, ok := r.Err.(*redis.CmdError); ok {
// // Is CmdError
// } else {
// // Is other error
// }
// }
type
CmdError
struct
{
Err
error
}
func
(
cerr
*
CmdError
)
Error
()
string
{
return
cerr
.
Err
.
Error
()
}
// Returns true if error returned was due to the redis server being read only
func
(
cerr
*
CmdError
)
Readonly
()
bool
{
return
strings
.
HasPrefix
(
cerr
.
Err
.
Error
(),
"READONLY"
)
}
//* Reply
/*
ReplyType describes type of a reply.
Possible values are:
StatusReply -- status reply
ErrorReply -- error reply
IntegerReply -- integer reply
NilReply -- nil reply
BulkReply -- bulk reply
MultiReply -- multi bulk reply
*/
type
ReplyType
uint8
const
(
StatusReply
ReplyType
=
iota
ErrorReply
IntegerReply
NilReply
BulkReply
MultiReply
)
// Reply holds a Redis reply.
type
Reply
struct
{
Type
ReplyType
// Reply type
Elems
[]
*
Reply
// Sub-replies
Err
error
// Reply error
buf
[]
byte
int
int64
}
// Bytes returns the reply value as a byte string or
// an error, if the reply type is not StatusReply or BulkReply.
func
(
r
*
Reply
)
Bytes
()
([]
byte
,
error
)
{
if
r
.
Type
==
ErrorReply
{
return
nil
,
r
.
Err
}
if
!
(
r
.
Type
==
StatusReply
||
r
.
Type
==
BulkReply
)
{
return
nil
,
errors
.
New
(
"string value is not available for this reply type"
)
}
return
r
.
buf
,
nil
}
// Str is a convenience method for calling Reply.Bytes() and converting it to string
func
(
r
*
Reply
)
Str
()
(
string
,
error
)
{
b
,
err
:=
r
.
Bytes
()
if
err
!=
nil
{
return
""
,
err
}
return
string
(
b
),
nil
}
// Int64 returns the reply value as a int64 or an error,
// if the reply type is not IntegerReply or the reply type
// BulkReply could not be parsed to an int64.
func
(
r
*
Reply
)
Int64
()
(
int64
,
error
)
{
if
r
.
Type
==
ErrorReply
{
return
0
,
r
.
Err
}
if
r
.
Type
!=
IntegerReply
{
s
,
err
:=
r
.
Str
()
if
err
==
nil
{
i64
,
err
:=
strconv
.
ParseInt
(
s
,
10
,
64
)
if
err
!=
nil
{
return
0
,
errors
.
New
(
"failed to parse integer value from string value"
)
}
else
{
return
i64
,
nil
}
}
return
0
,
errors
.
New
(
"integer value is not available for this reply type"
)
}
return
r
.
int
,
nil
}
// Int is a convenience method for calling Reply.Int64() and converting it to int.
func
(
r
*
Reply
)
Int
()
(
int
,
error
)
{
i64
,
err
:=
r
.
Int64
()
if
err
!=
nil
{
return
0
,
err
}
return
int
(
i64
),
nil
}
// Bool returns false, if the reply value equals to 0 or "0", otherwise true; or
// an error, if the reply type is not IntegerReply or BulkReply.
func
(
r
*
Reply
)
Bool
()
(
bool
,
error
)
{
if
r
.
Type
==
ErrorReply
{
return
false
,
r
.
Err
}
i
,
err
:=
r
.
Int
()
if
err
==
nil
{
if
i
==
0
{
return
false
,
nil
}
return
true
,
nil
}
s
,
err
:=
r
.
Str
()
if
err
==
nil
{
if
s
==
"0"
{
return
false
,
nil
}
return
true
,
nil
}
return
false
,
errors
.
New
(
"boolean value is not available for this reply type"
)
}
// List returns a multi bulk reply as a slice of strings or an error.
// The reply type must be MultiReply and its elements' types must all be either BulkReply or NilReply.
// Nil elements are returned as empty strings.
// Useful for list commands.
func
(
r
*
Reply
)
List
()
([]
string
,
error
)
{
// Doing all this in two places instead of just calling ListBytes() so we don't have
// to iterate twice
if
r
.
Type
==
ErrorReply
{
return
nil
,
r
.
Err
}
if
r
.
Type
!=
MultiReply
{
return
nil
,
errors
.
New
(
"reply type is not MultiReply"
)
}
strings
:=
make
([]
string
,
len
(
r
.
Elems
))
for
i
,
v
:=
range
r
.
Elems
{
if
v
.
Type
==
BulkReply
{
strings
[
i
]
=
string
(
v
.
buf
)
}
else
if
v
.
Type
==
NilReply
{
strings
[
i
]
=
""
}
else
{
return
nil
,
errors
.
New
(
"element type is not BulkReply or NilReply"
)
}
}
return
strings
,
nil
}
// ListBytes returns a multi bulk reply as a slice of bytes slices or an error.
// The reply type must be MultiReply and its elements' types must all be either BulkReply or NilReply.
// Nil elements are returned as nil.
// Useful for list commands.
func
(
r
*
Reply
)
ListBytes
()
([][]
byte
,
error
)
{
if
r
.
Type
==
ErrorReply
{
return
nil
,
r
.
Err
}
if
r
.
Type
!=
MultiReply
{
return
nil
,
errors
.
New
(
"reply type is not MultiReply"
)
}
bufs
:=
make
([][]
byte
,
len
(
r
.
Elems
))
for
i
,
v
:=
range
r
.
Elems
{
if
v
.
Type
==
BulkReply
{
bufs
[
i
]
=
v
.
buf
}
else
if
v
.
Type
==
NilReply
{
bufs
[
i
]
=
nil
}
else
{
return
nil
,
errors
.
New
(
"element type is not BulkReply or NilReply"
)
}
}
return
bufs
,
nil
}
// Hash returns a multi bulk reply as a map[string]string or an error.
// The reply type must be MultiReply,
// it must have an even number of elements,
// they must be in a "key value key value..." order and
// values must all be either BulkReply or NilReply.
// Nil values are returned as empty strings.
// Useful for hash commands.
func
(
r
*
Reply
)
Hash
()
(
map
[
string
]
string
,
error
)
{
if
r
.
Type
==
ErrorReply
{
return
nil
,
r
.
Err
}
rmap
:=
map
[
string
]
string
{}
if
r
.
Type
!=
MultiReply
{
return
nil
,
errors
.
New
(
"reply type is not MultiReply"
)
}
if
len
(
r
.
Elems
)
%
2
!=
0
{
return
nil
,
errors
.
New
(
"reply has odd number of elements"
)
}
for
i
:=
0
;
i
<
len
(
r
.
Elems
)
/
2
;
i
++
{
var
val
string
key
,
err
:=
r
.
Elems
[
i
*
2
]
.
Str
()
if
err
!=
nil
{
return
nil
,
errors
.
New
(
"key element has no string reply"
)
}
v
:=
r
.
Elems
[
i
*
2
+
1
]
if
v
.
Type
==
BulkReply
{
val
=
string
(
v
.
buf
)
rmap
[
key
]
=
val
}
else
if
v
.
Type
==
NilReply
{
}
else
{
return
nil
,
errors
.
New
(
"value element type is not BulkReply or NilReply"
)
}
}
return
rmap
,
nil
}
// String returns a string representation of the reply and its sub-replies.
// This method is for debugging.
// Use method Reply.Str() for reading string reply.
func
(
r
*
Reply
)
String
()
string
{
switch
r
.
Type
{
case
ErrorReply
:
return
r
.
Err
.
Error
()
case
StatusReply
:
fallthrough
case
BulkReply
:
return
string
(
r
.
buf
)
case
IntegerReply
:
return
strconv
.
FormatInt
(
r
.
int
,
10
)
case
NilReply
:
return
"<nil>"
case
MultiReply
:
s
:=
"[ "
for
_
,
e
:=
range
r
.
Elems
{
s
=
s
+
e
.
String
()
+
" "
}
return
s
+
"]"
}
// This should never execute
return
""
}
Godeps/_workspace/src/github.com/fzzy/radix/redis/reply_test.go
0 → 100644
浏览文件 @
8f62ac82
package
redis
import
(
"github.com/stretchr/testify/assert"
.
"testing"
)
func
TestStr
(
t
*
T
)
{
r
:=
&
Reply
{
Type
:
ErrorReply
,
Err
:
LoadingError
}
_
,
err
:=
r
.
Str
()
assert
.
Equal
(
t
,
LoadingError
,
err
)
r
=
&
Reply
{
Type
:
IntegerReply
}
_
,
err
=
r
.
Str
()
assert
.
NotNil
(
t
,
err
)
r
=
&
Reply
{
Type
:
StatusReply
,
buf
:
[]
byte
(
"foo"
)}
b
,
err
:=
r
.
Str
()
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
"foo"
,
b
)
r
=
&
Reply
{
Type
:
BulkReply
,
buf
:
[]
byte
(
"foo"
)}
b
,
err
=
r
.
Str
()
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
"foo"
,
b
)
}
func
TestBytes
(
t
*
T
)
{
r
:=
&
Reply
{
Type
:
BulkReply
,
buf
:
[]
byte
(
"foo"
)}
b
,
err
:=
r
.
Bytes
()
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
[]
byte
(
"foo"
),
b
)
}
func
TestInt64
(
t
*
T
)
{
r
:=
&
Reply
{
Type
:
ErrorReply
,
Err
:
LoadingError
}
_
,
err
:=
r
.
Int64
()
assert
.
Equal
(
t
,
LoadingError
,
err
)
r
=
&
Reply
{
Type
:
IntegerReply
,
int
:
5
}
b
,
err
:=
r
.
Int64
()
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
int64
(
5
),
b
)
r
=
&
Reply
{
Type
:
BulkReply
,
buf
:
[]
byte
(
"5"
)}
b
,
err
=
r
.
Int64
()
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
int64
(
5
),
b
)
r
=
&
Reply
{
Type
:
BulkReply
,
buf
:
[]
byte
(
"foo"
)}
_
,
err
=
r
.
Int64
()
assert
.
NotNil
(
t
,
err
)
}
func
TestInt
(
t
*
T
)
{
r
:=
&
Reply
{
Type
:
IntegerReply
,
int
:
5
}
b
,
err
:=
r
.
Int
()
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
5
,
b
)
}
func
TestBool
(
t
*
T
)
{
r
:=
&
Reply
{
Type
:
IntegerReply
,
int
:
0
}
b
,
err
:=
r
.
Bool
()
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
false
,
b
)
r
=
&
Reply
{
Type
:
StatusReply
,
buf
:
[]
byte
(
"0"
)}
b
,
err
=
r
.
Bool
()
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
false
,
b
)
r
=
&
Reply
{
Type
:
IntegerReply
,
int
:
2
}
b
,
err
=
r
.
Bool
()
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
true
,
b
)
r
=
&
Reply
{
Type
:
NilReply
}
_
,
err
=
r
.
Bool
()
assert
.
NotNil
(
t
,
err
)
}
func
TestList
(
t
*
T
)
{
r
:=
&
Reply
{
Type
:
MultiReply
}
r
.
Elems
=
make
([]
*
Reply
,
3
)
r
.
Elems
[
0
]
=
&
Reply
{
Type
:
BulkReply
,
buf
:
[]
byte
(
"0"
)}
r
.
Elems
[
1
]
=
&
Reply
{
Type
:
NilReply
}
r
.
Elems
[
2
]
=
&
Reply
{
Type
:
BulkReply
,
buf
:
[]
byte
(
"2"
)}
l
,
err
:=
r
.
List
()
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
3
,
len
(
l
))
assert
.
Equal
(
t
,
"0"
,
l
[
0
])
assert
.
Equal
(
t
,
""
,
l
[
1
])
assert
.
Equal
(
t
,
"2"
,
l
[
2
])
}
func
TestBytesList
(
t
*
T
)
{
r
:=
&
Reply
{
Type
:
MultiReply
}
r
.
Elems
=
make
([]
*
Reply
,
3
)
r
.
Elems
[
0
]
=
&
Reply
{
Type
:
BulkReply
,
buf
:
[]
byte
(
"0"
)}
r
.
Elems
[
1
]
=
&
Reply
{
Type
:
NilReply
}
r
.
Elems
[
2
]
=
&
Reply
{
Type
:
BulkReply
,
buf
:
[]
byte
(
"2"
)}
l
,
err
:=
r
.
ListBytes
()
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
3
,
len
(
l
))
assert
.
Equal
(
t
,
[]
byte
(
"0"
),
l
[
0
])
assert
.
Nil
(
t
,
l
[
1
])
assert
.
Equal
(
t
,
[]
byte
(
"2"
),
l
[
2
])
}
func
TestHash
(
t
*
T
)
{
r
:=
&
Reply
{
Type
:
MultiReply
}
r
.
Elems
=
make
([]
*
Reply
,
6
)
r
.
Elems
[
0
]
=
&
Reply
{
Type
:
BulkReply
,
buf
:
[]
byte
(
"a"
)}
r
.
Elems
[
1
]
=
&
Reply
{
Type
:
BulkReply
,
buf
:
[]
byte
(
"0"
)}
r
.
Elems
[
2
]
=
&
Reply
{
Type
:
BulkReply
,
buf
:
[]
byte
(
"b"
)}
r
.
Elems
[
3
]
=
&
Reply
{
Type
:
NilReply
}
r
.
Elems
[
4
]
=
&
Reply
{
Type
:
BulkReply
,
buf
:
[]
byte
(
"c"
)}
r
.
Elems
[
5
]
=
&
Reply
{
Type
:
BulkReply
,
buf
:
[]
byte
(
"2"
)}
h
,
err
:=
r
.
Hash
()
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
"0"
,
h
[
"a"
])
assert
.
Equal
(
t
,
""
,
h
[
"b"
])
assert
.
Equal
(
t
,
"2"
,
h
[
"c"
])
}
Godeps/_workspace/src/github.com/fzzy/radix/redis/resp/resp.go
0 → 100644
浏览文件 @
8f62ac82
差异被折叠。
点击展开。
Godeps/_workspace/src/github.com/fzzy/radix/redis/resp/resp_test.go
0 → 100644
浏览文件 @
8f62ac82
package
resp
import
(
"bytes"
"errors"
"github.com/stretchr/testify/assert"
.
"testing"
)
func
TestRead
(
t
*
T
)
{
var
m
*
Message
var
err
error
_
,
err
=
NewMessage
(
nil
)
assert
.
NotNil
(
t
,
err
)
_
,
err
=
NewMessage
([]
byte
{})
assert
.
NotNil
(
t
,
err
)
// Simple string
m
,
_
=
NewMessage
([]
byte
(
"+ohey
\r\n
"
))
assert
.
Equal
(
t
,
SimpleStr
,
m
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
"ohey"
),
m
.
val
)
// Empty simple string
m
,
_
=
NewMessage
([]
byte
(
"+
\r\n
"
))
assert
.
Equal
(
t
,
SimpleStr
,
m
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
""
),
m
.
val
.
([]
byte
))
// Error
m
,
_
=
NewMessage
([]
byte
(
"-ohey
\r\n
"
))
assert
.
Equal
(
t
,
Err
,
m
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
"ohey"
),
m
.
val
.
([]
byte
))
// Empty error
m
,
_
=
NewMessage
([]
byte
(
"-
\r\n
"
))
assert
.
Equal
(
t
,
Err
,
m
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
""
),
m
.
val
.
([]
byte
))
// Int
m
,
_
=
NewMessage
([]
byte
(
":1024
\r\n
"
))
assert
.
Equal
(
t
,
Int
,
m
.
Type
)
assert
.
Equal
(
t
,
int64
(
1024
),
m
.
val
.
(
int64
))
// Bulk string
m
,
_
=
NewMessage
([]
byte
(
"$3
\r\n
foo
\r\n
"
))
assert
.
Equal
(
t
,
BulkStr
,
m
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
"foo"
),
m
.
val
.
([]
byte
))
// Empty bulk string
m
,
_
=
NewMessage
([]
byte
(
"$0
\r\n\r\n
"
))
assert
.
Equal
(
t
,
BulkStr
,
m
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
""
),
m
.
val
.
([]
byte
))
// Nil bulk string
m
,
_
=
NewMessage
([]
byte
(
"$-1
\r\n
"
))
assert
.
Equal
(
t
,
Nil
,
m
.
Type
)
// Array
m
,
_
=
NewMessage
([]
byte
(
"*2
\r\n
+foo
\r\n
+bar
\r\n
"
))
assert
.
Equal
(
t
,
Array
,
m
.
Type
)
assert
.
Equal
(
t
,
2
,
len
(
m
.
val
.
([]
*
Message
)))
assert
.
Equal
(
t
,
SimpleStr
,
m
.
val
.
([]
*
Message
)[
0
]
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
"foo"
),
m
.
val
.
([]
*
Message
)[
0
]
.
val
.
([]
byte
))
assert
.
Equal
(
t
,
SimpleStr
,
m
.
val
.
([]
*
Message
)[
1
]
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
"bar"
),
m
.
val
.
([]
*
Message
)[
1
]
.
val
.
([]
byte
))
// Empty array
m
,
_
=
NewMessage
([]
byte
(
"*0
\r\n
"
))
assert
.
Equal
(
t
,
Array
,
m
.
Type
)
assert
.
Equal
(
t
,
0
,
len
(
m
.
val
.
([]
*
Message
)))
// Nil Array
m
,
_
=
NewMessage
([]
byte
(
"*-1
\r\n
"
))
assert
.
Equal
(
t
,
Nil
,
m
.
Type
)
// Embedded Array
m
,
_
=
NewMessage
([]
byte
(
"*3
\r\n
+foo
\r\n
+bar
\r\n
*2
\r\n
+foo
\r\n
+bar
\r\n
"
))
assert
.
Equal
(
t
,
Array
,
m
.
Type
)
assert
.
Equal
(
t
,
3
,
len
(
m
.
val
.
([]
*
Message
)))
assert
.
Equal
(
t
,
SimpleStr
,
m
.
val
.
([]
*
Message
)[
0
]
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
"foo"
),
m
.
val
.
([]
*
Message
)[
0
]
.
val
.
([]
byte
))
assert
.
Equal
(
t
,
SimpleStr
,
m
.
val
.
([]
*
Message
)[
1
]
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
"bar"
),
m
.
val
.
([]
*
Message
)[
1
]
.
val
.
([]
byte
))
m
=
m
.
val
.
([]
*
Message
)[
2
]
assert
.
Equal
(
t
,
2
,
len
(
m
.
val
.
([]
*
Message
)))
assert
.
Equal
(
t
,
SimpleStr
,
m
.
val
.
([]
*
Message
)[
0
]
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
"foo"
),
m
.
val
.
([]
*
Message
)[
0
]
.
val
.
([]
byte
))
assert
.
Equal
(
t
,
SimpleStr
,
m
.
val
.
([]
*
Message
)[
1
]
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
"bar"
),
m
.
val
.
([]
*
Message
)[
1
]
.
val
.
([]
byte
))
// Test that two bulks in a row read correctly
m
,
_
=
NewMessage
([]
byte
(
"*2
\r\n
$3
\r\n
foo
\r\n
$3
\r\n
bar
\r\n
"
))
assert
.
Equal
(
t
,
Array
,
m
.
Type
)
assert
.
Equal
(
t
,
2
,
len
(
m
.
val
.
([]
*
Message
)))
assert
.
Equal
(
t
,
BulkStr
,
m
.
val
.
([]
*
Message
)[
0
]
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
"foo"
),
m
.
val
.
([]
*
Message
)[
0
]
.
val
.
([]
byte
))
assert
.
Equal
(
t
,
BulkStr
,
m
.
val
.
([]
*
Message
)[
1
]
.
Type
)
assert
.
Equal
(
t
,
[]
byte
(
"bar"
),
m
.
val
.
([]
*
Message
)[
1
]
.
val
.
([]
byte
))
}
type
arbitraryTest
struct
{
val
interface
{}
expect
[]
byte
}
var
nilMessage
,
_
=
NewMessage
([]
byte
(
"$-1
\r\n
"
))
var
arbitraryTests
=
[]
arbitraryTest
{
{[]
byte
(
"OHAI"
),
[]
byte
(
"$4
\r\n
OHAI
\r\n
"
)},
{
"OHAI"
,
[]
byte
(
"$4
\r\n
OHAI
\r\n
"
)},
{
true
,
[]
byte
(
"$1
\r\n
1
\r\n
"
)},
{
false
,
[]
byte
(
"$1
\r\n
0
\r\n
"
)},
{
nil
,
[]
byte
(
"$-1
\r\n
"
)},
{
80
,
[]
byte
(
":80
\r\n
"
)},
{
int64
(
-
80
),
[]
byte
(
":-80
\r\n
"
)},
{
uint64
(
80
),
[]
byte
(
":80
\r\n
"
)},
{
float32
(
0.1234
),
[]
byte
(
"$6
\r\n
0.1234
\r\n
"
)},
{
float64
(
0.1234
),
[]
byte
(
"$6
\r\n
0.1234
\r\n
"
)},
{
errors
.
New
(
"hi"
),
[]
byte
(
"-hi
\r\n
"
)},
{
nilMessage
,
[]
byte
(
"$-1
\r\n
"
)},
{[]
int
{
1
,
2
,
3
},
[]
byte
(
"*3
\r\n
:1
\r\n
:2
\r\n
:3
\r\n
"
)},
{
map
[
int
]
int
{
1
:
2
},
[]
byte
(
"*2
\r\n
:1
\r\n
:2
\r\n
"
)},
{
NewSimpleString
(
"OK"
),
[]
byte
(
"+OK
\r\n
"
)},
}
var
arbitraryAsStringTests
=
[]
arbitraryTest
{
{[]
byte
(
"OHAI"
),
[]
byte
(
"$4
\r\n
OHAI
\r\n
"
)},
{
"OHAI"
,
[]
byte
(
"$4
\r\n
OHAI
\r\n
"
)},
{
true
,
[]
byte
(
"$1
\r\n
1
\r\n
"
)},
{
false
,
[]
byte
(
"$1
\r\n
0
\r\n
"
)},
{
nil
,
[]
byte
(
"$0
\r\n\r\n
"
)},
{
80
,
[]
byte
(
"$2
\r\n
80
\r\n
"
)},
{
int64
(
-
80
),
[]
byte
(
"$3
\r\n
-80
\r\n
"
)},
{
uint64
(
80
),
[]
byte
(
"$2
\r\n
80
\r\n
"
)},
{
float32
(
0.1234
),
[]
byte
(
"$6
\r\n
0.1234
\r\n
"
)},
{
float64
(
0.1234
),
[]
byte
(
"$6
\r\n
0.1234
\r\n
"
)},
{
errors
.
New
(
"hi"
),
[]
byte
(
"$2
\r\n
hi
\r\n
"
)},
{
nilMessage
,
[]
byte
(
"$-1
\r\n
"
)},
{[]
int
{
1
,
2
,
3
},
[]
byte
(
"*3
\r\n
$1
\r\n
1
\r\n
$1
\r\n
2
\r\n
$1
\r\n
3
\r\n
"
)},
{
map
[
int
]
int
{
1
:
2
},
[]
byte
(
"*2
\r\n
$1
\r\n
1
\r\n
$1
\r\n
2
\r\n
"
)},
{
NewSimpleString
(
"OK"
),
[]
byte
(
"+OK
\r\n
"
)},
}
var
arbitraryAsFlattenedStringsTests
=
[]
arbitraryTest
{
{
[]
interface
{}{
"wat"
,
map
[
string
]
interface
{}{
"foo"
:
1
,
}},
[]
byte
(
"*3
\r\n
$3
\r\n
wat
\r\n
$3
\r\n
foo
\r\n
$1
\r\n
1
\r\n
"
),
},
}
func
TestWriteArbitrary
(
t
*
T
)
{
var
err
error
buf
:=
bytes
.
NewBuffer
([]
byte
{})
for
_
,
test
:=
range
arbitraryTests
{
t
.
Logf
(
"Checking test %v"
,
test
)
buf
.
Reset
()
err
=
WriteArbitrary
(
buf
,
test
.
val
)
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
test
.
expect
,
buf
.
Bytes
())
}
}
func
TestWriteArbitraryAsString
(
t
*
T
)
{
var
err
error
buf
:=
bytes
.
NewBuffer
([]
byte
{})
for
_
,
test
:=
range
arbitraryAsStringTests
{
t
.
Logf
(
"Checking test %v"
,
test
)
buf
.
Reset
()
err
=
WriteArbitraryAsString
(
buf
,
test
.
val
)
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
test
.
expect
,
buf
.
Bytes
())
}
}
func
TestWriteArbitraryAsFlattenedStrings
(
t
*
T
)
{
var
err
error
buf
:=
bytes
.
NewBuffer
([]
byte
{})
for
_
,
test
:=
range
arbitraryAsFlattenedStringsTests
{
t
.
Logf
(
"Checking test %v"
,
test
)
buf
.
Reset
()
err
=
WriteArbitraryAsFlattenedStrings
(
buf
,
test
.
val
)
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
test
.
expect
,
buf
.
Bytes
())
}
}
func
TestMessageWrite
(
t
*
T
)
{
var
err
error
var
m
*
Message
buf
:=
bytes
.
NewBuffer
([]
byte
{})
for
_
,
test
:=
range
arbitraryTests
{
t
.
Logf
(
"Checking test; %v"
,
test
)
buf
.
Reset
()
m
,
err
=
NewMessage
(
test
.
expect
)
assert
.
Nil
(
t
,
err
)
err
=
WriteMessage
(
buf
,
m
)
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
test
.
expect
,
buf
.
Bytes
())
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论