mirror of
https://github.com/EchoVault/SugarDB.git
synced 2025-10-05 07:56:52 +08:00
Removed duplicate imports for set, sorted_set, pubsub and acl modules. Moved /modules from /pkg to /internal. Delted commands package: Commands will now be automatically loaded when an EchoVault instance is initialised.
This commit is contained in:
333
internal/modules/admin/commands.go
Normal file
333
internal/modules/admin/commands.go
Normal file
@@ -0,0 +1,333 @@
|
||||
// Copyright 2024 Kelvin Clement Mwinuka
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/echovault/echovault/pkg/constants"
|
||||
"github.com/echovault/echovault/pkg/types"
|
||||
"github.com/gobwas/glob"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func handleGetAllCommands(params types.HandlerFuncParams) ([]byte, error) {
|
||||
commands := params.GetAllCommands()
|
||||
|
||||
res := ""
|
||||
commandCount := 0
|
||||
|
||||
for _, c := range commands {
|
||||
if c.SubCommands == nil || len(c.SubCommands) <= 0 {
|
||||
res += "*6\r\n"
|
||||
// Command name
|
||||
res += fmt.Sprintf("+command\r\n*1\r\n$%d\r\n%s\r\n", len(c.Command), c.Command)
|
||||
// Command categories
|
||||
res += fmt.Sprintf("+categories\r\n*%d\r\n", len(c.Categories))
|
||||
for _, category := range c.Categories {
|
||||
res += fmt.Sprintf("$%d\r\n%s\r\n", len(category), category)
|
||||
}
|
||||
// Description
|
||||
res += fmt.Sprintf("+description\r\n*1\r\n$%d\r\n%s\r\n", len(c.Description), c.Description)
|
||||
|
||||
commandCount += 1
|
||||
continue
|
||||
}
|
||||
// There are sub-commands
|
||||
for _, sc := range c.SubCommands {
|
||||
res += "*6\r\n"
|
||||
// Command name
|
||||
command := fmt.Sprintf("%s %s", c.Command, sc.Command)
|
||||
res += fmt.Sprintf("+command\r\n*1\r\n$%d\r\n%s\r\n", len(command), command)
|
||||
// Command categories
|
||||
res += fmt.Sprintf("+categories\r\n*%d\r\n", len(sc.Categories))
|
||||
for _, category := range sc.Categories {
|
||||
res += fmt.Sprintf("$%d\r\n%s\r\n", len(category), category)
|
||||
}
|
||||
// Description
|
||||
res += fmt.Sprintf("+description\r\n*1\r\n$%d\r\n%s\r\n", len(sc.Description), sc.Description)
|
||||
|
||||
commandCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
res = fmt.Sprintf("*%d\r\n%s", commandCount, res)
|
||||
|
||||
return []byte(res), nil
|
||||
}
|
||||
|
||||
func handleCommandCount(params types.HandlerFuncParams) ([]byte, error) {
|
||||
var count int
|
||||
|
||||
commands := params.GetAllCommands()
|
||||
for _, command := range commands {
|
||||
if command.SubCommands != nil && len(command.SubCommands) > 0 {
|
||||
for _, _ = range command.SubCommands {
|
||||
count += 1
|
||||
}
|
||||
continue
|
||||
}
|
||||
count += 1
|
||||
}
|
||||
|
||||
return []byte(fmt.Sprintf(":%d\r\n", count)), nil
|
||||
}
|
||||
|
||||
func handleCommandList(params types.HandlerFuncParams) ([]byte, error) {
|
||||
switch len(params.Command) {
|
||||
case 2:
|
||||
// Command is COMMAND LIST
|
||||
var count int
|
||||
var res string
|
||||
commands := params.GetAllCommands()
|
||||
for _, command := range commands {
|
||||
if command.SubCommands != nil && len(command.SubCommands) > 0 {
|
||||
for _, subcommand := range command.SubCommands {
|
||||
comm := fmt.Sprintf("%s %s", command.Command, subcommand.Command)
|
||||
res += fmt.Sprintf("$%d\r\n%s\r\n", len(comm), comm)
|
||||
count += 1
|
||||
}
|
||||
continue
|
||||
}
|
||||
res += fmt.Sprintf("$%d\r\n%s\r\n", len(command.Command), command.Command)
|
||||
count += 1
|
||||
}
|
||||
res = fmt.Sprintf("*%d\r\n%s", count, res)
|
||||
return []byte(res), nil
|
||||
|
||||
case 5:
|
||||
var count int
|
||||
var res string
|
||||
// Command has filter
|
||||
if !strings.EqualFold("FILTERBY", params.Command[2]) {
|
||||
return nil, fmt.Errorf("expected FILTERBY, got %s", strings.ToUpper(params.Command[2]))
|
||||
}
|
||||
if strings.EqualFold("ACLCAT", params.Command[3]) {
|
||||
// ACL Category filter
|
||||
commands := params.GetAllCommands()
|
||||
category := strings.ToLower(params.Command[4])
|
||||
for _, command := range commands {
|
||||
if command.SubCommands != nil && len(command.SubCommands) > 0 {
|
||||
for _, subcommand := range command.SubCommands {
|
||||
if slices.Contains(subcommand.Categories, category) {
|
||||
comm := fmt.Sprintf("%s %s", command.Command, subcommand.Command)
|
||||
res += fmt.Sprintf("$%d\r\n%s\r\n", len(comm), comm)
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if slices.Contains(command.Categories, category) {
|
||||
res += fmt.Sprintf("$%d\r\n%s\r\n", len(command.Command), command.Command)
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
} else if strings.EqualFold("PATTERN", params.Command[3]) {
|
||||
// Pattern filter
|
||||
commands := params.GetAllCommands()
|
||||
g := glob.MustCompile(params.Command[4])
|
||||
for _, command := range commands {
|
||||
if command.SubCommands != nil && len(command.SubCommands) > 0 {
|
||||
for _, subcommand := range command.SubCommands {
|
||||
comm := fmt.Sprintf("%s %s", command.Command, subcommand.Command)
|
||||
if g.Match(comm) {
|
||||
res += fmt.Sprintf("$%d\r\n%s\r\n", len(comm), comm)
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if g.Match(command.Command) {
|
||||
res += fmt.Sprintf("$%d\r\n%s\r\n", len(command.Command), command.Command)
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
} else if strings.EqualFold("MODULE", params.Command[3]) {
|
||||
// Module filter
|
||||
commands := params.GetAllCommands()
|
||||
module := strings.ToLower(params.Command[4])
|
||||
for _, command := range commands {
|
||||
if command.SubCommands != nil && len(command.SubCommands) > 0 {
|
||||
for _, subcommand := range command.SubCommands {
|
||||
if strings.EqualFold(subcommand.Module, module) {
|
||||
comm := fmt.Sprintf("%s %s", command.Command, subcommand.Command)
|
||||
res += fmt.Sprintf("$%d\r\n%s\r\n", len(comm), comm)
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(command.Module, module) {
|
||||
res += fmt.Sprintf("$%d\r\n%s\r\n", len(command.Command), command.Command)
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("expected filter to be ACLCAT or PATTERN, got %s", strings.ToUpper(params.Command[3]))
|
||||
}
|
||||
res = fmt.Sprintf("*%d\r\n%s", count, res)
|
||||
return []byte(res), nil
|
||||
default:
|
||||
return nil, errors.New(constants.WrongArgsResponse)
|
||||
}
|
||||
}
|
||||
|
||||
func handleCommandDocs(params types.HandlerFuncParams) ([]byte, error) {
|
||||
return []byte("*0\r\n"), nil
|
||||
}
|
||||
|
||||
func Commands() []types.Command {
|
||||
return []types.Command{
|
||||
{
|
||||
Command: "commands",
|
||||
Module: constants.AdminModule,
|
||||
Categories: []string{constants.AdminCategory, constants.SlowCategory},
|
||||
Description: "Get a list of all the commands in available on the echovault with categories and descriptions",
|
||||
Sync: false,
|
||||
KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) {
|
||||
return types.AccessKeys{
|
||||
Channels: make([]string, 0),
|
||||
ReadKeys: make([]string, 0),
|
||||
WriteKeys: make([]string, 0),
|
||||
}, nil
|
||||
},
|
||||
HandlerFunc: handleGetAllCommands,
|
||||
},
|
||||
{
|
||||
Command: "command",
|
||||
Module: constants.AdminModule,
|
||||
Categories: []string{},
|
||||
Description: "Commands pertaining to echovault commands",
|
||||
Sync: false,
|
||||
KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) {
|
||||
return types.AccessKeys{
|
||||
Channels: make([]string, 0),
|
||||
ReadKeys: make([]string, 0),
|
||||
WriteKeys: make([]string, 0),
|
||||
}, nil
|
||||
},
|
||||
SubCommands: []types.SubCommand{
|
||||
{
|
||||
Command: "docs",
|
||||
Module: constants.AdminModule,
|
||||
Categories: []string{constants.SlowCategory, constants.ConnectionCategory},
|
||||
Description: "Get command documentation",
|
||||
Sync: false,
|
||||
KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) {
|
||||
return types.AccessKeys{
|
||||
Channels: make([]string, 0),
|
||||
ReadKeys: make([]string, 0),
|
||||
WriteKeys: make([]string, 0),
|
||||
}, nil
|
||||
},
|
||||
HandlerFunc: handleCommandDocs,
|
||||
},
|
||||
{
|
||||
Command: "count",
|
||||
Module: constants.AdminModule,
|
||||
Categories: []string{constants.SlowCategory},
|
||||
Description: "Get the dumber of commands in the echovault",
|
||||
Sync: false,
|
||||
KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) {
|
||||
return types.AccessKeys{
|
||||
Channels: make([]string, 0),
|
||||
ReadKeys: make([]string, 0),
|
||||
WriteKeys: make([]string, 0),
|
||||
}, nil
|
||||
},
|
||||
HandlerFunc: handleCommandCount,
|
||||
},
|
||||
{
|
||||
Command: "list",
|
||||
Module: constants.AdminModule,
|
||||
Categories: []string{constants.SlowCategory},
|
||||
Description: `(COMMAND LIST [FILTERBY <ACLCAT category | PATTERN pattern | MODULE module>]) Get the list of command names.
|
||||
Allows for filtering by ACL category or glob pattern.`,
|
||||
Sync: false,
|
||||
KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) {
|
||||
return types.AccessKeys{
|
||||
Channels: make([]string, 0),
|
||||
ReadKeys: make([]string, 0),
|
||||
WriteKeys: make([]string, 0),
|
||||
}, nil
|
||||
},
|
||||
HandlerFunc: handleCommandList,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Command: "save",
|
||||
Module: constants.AdminModule,
|
||||
Categories: []string{constants.AdminCategory, constants.SlowCategory, constants.DangerousCategory},
|
||||
Description: "(SAVE) Trigger a snapshot save",
|
||||
Sync: true,
|
||||
KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) {
|
||||
return types.AccessKeys{
|
||||
Channels: make([]string, 0),
|
||||
ReadKeys: make([]string, 0),
|
||||
WriteKeys: make([]string, 0),
|
||||
}, nil
|
||||
},
|
||||
HandlerFunc: func(params types.HandlerFuncParams) ([]byte, error) {
|
||||
if err := params.TakeSnapshot(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte(constants.OkResponse), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Command: "lastsave",
|
||||
Module: constants.AdminModule,
|
||||
Categories: []string{constants.AdminCategory, constants.FastCategory, constants.DangerousCategory},
|
||||
Description: "(LASTSAVE) Get unix timestamp for the latest snapshot in milliseconds.",
|
||||
Sync: false,
|
||||
KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) {
|
||||
return types.AccessKeys{
|
||||
Channels: make([]string, 0),
|
||||
ReadKeys: make([]string, 0),
|
||||
WriteKeys: make([]string, 0),
|
||||
}, nil
|
||||
},
|
||||
HandlerFunc: func(params types.HandlerFuncParams) ([]byte, error) {
|
||||
msec := params.GetLatestSnapshotTime()
|
||||
if msec == 0 {
|
||||
return nil, errors.New("no snapshot")
|
||||
}
|
||||
return []byte(fmt.Sprintf(":%d\r\n", msec)), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Command: "rewriteaof",
|
||||
Module: constants.AdminModule,
|
||||
Categories: []string{constants.AdminCategory, constants.SlowCategory, constants.DangerousCategory},
|
||||
Description: "(REWRITEAOF) Trigger re-writing of append process",
|
||||
Sync: false,
|
||||
KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) {
|
||||
return types.AccessKeys{
|
||||
Channels: make([]string, 0),
|
||||
ReadKeys: make([]string, 0),
|
||||
WriteKeys: make([]string, 0),
|
||||
}, nil
|
||||
},
|
||||
HandlerFunc: func(params types.HandlerFuncParams) ([]byte, error) {
|
||||
if err := params.RewriteAOF(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte(constants.OkResponse), nil
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user