mirror of
https://github.com/HDT3213/godis.git
synced 2025-10-05 16:57:06 +08:00
support Command command
This commit is contained in:
171
database/command.go
Normal file
171
database/command.go
Normal file
@@ -0,0 +1,171 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"github.com/hdt3213/godis/interface/redis"
|
||||
"github.com/hdt3213/godis/redis/protocol"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
||||
|
||||
var commandTable = make(map[string]*godisCommand)
|
||||
|
||||
const (
|
||||
Write = "write"
|
||||
Readonly = "readonly"
|
||||
Denyoom = "denyoom"
|
||||
Admin = "admin"
|
||||
Pubsub = "pubsub"
|
||||
Noscript = "noscript"
|
||||
Random = "random"
|
||||
SortForScript = "sortforscript"
|
||||
Loading = "loading"
|
||||
Stale = "stale"
|
||||
SkipMonitor = "skip_monitor"
|
||||
Asking = "asking"
|
||||
Fast = "fast"
|
||||
Movablekeys = "movablekeys"
|
||||
)
|
||||
|
||||
type godisCommand struct {
|
||||
name string
|
||||
arity int
|
||||
signs []string
|
||||
firstKey int
|
||||
lastKey int
|
||||
stepNumber int
|
||||
prepare PreFunc
|
||||
}
|
||||
|
||||
func RegisterGodisCommand(name string, arity int, signs []string, firstKey int, lastKey int, stepNumber int, prepare PreFunc) {
|
||||
name = strings.ToLower(name)
|
||||
commandTable[name] = &godisCommand{
|
||||
name: name,
|
||||
arity: arity,
|
||||
signs: signs,
|
||||
firstKey: firstKey,
|
||||
lastKey: lastKey,
|
||||
stepNumber: stepNumber,
|
||||
prepare: prepare,
|
||||
}
|
||||
}
|
||||
|
||||
func execCommand(args [][]byte) redis.Reply {
|
||||
n := len(args)
|
||||
if n > 1 {
|
||||
subCommand := strings.ToUpper(string(args[1]))
|
||||
if subCommand == "INFO" {
|
||||
return getCommands(args[2:])
|
||||
} else if subCommand == "COUNT" {
|
||||
return protocol.MakeIntReply(int64(len(commandTable)))
|
||||
} else if subCommand == "GETKEYS" {
|
||||
if n < 2 {
|
||||
return protocol.MakeErrReply("Unknown subcommand or wrong number of arguments for '" + subCommand + "'")
|
||||
}
|
||||
return getKeys(args[2:])
|
||||
} else {
|
||||
return protocol.MakeErrReply("Unknow subcomand or wrong number of arguments for '" + subCommand + "'")
|
||||
}
|
||||
} else {
|
||||
return getAllGodisCommandReply()
|
||||
}
|
||||
}
|
||||
|
||||
func getKeys(args [][]byte) redis.Reply {
|
||||
key := string(args[0])
|
||||
command, ok := commandTable[key]
|
||||
if !ok {
|
||||
return protocol.MakeErrReply("Invalid command specified")
|
||||
}
|
||||
arity := command.arity
|
||||
if arity > 0 {
|
||||
if len(args) != arity {
|
||||
return protocol.MakeErrReply("Invalid number of arguments specified for command")
|
||||
}
|
||||
} else {
|
||||
if len(args) < -arity {
|
||||
return protocol.MakeErrReply("Invalid number of arguments specified for command")
|
||||
}
|
||||
}
|
||||
|
||||
prepare := command.prepare
|
||||
if prepare == nil {
|
||||
return protocol.MakeErrReply("The command has no key arguments")
|
||||
}
|
||||
writeKeys, readKeys := prepare(args[1:])
|
||||
|
||||
keys := append(writeKeys, readKeys...)
|
||||
replies := make([]redis.Reply, len(keys))
|
||||
for i, key := range keys {
|
||||
replies[i] = protocol.MakeBulkReply([]byte(key))
|
||||
}
|
||||
return protocol.MakeMultiRawReply(replies)
|
||||
}
|
||||
|
||||
func getCommands(args [][]byte) redis.Reply {
|
||||
replies := make([]redis.Reply, len(args))
|
||||
|
||||
for i, v := range args {
|
||||
reply, ok := commandTable[string(v)]
|
||||
if ok {
|
||||
replies[i] = reply.ToReply()
|
||||
} else {
|
||||
replies[i] = protocol.MakeNullBulkReply()
|
||||
}
|
||||
}
|
||||
|
||||
return protocol.MakeMultiRawReply(replies)
|
||||
}
|
||||
|
||||
func getAllGodisCommandReply() redis.Reply {
|
||||
replies := make([]redis.Reply, len(commandTable))
|
||||
i := 0
|
||||
for _, v := range commandTable {
|
||||
replies[i] = v.ToReply()
|
||||
i++
|
||||
}
|
||||
return protocol.MakeMultiRawReply(replies)
|
||||
}
|
||||
|
||||
func (g *godisCommand) ToReply() redis.Reply {
|
||||
args := make([]redis.Reply, 6)
|
||||
args[0] = protocol.MakeBulkReply([]byte(g.name))
|
||||
args[1] = protocol.MakeIntReply(int64(g.arity))
|
||||
signs := make([]redis.Reply, len(g.signs))
|
||||
for i, v := range g.signs {
|
||||
signs[i] = protocol.MakeStatusReply(v)
|
||||
}
|
||||
args[2] = protocol.MakeMultiRawReply(signs)
|
||||
args[3] = protocol.MakeIntReply(int64(g.firstKey))
|
||||
args[4] = protocol.MakeIntReply(int64(g.lastKey))
|
||||
args[5] = protocol.MakeIntReply(int64(g.stepNumber))
|
||||
|
||||
return protocol.MakeMultiRawReply(args)
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterGodisCommand("Command", 0, []string{Random, Loading, Stale}, 0, 0, 0, nil)
|
||||
|
||||
RegisterGodisCommand("Keys", 2, []string{Readonly, SortForScript}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("Auth", 2, []string{Noscript, Loading, Stale, SkipMonitor, Fast}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("Info", -1, []string{Random, Loading, Stale}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("Slaveof", 3, []string{Admin, Noscript, Stale}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("Subscribe", -2, []string{Pubsub, Noscript, Loading, Stale}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("Publish", 3, []string{Pubsub, Noscript, Loading, Fast}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("FlushAll", -1, []string{Write}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("FlushDb", -1, []string{Write}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("Save", 1, []string{Admin, Noscript}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("BgSave", 1, []string{Admin, Noscript}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("Select", 2, []string{Loading, Fast}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("Replconf", -1, []string{Admin, Noscript, Loading, Stale}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("Replconf", 3, []string{Readonly, Admin, Noscript}, 0, 0, 0, nil)
|
||||
|
||||
// transaction command
|
||||
RegisterGodisCommand("Multi", 1, []string{Noscript, Fast}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("Discard", 1, []string{Noscript, Fast}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("Exec", 1, []string{Noscript, SkipMonitor}, 0, 0, 0, nil)
|
||||
RegisterGodisCommand("Watch", 1, []string{Noscript, Fast}, 1, -1, 1, readAllKeys)
|
||||
|
||||
}
|
Reference in New Issue
Block a user