summaryrefslogtreecommitdiffstats
path: root/bridge/matrix/helpers.go
diff options
context:
space:
mode:
authorSimon THOBY <git@nightmared.fr>2020-11-22 15:57:41 +0100
committerGitHub <noreply@github.com>2020-11-22 15:57:41 +0100
commit1a3c57a031acfd99f9a6882478f866d249f9d39d (patch)
treed6203d045a025cc9b44ade17710a4b77f3e38e9a /bridge/matrix/helpers.go
parent4cc2c914e634eb8c79eb61aa1bc29faf6021ffcf (diff)
downloadmatterbridge-msglm-1a3c57a031acfd99f9a6882478f866d249f9d39d.tar.gz
matterbridge-msglm-1a3c57a031acfd99f9a6882478f866d249f9d39d.tar.bz2
matterbridge-msglm-1a3c57a031acfd99f9a6882478f866d249f9d39d.zip
Send the display name instead of the user name (matrix) (#1282)
* matrix: send the display name (the nickname in matrix parlance) instead of the user name There is also the option UseUserName (already in use by the discord bridge) to turn back to the old behavior. * matrix: update displayNames on join events * matrix: introduce a helper.go file to keep matrix.go size reasonable
Diffstat (limited to 'bridge/matrix/helpers.go')
-rw-r--r--bridge/matrix/helpers.go166
1 files changed, 166 insertions, 0 deletions
diff --git a/bridge/matrix/helpers.go b/bridge/matrix/helpers.go
new file mode 100644
index 00000000..91aea805
--- /dev/null
+++ b/bridge/matrix/helpers.go
@@ -0,0 +1,166 @@
+package bmatrix
+
+import (
+ "encoding/json"
+ "errors"
+ "html"
+ "strings"
+ "time"
+
+ matrix "github.com/matrix-org/gomatrix"
+)
+
+func newMatrixUsername(username string) *matrixUsername {
+ mUsername := new(matrixUsername)
+
+ // check if we have a </tag>. if we have, we don't escape HTML. #696
+ if htmlTag.MatchString(username) {
+ mUsername.formatted = username
+ // remove the HTML formatting for beautiful push messages #1188
+ mUsername.plain = htmlReplacementTag.ReplaceAllString(username, "")
+ } else {
+ mUsername.formatted = html.EscapeString(username)
+ mUsername.plain = username
+ }
+
+ return mUsername
+}
+
+// getRoomID retrieves a matching room ID from the channel name.
+func (b *Bmatrix) getRoomID(channel string) string {
+ b.RLock()
+ defer b.RUnlock()
+ for ID, name := range b.RoomMap {
+ if name == channel {
+ return ID
+ }
+ }
+
+ return ""
+}
+
+// interface2Struct marshals and immediately unmarshals an interface.
+// Useful for converting map[string]interface{} to a struct.
+func interface2Struct(in interface{}, out interface{}) error {
+ jsonObj, err := json.Marshal(in)
+ if err != nil {
+ return err //nolint:wrapcheck
+ }
+
+ return json.Unmarshal(jsonObj, out)
+}
+
+// getDisplayName retrieves the displayName for mxid, querying the homserver if the mxid is not in the cache.
+func (b *Bmatrix) getDisplayName(mxid string) string {
+ if b.GetBool("UseUserName") {
+ return mxid[1:]
+ }
+
+ b.RLock()
+ if val, present := b.NicknameMap[mxid]; present {
+ b.RUnlock()
+
+ return val.displayName
+ }
+ b.RUnlock()
+
+ displayName, err := b.mc.GetDisplayName(mxid)
+ var httpError *matrix.HTTPError
+ if errors.As(err, &httpError) {
+ b.Log.Warnf("Couldn't retrieve the display name for %s", mxid)
+ }
+
+ if err != nil {
+ return b.cacheDisplayName(mxid, mxid[1:])
+ }
+
+ return b.cacheDisplayName(mxid, displayName.DisplayName)
+}
+
+// cacheDisplayName stores the mapping between a mxid and a display name, to be reused later without performing a query to the homserver.
+// Note that old entries are cleaned when this function is called.
+func (b *Bmatrix) cacheDisplayName(mxid string, displayName string) string {
+ now := time.Now()
+
+ // scan to delete old entries, to stop memory usage from becoming too high with old entries
+ toDelete := []string{}
+ b.RLock()
+ for k, v := range b.NicknameMap {
+ if now.Sub(v.lastUpdated) > 10*time.Minute {
+ toDelete = append(toDelete, k)
+ }
+ }
+ b.RUnlock()
+
+ b.Lock()
+ for _, v := range toDelete {
+ delete(b.NicknameMap, v)
+ }
+ b.NicknameMap[mxid] = NicknameCacheEntry{
+ displayName: displayName,
+ lastUpdated: now,
+ }
+ b.Unlock()
+
+ return displayName
+}
+
+// handleError converts errors into httpError.
+//nolint:exhaustivestruct
+func handleError(err error) *httpError {
+ var mErr matrix.HTTPError
+ if !errors.As(err, &mErr) {
+ return &httpError{
+ Err: "not a HTTPError",
+ }
+ }
+
+ var httpErr httpError
+
+ if err := json.Unmarshal(mErr.Contents, &httpErr); err != nil {
+ return &httpError{
+ Err: "unmarshal failed",
+ }
+ }
+
+ return &httpErr
+}
+
+func (b *Bmatrix) containsAttachment(content map[string]interface{}) bool {
+ // Skip empty messages
+ if content["msgtype"] == nil {
+ return false
+ }
+
+ // Only allow image,video or file msgtypes
+ if !(content["msgtype"].(string) == "m.image" ||
+ content["msgtype"].(string) == "m.video" ||
+ content["msgtype"].(string) == "m.file") {
+ return false
+ }
+
+ return true
+}
+
+// getAvatarURL returns the avatar URL of the specified sender.
+func (b *Bmatrix) getAvatarURL(sender string) string {
+ urlPath := b.mc.BuildURL("profile", sender, "avatar_url")
+
+ s := struct {
+ AvatarURL string `json:"avatar_url"`
+ }{}
+
+ err := b.mc.MakeRequest("GET", urlPath, nil, &s)
+ if err != nil {
+ b.Log.Errorf("getAvatarURL failed: %s", err)
+
+ return ""
+ }
+
+ url := strings.ReplaceAll(s.AvatarURL, "mxc://", b.GetString("Server")+"/_matrix/media/r0/thumbnail/")
+ if url != "" {
+ url += "?width=37&height=37&method=crop"
+ }
+
+ return url
+}