-
Notifications
You must be signed in to change notification settings - Fork 61
/
discord.go
131 lines (105 loc) · 3.28 KB
/
discord.go
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package discord
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
"github.com/containrrr/shoutrrr/pkg/format"
"github.com/containrrr/shoutrrr/pkg/services/standard"
"github.com/containrrr/shoutrrr/pkg/types"
"github.com/containrrr/shoutrrr/pkg/util"
)
// Service providing Discord as a notification service
type Service struct {
standard.Standard
config *Config
pkr format.PropKeyResolver
}
var limits = types.MessageLimit{
ChunkSize: 2000,
TotalChunkSize: 6000,
ChunkCount: 10,
}
const (
hookURL = "https://discord.com/api/webhooks"
// Only search this many runes for a good split position
maxSearchRunes = 100
)
// Send a notification message to discord
func (service *Service) Send(message string, params *types.Params) (err error) {
if service.config.JSON {
postURL := CreateAPIURLFromConfig(service.config)
err = doSend([]byte(message), postURL)
} else {
items, omitted := CreateItemsFromPlain(message, service.config.SplitLines)
err = service.sendItems(items, params, omitted)
}
if err != nil {
err = fmt.Errorf("failed to send discord notification: %v", err)
}
return
}
// SendItems sends items with additional meta data and richer appearance
func (service *Service) SendItems(items []types.MessageItem, params *types.Params) error {
return service.sendItems(items, params, 0)
}
func (service *Service) sendItems(items []types.MessageItem, params *types.Params, omitted int) error {
var err error
config := *service.config
if err = service.pkr.UpdateConfigFromParams(&config, params); err != nil {
return err
}
var payload WebhookPayload
payload, err = CreatePayloadFromItems(items, config.Title, config.LevelColors(), omitted)
if err != nil {
return err
}
payload.Username = config.Username
payload.AvatarURL = config.Avatar
var payloadBytes []byte
payloadBytes, err = json.Marshal(payload)
if err != nil {
return err
}
postURL := CreateAPIURLFromConfig(&config)
return doSend(payloadBytes, postURL)
}
// CreateItemsFromPlain creates a set of MessageItems that is compatible with Discords webhook payload
func CreateItemsFromPlain(plain string, splitLines bool) (items []types.MessageItem, omitted int) {
if splitLines {
return util.MessageItemsFromLines(plain, limits)
}
return util.PartitionMessage(plain, limits, maxSearchRunes)
}
// Initialize loads ServiceConfig from configURL and sets logger for this Service
func (service *Service) Initialize(configURL *url.URL, logger types.StdLogger) error {
service.Logger.SetLogger(logger)
service.config = &Config{}
service.pkr = format.NewPropKeyResolver(service.config)
if err := service.pkr.SetDefaultProps(service.config); err != nil {
return err
}
if err := service.config.SetURL(configURL); err != nil {
return err
}
return nil
}
// CreateAPIURLFromConfig takes a discord config object and creates a post url
func CreateAPIURLFromConfig(config *Config) string {
return fmt.Sprintf(
"%s/%s/%s",
hookURL,
config.WebhookID,
config.Token)
}
func doSend(payload []byte, postURL string) error {
res, err := http.Post(postURL, "application/json", bytes.NewBuffer(payload))
if res == nil && err == nil {
err = fmt.Errorf("unknown error")
}
if err == nil && res.StatusCode != http.StatusNoContent {
err = fmt.Errorf("response status code %s", res.Status)
}
return err
}