all repos

viye @ cf8afd92aed2f4da2448c272cbbb65f19b460f5b

my shot at reimplementing xiki

viye/internal/plumbing/http/http.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
add http tool, 1 month ago
1
package http
2
3
import (
4
	"context"
5
	"errors"
6
	"fmt"
7
	"io"
8
	"net/http"
9
	"strings"
10
	"time"
11
12
	"github.com/olexsmir/viye/internal/viye"
13
)
14
15
// get http://localhost
16
//	: Header: Value
17
//	: Header2: value
18
//	: {"json": "body"}
19
20
const timeout = 5 * time.Second
21
22
type Tool struct{}
23
24
func (Tool) Name() string { return "http(get, post, put, patch, delete)" }
25
func (Tool) Match(c *viye.Context) bool {
26
	return (c.Cmd == "get" || c.Cmd == "post" || c.Cmd == "put" || c.Cmd == "patch" || c.Cmd == "delete")
27
}
28
29
func (Tool) Execute(c *viye.Context) (string, error) {
30
	if len(c.Args) < 1 || !isURL(c.Args[0]) {
31
		return "", errors.New("please provide an url")
32
	}
33
34
	headers, body, err := parseBody(viye.ParseData(c.Body))
35
	if err != nil {
36
		return "", fmt.Errorf("body parsing error: %v", err)
37
	}
38
39
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
40
	defer cancel()
41
42
	req, err := http.NewRequestWithContext(ctx, cmdToMethod(c.Cmd), c.Args[0], strings.NewReader(body))
43
	if err != nil {
44
		return "", fmt.Errorf("failed to create request: %v", err)
45
	}
46
	for header, value := range headers {
47
		req.Header.Set(header, value)
48
	}
49
50
	resp, err := (&http.Client{Timeout: timeout}).Do(req)
51
	if err != nil {
52
		return "", fmt.Errorf("failed to make a request: %v", err)
53
	}
54
55
	respBody, _ := io.ReadAll(resp.Body)
56
	out := fmt.Sprintf("%d\t%s", resp.StatusCode, respBody)
57
	return viye.FormatOutput(out), nil
58
}
59
60
func parseBody(inp []string) (headers map[string]string, body string, err error) {
61
	if len(inp) == 0 {
62
		return nil, "", nil
63
	}
64
	headers = make(map[string]string)
65
66
	for _, line := range inp {
67
		key, val, ok := strings.Cut(line, ": ")
68
		if ok {
69
			headers[key] = val
70
		}
71
	}
72
73
	last := inp[len(inp)-1]
74
	if _, _, ok := strings.Cut(last, ": "); !ok {
75
		body = last
76
	}
77
78
	return headers, body, nil
79
}
80
81
func isURL(u string) bool {
82
	return strings.HasPrefix(u, "http://") || strings.HasPrefix(u, "https://")
83
}
84
85
func cmdToMethod(c string) string {
86
	switch c {
87
	case "get":
88
		return http.MethodGet
89
	case "post":
90
		return http.MethodPost
91
	case "put":
92
		return http.MethodPut
93
	case "patch":
94
		return http.MethodPatch
95
	case "delete":
96
		return http.MethodDelete
97
	default:
98
		panic("unreachable")
99
	}
100
}