about summary refs log tree commit diff
path: root/pkg/discord/rest.go
blob: 438d8d1c21c9dcc828cf9df2b43cff08c514e29c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package discord

import (
	"bytes"
	"encoding/json"
	"errors"
	"net/http"
	"time"
)

const DISCORD_URl = "https://discord.com/api/v9/"
const USER_AGENT = "DiscordBot (https://jinx.rnrd.eu/, v0.0.0) Jinx"

type REST interface {
	Gateway() (string, error)

	SendMessage(channelID Snowflake, content string) error
}

var _ REST = &RESTImpl{}

type RESTImpl struct {
	token  string
	client *http.Client
}

func NewREST(token string) *RESTImpl {
	return &RESTImpl{
		token: token,
		client: &http.Client{
			Timeout: time.Second * 5,
		},
	}
}

func (r *RESTImpl) Gateway() (string, error) {
	type gatewayResponse struct {
		URL string `json:"url"`
	}

	res, err := request[gatewayResponse](r, "GET", url("gateway"), nil)
	if err != nil {
		return "", err
	}

	return res.URL + "?v=9&encoding=json", nil
}

func (r *RESTImpl) SendMessage(channelID Snowflake, content string) error {
	msg := struct {
		Content string `json:"content"`
	}{
		Content: content,
	}

	_, err := request[any](r, "POST", url("channels/"+string(channelID)+"/messages"), msg)
	if err != nil {
		return err
	}

	return nil
}

func request[D any](r *RESTImpl, method string, url string, data any) (*D, error) {
	var raw []byte
	if data != nil {
		var err error
		raw, err = json.Marshal(data)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, url, bytes.NewBuffer(raw))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", r.token)
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("User-Agent", USER_AGENT)

	resp, err := r.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	switch resp.StatusCode {
	case 200:
	default:
		return nil, errors.New("unexpected status code: " + resp.Status)
	}

	var buf bytes.Buffer
	if _, err = buf.ReadFrom(resp.Body); err != nil {
		return nil, err
	}

	var res D
	if err = json.Unmarshal(buf.Bytes(), &res); err != nil {
		return nil, err
	}

	return &res, nil
}

func url(path string) string {
	return DISCORD_URl + path
}