Uncommented AddCommand method

This commit is contained in:
Kelvin Clement Mwinuka
2024-05-26 15:26:04 +08:00
parent e3ecc42454
commit abee9ea858
5 changed files with 1459 additions and 231 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,7 @@ package echovault
import ( import (
"context" "context"
"fmt"
"github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal"
"slices" "slices"
"strings" "strings"
@@ -84,14 +85,9 @@ type CommandHandlerFunc func(params CommandHandlerFuncParams) ([]byte, error)
type CommandHandlerFuncParams struct { type CommandHandlerFuncParams struct {
Context context.Context Context context.Context
Command []string Command []string
KeyExists func(ctx context.Context, key string) bool KeysExist func(keys []string) map[string]bool
CreateKeyAndLock func(ctx context.Context, key string) (bool, error) GetValues func(ctx context.Context, keys []string) map[string]interface{}
KeyLock func(ctx context.Context, key string) (bool, error) SetValues func(ctx context.Context, entries map[string]interface{}) error
KeyUnlock func(ctx context.Context, key string)
KeyRLock func(ctx context.Context, key string) (bool, error)
KeyRUnlock func(ctx context.Context, key string)
GetValue func(ctx context.Context, key string) interface{}
SetValue func(ctx context.Context, key string, value interface{}) error
} }
// CommandOptions provides the specification of the command to be added to the EchoVault instance. // CommandOptions provides the specification of the command to be added to the EchoVault instance.
@@ -229,133 +225,123 @@ func (server *EchoVault) RewriteAOF() (string, error) {
// Errors: // Errors:
// //
// "command <command> already exists" - If a command with the same command name as the passed command already exists. // "command <command> already exists" - If a command with the same command name as the passed command already exists.
// func (server *EchoVault) AddCommand(command CommandOptions) error { func (server *EchoVault) AddCommand(command CommandOptions) error {
// server.commandsRWMut.Lock() server.commandsRWMut.Lock()
// defer server.commandsRWMut.Unlock() defer server.commandsRWMut.Unlock()
// // Check if command already exists // Check if command already exists
// for _, c := range server.commands { for _, c := range server.commands {
// if strings.EqualFold(c.Command, command.Command) { if strings.EqualFold(c.Command, command.Command) {
// return fmt.Errorf("command %s already exists", command.Command) return fmt.Errorf("command %s already exists", command.Command)
// } }
// } }
//
// if command.SubCommand == nil || len(command.SubCommand) == 0 { if command.SubCommand == nil || len(command.SubCommand) == 0 {
// // Add command with no subcommands // Add command with no subcommands
// server.commands = append(server.commands, internal.Command{ server.commands = append(server.commands, internal.Command{
// Command: command.Command, Command: command.Command,
// Module: strings.ToLower(command.Module), // Convert module to lower case for uniformity Module: strings.ToLower(command.Module), // Convert module to lower case for uniformity
// Categories: func() []string { Categories: func() []string {
// // Convert all the categories to lower case for uniformity // Convert all the categories to lower case for uniformity
// cats := make([]string, len(command.Categories)) cats := make([]string, len(command.Categories))
// for i, cat := range command.Categories { for i, cat := range command.Categories {
// cats[i] = strings.ToLower(cat) cats[i] = strings.ToLower(cat)
// } }
// return cats return cats
// }(), }(),
// Description: command.Description, Description: command.Description,
// Sync: command.Sync, Sync: command.Sync,
// KeyExtractionFunc: internal.KeyExtractionFunc(func(cmd []string) (internal.KeyExtractionFuncResult, error) { KeyExtractionFunc: internal.KeyExtractionFunc(func(cmd []string) (internal.KeyExtractionFuncResult, error) {
// accessKeys, err := command.KeyExtractionFunc(cmd) accessKeys, err := command.KeyExtractionFunc(cmd)
// if err != nil { if err != nil {
// return internal.KeyExtractionFuncResult{}, err return internal.KeyExtractionFuncResult{}, err
// } }
// return internal.KeyExtractionFuncResult{ return internal.KeyExtractionFuncResult{
// Channels: []string{}, Channels: []string{},
// ReadKeys: accessKeys.ReadKeys, ReadKeys: accessKeys.ReadKeys,
// WriteKeys: accessKeys.WriteKeys, WriteKeys: accessKeys.WriteKeys,
// }, nil }, nil
// }), }),
// HandlerFunc: internal.HandlerFunc(func(params internal.HandlerFuncParams) ([]byte, error) { HandlerFunc: internal.HandlerFunc(func(params internal.HandlerFuncParams) ([]byte, error) {
// return command.HandlerFunc(CommandHandlerFuncParams{ return command.HandlerFunc(CommandHandlerFuncParams{
// Context: params.Context, Context: params.Context,
// Command: params.Command, Command: params.Command,
// KeyLock: params.KeyLock, KeysExist: params.KeysExist,
// KeyUnlock: params.KeyUnlock, GetValues: params.GetValues,
// KeyRLock: params.KeyRLock, SetValues: params.SetValues,
// KeyRUnlock: params.KeyRUnlock, })
// KeyExists: params.KeyExists, }),
// CreateKeyAndLock: params.CreateKeyAndLock, })
// GetValue: params.GetValue, return nil
// SetValue: params.SetValue, }
// })
// }), // Add command with subcommands
// }) newCommand := internal.Command{
// return nil Command: command.Command,
// } Module: command.Module,
// Categories: func() []string {
// // Add command with subcommands // Convert all the categories to lower case for uniformity
// newCommand := internal.Command{ cats := make([]string, len(command.Categories))
// Command: command.Command, for j, cat := range command.Categories {
// Module: command.Module, cats[j] = strings.ToLower(cat)
// Categories: func() []string { }
// // Convert all the categories to lower case for uniformity return cats
// cats := make([]string, len(command.Categories)) }(),
// for j, cat := range command.Categories { Description: command.Description,
// cats[j] = strings.ToLower(cat) Sync: command.Sync,
// } KeyExtractionFunc: func(cmd []string) (internal.KeyExtractionFuncResult, error) {
// return cats return internal.KeyExtractionFuncResult{}, nil
// }(), },
// Description: command.Description, HandlerFunc: func(param internal.HandlerFuncParams) ([]byte, error) { return nil, nil },
// Sync: command.Sync, SubCommands: make([]internal.SubCommand, len(command.SubCommand)),
// KeyExtractionFunc: func(cmd []string) (internal.KeyExtractionFuncResult, error) { }
// return internal.KeyExtractionFuncResult{}, nil
// }, for i, sc := range command.SubCommand {
// HandlerFunc: func(param internal.HandlerFuncParams) ([]byte, error) { return nil, nil }, // Skip the subcommand if it already exists in newCommand
// SubCommands: make([]internal.SubCommand, len(command.SubCommand)), if slices.ContainsFunc(newCommand.SubCommands, func(subcommand internal.SubCommand) bool {
// } return strings.EqualFold(subcommand.Command, sc.Command)
// }) {
// for i, sc := range command.SubCommand { continue
// // Skip the subcommand if it already exists in newCommand }
// if slices.ContainsFunc(newCommand.SubCommands, func(subcommand internal.SubCommand) bool { newCommand.SubCommands[i] = internal.SubCommand{
// return strings.EqualFold(subcommand.Command, sc.Command) Command: sc.Command,
// }) { Module: strings.ToLower(command.Module),
// continue Categories: func() []string {
// } // Convert all the categories to lower case for uniformity
// newCommand.SubCommands[i] = internal.SubCommand{ cats := make([]string, len(sc.Categories))
// Command: sc.Command, for j, cat := range sc.Categories {
// Module: strings.ToLower(command.Module), cats[j] = strings.ToLower(cat)
// Categories: func() []string { }
// // Convert all the categories to lower case for uniformity return cats
// cats := make([]string, len(sc.Categories)) }(),
// for j, cat := range sc.Categories { Description: sc.Description,
// cats[j] = strings.ToLower(cat) Sync: sc.Sync,
// } KeyExtractionFunc: internal.KeyExtractionFunc(func(cmd []string) (internal.KeyExtractionFuncResult, error) {
// return cats accessKeys, err := sc.KeyExtractionFunc(cmd)
// }(), if err != nil {
// Description: sc.Description, return internal.KeyExtractionFuncResult{}, err
// Sync: sc.Sync, }
// KeyExtractionFunc: internal.KeyExtractionFunc(func(cmd []string) (internal.KeyExtractionFuncResult, error) { return internal.KeyExtractionFuncResult{
// accessKeys, err := sc.KeyExtractionFunc(cmd) Channels: []string{},
// if err != nil { ReadKeys: accessKeys.ReadKeys,
// return internal.KeyExtractionFuncResult{}, err WriteKeys: accessKeys.WriteKeys,
// } }, nil
// return internal.KeyExtractionFuncResult{ }),
// Channels: []string{}, HandlerFunc: internal.HandlerFunc(func(params internal.HandlerFuncParams) ([]byte, error) {
// ReadKeys: accessKeys.ReadKeys, return sc.HandlerFunc(CommandHandlerFuncParams{
// WriteKeys: accessKeys.WriteKeys, Context: params.Context,
// }, nil Command: params.Command,
// }), KeysExist: params.KeysExist,
// HandlerFunc: internal.HandlerFunc(func(params internal.HandlerFuncParams) ([]byte, error) { GetValues: params.GetValues,
// return sc.HandlerFunc(CommandHandlerFuncParams{ SetValues: params.SetValues,
// Context: params.Context, })
// Command: params.Command, }),
// KeyLock: params.KeyLock, }
// KeyUnlock: params.KeyUnlock, }
// KeyRLock: params.KeyRLock,
// KeyRUnlock: params.KeyRUnlock, server.commands = append(server.commands, newCommand)
// KeyExists: params.KeyExists,
// CreateKeyAndLock: params.CreateKeyAndLock, return nil
// GetValue: params.GetValue, }
// SetValue: params.SetValue,
// })
// }),
// }
// }
//
// server.commands = append(server.commands, newCommand)
//
// return nil
// }
// ExecuteCommand executes the command passed to it. If 1 string is passed, EchoVault will try to // ExecuteCommand executes the command passed to it. If 1 string is passed, EchoVault will try to
// execute the command. If 2 strings are passed, EchoVault will attempt to execute the subcommand of the command. // execute the command. If 2 strings are passed, EchoVault will attempt to execute the subcommand of the command.

View File

@@ -159,14 +159,13 @@ func NewEchoVault(options ...func(echovault *EchoVault)) (*EchoVault, error) {
) )
// Load .so modules from config // Load .so modules from config
// TODO: Uncomment this for _, path := range echovault.config.Modules {
// for _, path := range echovault.config.Modules { if err := echovault.LoadModule(path); err != nil {
// if err := echovault.LoadModule(path); err != nil { log.Printf("%s %v\n", path, err)
// log.Printf("%s %v\n", path, err) continue
// continue }
// } log.Printf("loaded plugin %s\n", path)
// log.Printf("loaded plugin %s\n", path) }
// }
// Function for server commands retrieval // Function for server commands retrieval
echovault.getCommands = func() []internal.Command { echovault.getCommands = func() []internal.Command {

View File

@@ -40,14 +40,9 @@ func KeyExtractionFunc(cmd []string, args ...string) ([]string, []string, error)
func HandlerFunc( func HandlerFunc(
ctx context.Context, ctx context.Context,
command []string, command []string,
keyExists func(ctx context.Context, key string) bool, keysExist func(keys []string) map[string]bool,
keyLock func(ctx context.Context, key string) (bool, error), getValues func(ctx context.Context, keys []string) map[string]interface{},
keyUnlock func(ctx context.Context, key string), setValues func(ctx context.Context, entries map[string]interface{}) error,
keyRLock func(ctx context.Context, key string) (bool, error),
keyRUnlock func(ctx context.Context, key string),
createKeyAndLock func(ctx context.Context, key string) (bool, error),
getValue func(ctx context.Context, key string) interface{},
setValue func(ctx context.Context, key string, value interface{}) error,
args ...string) ([]byte, error) { args ...string) ([]byte, error) {
readKeys, _, err := KeyExtractionFunc(command, args...) readKeys, _, err := KeyExtractionFunc(command, args...)
@@ -55,18 +50,13 @@ func HandlerFunc(
return nil, err return nil, err
} }
key := readKeys[0] key := readKeys[0]
exists := keysExist(readKeys)[key]
if !keyExists(ctx, key) { if !exists {
return []byte(":0\r\n"), nil return []byte(":0\r\n"), nil
} }
_, err = keyRLock(ctx, key) val, ok := getValues(ctx, []string{key})[key].(int64)
if err != nil {
return nil, err
}
defer keyRUnlock(ctx, key)
val, ok := getValue(ctx, key).(int64)
if !ok { if !ok {
return nil, fmt.Errorf("value at key %s is not an integer", key) return nil, fmt.Errorf("value at key %s is not an integer", key)
} }

View File

@@ -40,14 +40,9 @@ func KeyExtractionFunc(cmd []string, args ...string) ([]string, []string, error)
func HandlerFunc( func HandlerFunc(
ctx context.Context, ctx context.Context,
command []string, command []string,
keyExists func(ctx context.Context, key string) bool, keysExist func(keys []string) map[string]bool,
keyLock func(ctx context.Context, key string) (bool, error), getValues func(ctx context.Context, keys []string) map[string]interface{},
keyUnlock func(ctx context.Context, key string), setValues func(ctx context.Context, entries map[string]interface{}) error,
keyRLock func(ctx context.Context, key string) (bool, error),
keyRUnlock func(ctx context.Context, key string),
createKeyAndLock func(ctx context.Context, key string) (bool, error),
getValue func(ctx context.Context, key string) interface{},
setValue func(ctx context.Context, key string, value interface{}) error,
args ...string) ([]byte, error) { args ...string) ([]byte, error) {
_, writeKeys, err := KeyExtractionFunc(command, args...) _, writeKeys, err := KeyExtractionFunc(command, args...)
@@ -56,25 +51,12 @@ func HandlerFunc(
} }
key := writeKeys[0] key := writeKeys[0]
if !keyExists(ctx, key) {
_, err := createKeyAndLock(ctx, key)
if err != nil {
return nil, err
}
} else {
_, err := keyLock(ctx, key)
if err != nil {
return nil, err
}
}
defer keyUnlock(ctx, key)
value, err := strconv.ParseInt(command[2], 10, 64) value, err := strconv.ParseInt(command[2], 10, 64)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = setValue(ctx, key, value) err = setValues(ctx, map[string]interface{}{key: value})
if err != nil { if err != nil {
return nil, err return nil, err
} }