diff --git a/src/modules/admin/commands.go b/src/modules/admin/commands.go index 46da288..4e80b00 100644 --- a/src/modules/admin/commands.go +++ b/src/modules/admin/commands.go @@ -8,8 +8,61 @@ import ( "net" ) +func handleGetAllCommands(ctx context.Context, cmd []string, server utils.Server, _ *net.Conn) ([]byte, error) { + commands := server.GetAllCommands(ctx) + + 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\r\n", commandCount, res) + + return []byte(res), nil +} + func Commands() []utils.Command { return []utils.Command{ + { + Command: "commands", + Categories: []string{utils.AdminCategory, utils.SlowCategory}, + Description: "Get a list of all the commands in available on the server with categories and descriptions", + Sync: false, + KeyExtractionFunc: func(cmd []string) ([]string, error) { return []string{}, nil }, + HandlerFunc: handleGetAllCommands, + }, { Command: "save", Categories: []string{utils.AdminCategory, utils.SlowCategory, utils.DangerousCategory}, diff --git a/src/modules/admin/commands_test.go b/src/modules/admin/commands_test.go new file mode 100644 index 0000000..a453519 --- /dev/null +++ b/src/modules/admin/commands_test.go @@ -0,0 +1,31 @@ +package admin + +import ( + "bytes" + "context" + "fmt" + "github.com/echovault/echovault/src/server" + "github.com/tidwall/resp" + "testing" +) + +func Test_CommandsHandler(t *testing.T) { + mockServer := server.NewServer(server.Opts{ + Commands: Commands(), + }) + + res, err := handleGetAllCommands(context.Background(), []string{"commands"}, mockServer, nil) + if err != nil { + t.Error(err) + } + + rd := resp.NewReader(bytes.NewReader(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + + for _, element := range rv.Array() { + fmt.Println(element) + } +} diff --git a/src/server/server.go b/src/server/server.go index 94f431c..5002372 100644 --- a/src/server/server.go +++ b/src/server/server.go @@ -225,8 +225,29 @@ func (server *Server) handleConnection(ctx context.Context, conn net.Conn) { continue } - if _, err = w.Write(res); err != nil { - log.Println(err) + chunkSize := 1024 + + if len(res) <= chunkSize { + _, err = w.Write(res) + if err != nil { + log.Println(err) + } + continue + } + + // If the response is large, send it in chunks. + startIndex := 0 + for { + // If the current start index is less than chunkSize from length, return the remaining bytes. + if len(res)-1-startIndex < chunkSize { + _, _ = w.Write(res[startIndex:]) + break + } + n, _ := w.Write(res[startIndex : startIndex+chunkSize]) + if n < chunkSize { + break + } + startIndex += chunkSize } }