diff --git a/pkg/es/repl.go b/pkg/es/repl.go index b9a6404..c3b357d 100644 --- a/pkg/es/repl.go +++ b/pkg/es/repl.go @@ -17,6 +17,7 @@ along with this program. If not, see . package es import ( + "bufio" "bytes" "context" "crypto/tls" @@ -34,19 +35,98 @@ import ( "github.com/chzyer/readline" ) +const intro = `Input format: verb path [data]" + +Example: + +post /yourindex/_ccr/pause_follow +put /yourindex/_settings {"number_of_replicas": 1} + +You can also put multiline JSON after the path like: + +put /yourindex/_settings +{ + "number_of_replicas": 1 +} + +If you do NOT supply a JSON in the first line, you need to hit ENTER +twice to complete.` + +func Repl(conf *cfg.Config) error { + verbs := []string{"post", "get", "put", "delete"} + + fmt.Println(intro) + fmt.Println() + + reader, err := readline.NewEx(&readline.Config{ + Prompt: "> ", + HistoryFile: os.Getenv("HOME") + "/.config/esctl/history", + HistoryLimit: 500, + InterruptPrompt: "^C", + EOFPrompt: "exit", + HistorySearchFold: true, + }) + + if err != nil { + return fmt.Errorf("failed to initialize readline lib: %s", err) + } + + for { + text, err := reader.Readline() + if err != nil { + break + } + + text = strings.TrimSpace(text) + + if text == "" { + continue + } + + parts := strings.SplitN(strings.TrimSpace(text), " ", 3) + if len(parts) < 2 { + fmt.Println("error: you need to input a verb, uri [and post data]") + continue + } + + if !slices.Contains(verbs, strings.ToLower(parts[0])) { + fmt.Println("error: verb must be one of " + strings.Join(verbs, ",")) + continue + } + + if !strings.HasPrefix(parts[1], "/") { + parts[1] = "/" + parts[1] + } + + json := "" + if len(parts) == 3 { + // put /uri {json} + json = parts[2] + } + + // put /uri/ [json] + data, err := readJSON(json) + if err != nil { + fmt.Println(err) + } + + err = CallAPI(conf, parts[0], parts[1], data) + if err != nil { + fmt.Printf("failed to call API: %s\n", err) + } + + reader.SetPrompt("> ") + } + + return nil +} + func encodeAuth(username, password string) string { return base64.StdEncoding.EncodeToString([]byte(username + ":" + password)) } -func CallAPI(conf *cfg.Config, input []string) error { - var data string - - verb := strings.ToUpper(input[0]) - path := input[1] - - if len(input) == 3 { - data = input[2] - } +func CallAPI(conf *cfg.Config, verb, path, data string) error { + verb = strings.ToUpper(verb) // we're using port-forwards anyway tr := &http.Transport{ @@ -108,69 +188,37 @@ func prettyfiJson(conf *cfg.Config, raw []byte) error { return nil } -func Repl(conf *cfg.Config) error { - verbs := []string{"post", "get", "put", "delete"} +// interactively read arbitrary JSON data from STDIN, which is +// virtually a repl inside the primary repl +func readJSON(input string) (string, error) { + data := "" - fmt.Println("Input format: verb path [data]") - fmt.Println("example: post /yourindex/_ccr/pause_follow") + if input != "" { + data = input + } else { + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) - reader, err := readline.NewEx(&readline.Config{ - Prompt: "> ", - HistoryFile: os.Getenv("HOME") + "/.config/esctl/history", - HistoryLimit: 500, - InterruptPrompt: "^C", - EOFPrompt: "exit", - HistorySearchFold: true, - }) - - if err != nil { - return fmt.Errorf("failed to initialize readline lib: %s", err) - } - - for { - text, err := reader.Readline() - if err != nil { - break - } - - text = strings.TrimSpace(text) - - if text == "" { - continue - } - - parts := strings.SplitN(strings.TrimSpace(text), " ", 3) - if len(parts) < 2 { - fmt.Println("error: you need to input a verb, uri [and post data]") - continue - } - - if !slices.Contains(verbs, strings.ToLower(parts[0])) { - fmt.Println("error: verb must be one of " + strings.Join(verbs, ",")) - continue - } - - if !strings.HasPrefix(parts[1], "/") { - fmt.Println("error: url path must start with /") - continue - } - - if len(parts) == 3 { - data := map[string]any{} - err := json.Unmarshal([]byte(parts[2]), &data) - if err != nil { - fmt.Printf("error: input data is not proper JSON: %s", err) - continue + if line == "" { + break } - } - err = CallAPI(conf, parts) - if err != nil { - fmt.Printf("failed to call API: %s\n", err) + data += line } - - reader.SetPrompt("> ") } - return nil + if data == "" { + return data, nil + } + + // validate + check := map[string]any{} + err := json.Unmarshal([]byte(data), &check) + if err != nil { + return "", fmt.Errorf("error: input data is not proper JSON: %s", err) + + } + + return data, nil }