summaryrefslogtreecommitdiffstats
path: root/bridge/discord/webhook.go
blob: b518ea62622d0957f68b1b808237bf92c58fbb04 (plain) (blame)
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package bdiscord

import (
	"bytes"

	"github.com/42wim/matterbridge/bridge/config"
	"github.com/42wim/matterbridge/bridge/helper"
	"github.com/bwmarrin/discordgo"
)

// shouldMessageUseWebhooks checks if have a channel specific webhook, if we're not using auto webhooks
func (b *Bdiscord) shouldMessageUseWebhooks(msg *config.Message) bool {
	if b.useAutoWebhooks {
		return true
	}

	b.channelsMutex.RLock()
	defer b.channelsMutex.RUnlock()
	if ci, ok := b.channelInfoMap[msg.Channel+b.Account]; ok {
		if ci.Options.WebhookURL != "" {
			return true
		}
	}
	return false
}

// maybeGetLocalAvatar checks if UseLocalAvatar contains the message's
// account or protocol, and if so, returns the Discord avatar (if exists)
func (b *Bdiscord) maybeGetLocalAvatar(msg *config.Message) string {
	for _, val := range b.GetStringSlice("UseLocalAvatar") {
		if msg.Protocol != val && msg.Account != val {
			continue
		}

		member, err := b.getGuildMemberByNick(msg.Username)
		if err != nil {
			return ""
		}

		return member.User.AvatarURL("")
	}
	return ""
}

// webhookSend send one or more message via webhook, taking care of file
// uploads (from slack, telegram or mattermost).
// Returns messageID and error.
func (b *Bdiscord) webhookSend(msg *config.Message, channelID string) (*discordgo.Message, error) {
	var (
		res  *discordgo.Message
		res2 *discordgo.Message
		err  error
	)

	// If avatar is unset, mutate the message to include the local avatar (but only if settings say we should do this)
	if msg.Avatar == "" {
		msg.Avatar = b.maybeGetLocalAvatar(msg)
	}

	// WebhookParams can have either `Content` or `File`.

	// We can't send empty messages.
	if msg.Text != "" {
		res, err = b.transmitter.Send(
			channelID,
			&discordgo.WebhookParams{
				Content:         msg.Text,
				Username:        msg.Username,
				AvatarURL:       msg.Avatar,
				AllowedMentions: b.getAllowedMentions(),
			},
		)
		if err != nil {
			b.Log.Errorf("Could not send text (%s) for message %#v: %s", msg.Text, msg, err)
		}
	}

	if msg.Extra != nil {
		for _, f := range msg.Extra["file"] {
			fi := f.(config.FileInfo)
			file := discordgo.File{
				Name:        fi.Name,
				ContentType: "",
				Reader:      bytes.NewReader(*fi.Data),
			}
			content := fi.Comment

			res2, err = b.transmitter.Send(
				channelID,
				&discordgo.WebhookParams{
					Username:        msg.Username,
					AvatarURL:       msg.Avatar,
					Files:           []*discordgo.File{&file},
					Content:         content,
					AllowedMentions: b.getAllowedMentions(),
				},
			)
			if err != nil {
				b.Log.Errorf("Could not send file %#v for message %#v: %s", file, msg, err)
			}
		}
	}

	if msg.Text == "" {
		res = res2
	}

	return res, err
}

func (b *Bdiscord) handleEventWebhook(msg *config.Message, channelID string) (string, error) {
	// skip events
	if msg.Event != "" && msg.Event != config.EventUserAction && msg.Event != config.EventJoinLeave && msg.Event != config.EventTopicChange {
		return "", nil
	}

	// skip empty messages
	if msg.Text == "" && (msg.Extra == nil || len(msg.Extra["file"]) == 0) {
		b.Log.Debugf("Skipping empty message %#v", msg)
		return "", nil
	}

	msg.Text = helper.ClipMessage(msg.Text, MessageLength, b.GetString("MessageClipped"))
	msg.Text = b.replaceUserMentions(msg.Text)
	// discord username must be [0..32] max
	if len(msg.Username) > 32 {
		msg.Username = msg.Username[0:32]
	}

	if msg.ID != "" {
		b.Log.Debugf("Editing webhook message")
		err := b.transmitter.Edit(channelID, msg.ID, &discordgo.WebhookParams{
			Content:         msg.Text,
			Username:        msg.Username,
			AllowedMentions: b.getAllowedMentions(),
		})
		if err == nil {
			return msg.ID, nil
		}
		b.Log.Errorf("Could not edit webhook message: %s", err)
	}

	b.Log.Debugf("Processing webhook sending for message %#v", msg)
	discordMsg, err := b.webhookSend(msg, channelID)
	if err != nil {
		b.Log.Errorf("Could not broadcast via webhook for message %#v: %s", msg, err)
		return "", err
	}
	if discordMsg == nil {
		return "", nil
	}

	return discordMsg.ID, nil
}