resp 协议主要是方便使用redis 客户端进行连接,resp 主要是依赖 tidwall/redcon golang redis 协议包
resp 服务说明
server_resp.go 文件,干的事情比较简单,就是redis command 的支持,包含了几个内置的
ping select help quit echo, 以及宏相关的list 以及宏调用的command
代码
server_resp.go
- 注册redis 协议服务
func initRESPServer() error {
return redcon.ListenAndServe(
*flagRESPListenAddr,
func(conn redcon.Conn, cmd redcon.Command) {
// handles any panic
defer (func() {
if err := recover(); err != nil {
conn.WriteError(fmt.Sprintf("fatal error: %s", (err.(error)).Error()))
}
})()
- 协议解析
内置协议的处理help echo ping 。。。
比较简单,就是写数据,都是字符串类型的
// internal command to pick a database
if todoNormalized == "select" {
conn.WriteString("OK")
return
}
// internal ping-pong
if todoNormalized == "ping" {
conn.WriteString("PONG")
return
}
// ECHO <args ...>
if todoNormalized == "echo" {
conn.WriteString(strings.Join(args, " "))
return
}
宏调用
list command 命令,主要是调用macrosManager 的list 方便,返回宏的列表
// HELP|INFO|LIST
if todoNormalized == "list" || todoNormalized == "help" || todoNormalized == "info" {
conn.WriteArray(macrosManager.Size())
for _, v := range macrosManager.List() {
conn.WriteBulkString(v)
}
}
宏方便指定
核心是commandExecMacro
macro := macrosManager.Get(todo)
if nil == macro {
conn.WriteError("not found")
conn.Close()
return
}
var input map[string]interface{}
if len(args) > 0 {
json.Unmarshal([]byte(args[0]), &input)
}
// handle our command
commandExecMacro(conn, macro, input)
commandExecMacro 方法如下:
func commandExecMacro(conn redcon.Conn, macro *Macro, input map[string]interface{}) {
// 调用macro 的call,call 包含了宏生命周期中的处理,注意input 数据是一个json 对象数据,所以通过
redis 客户端调用宏的时候数据需要json 序列化
out, err := macro.Call(input)
if err != nil {
conn.WriteArray(2)
conn.WriteInt(0)
j, _ := json.Marshal(err.Error())
conn.WriteBulk(j)
return
}
jsonOUT, _ := json.Marshal(out)
conn.WriteArray(2)
conn.WriteInt(1)
conn.WriteBulk(jsonOUT)
}
参考资料
https://github.com/tidwall/redcon
https://github.com/alash3al/sqler/blob/master/server_resp.go