Thumbnail

rani/matterbridge.git

Clone URL: https://git.buni.party/rani/matterbridge.git

commit 1943998fec067c139899400b4b3adb0fc46b70fb Author: Joseph Crowell <joseph.w.crowell@gmail.com> Date: Sat Dec 13 02:26:33 2025 +0000 make linter happy diff --git a/bridge/matrix/helpers.go b/bridge/matrix/helpers.go index 5e2b66e..2b5acdc 100644 --- a/bridge/matrix/helpers.go +++ b/bridge/matrix/helpers.go @@ -5321 +5323 @@ func interface2Struct(in interface{}, out interface{}) error {  }    // getDisplayName retrieves the displayName for mxid, querying the homeserver if the mxid is not in the cache. -func (b *Bmatrix) getDisplayName(mxid id.UserID) string { +func (b *Bmatrix) getDisplayName(ctx context.Context, mxid id.UserID) string {   // Localpart is the user name. Return it if UseUserName is set.   if b.GetBool("UseUserName") {   return mxid.Localpart()   }     b.RLock() +   if val, present := b.NicknameMap[mxid.Localpart()]; present {   b.RUnlock()     return val.displayName   } +   b.RUnlock()   - resp, err := b.mc.GetDisplayName(context.TODO(), mxid) + resp, err := b.mc.GetDisplayName(ctx, mxid)   if err != nil {   b.Log.Errorf("Retrieving the display name for %s failed: %s", mxid, err)   @@ -896 +917 @@ func (b *Bmatrix) cacheDisplayName(mxid id.UserID, displayName string) string {   conflict := false     b.Lock() +   for localpart, v := range b.NicknameMap {   // to prevent username reuse across matrix servers - or even on the same server, append   // the mxid to the username when there is a conflict @@ -1628 +1658 @@ func (b *Bmatrix) containsAttachment(content map[string]interface{}) bool {  }    // getAvatarURL returns the avatar URL of the specified sender. -func (b *Bmatrix) getAvatarURL(sender id.UserID) string { - urlPath, err := b.mc.GetAvatarURL(context.TODO(), sender) +func (b *Bmatrix) getAvatarURL(ctx context.Context, sender id.UserID) string { + urlPath, err := b.mc.GetAvatarURL(ctx, sender)   if err != nil {   b.Log.Errorf("getAvatarURL failed: %s", err)   diff --git a/bridge/matrix/matrix.go b/bridge/matrix/matrix.go index fe1ce4f..0f8985b 100644 --- a/bridge/matrix/matrix.go +++ b/bridge/matrix/matrix.go @@ -709 +7010 @@ type MessageRelation struct {  }    type EditedMessage struct { + event.MessageEventContent +   NewContent SubTextMessage `json:"m.new_content"`   RelatedTo MessageRelation `json:"m.relates_to"` - event.MessageEventContent  }    type InReplyToRelationContent struct { @@ -848 +859 @@ type InReplyToRelation struct {  }    type ReplyMessage struct { - RelatedTo InReplyToRelation `json:"m.relates_to"`   event.MessageEventContent + + RelatedTo InReplyToRelation `json:"m.relates_to"`  }    func New(cfg *bridge.Config) bridge.Bridger { @@ -10112 +10314 @@ func (b *Bmatrix) Connect() error {     if b.GetString("MxID") != "" && b.GetString("Token") != "" {   userID := id.NewUserID(b.GetString("MxID"), b.GetString("Server")) +   b.mc, err = mautrix.NewClient(   b.GetString("Server"), userID, b.GetString("Token"),   )   if err != nil {   return err   } +   b.UserID = userID   b.AccessToken = b.GetString("Token")   b.Log.Info("Using existing Matrix credentials") @@ -1157 +1198 @@ func (b *Bmatrix) Connect() error {   if err != nil {   return err   } - resp, err := b.mc.Login( + + resp, err2 := b.mc.Login(   context.TODO(),   &mautrix.ReqLogin{   Type: mautrix.AuthTypePassword, @@ -1248 +1298 @@ func (b *Bmatrix) Connect() error {   StoreCredentials: true,   },   ) - if err != nil { - return err + if err2 != nil { + return err2   }   b.UserID = resp.UserID   b.AccessToken = resp.AccessToken @@ -1346 +1397 @@ func (b *Bmatrix) Connect() error {   // BEGIN CACHED MESSAGES FIX   **/   var initialSyncComplete = false +   accountStore := mautrix.NewAccountDataStore("org.example.mybot.synctoken", b.mc)   b.mc.Store = accountStore   @@ -1526 +1587 @@ func (b *Bmatrix) Connect() error {   if err != nil {   b.Log.Fatalf("Failed to create filter: %v", err)   } +   filterID := filterResponse.FilterID     err = b.mc.Store.SaveFilterID(context.Background(), b.UserID, filterID) @@ -1647 +1717 @@ func (b *Bmatrix) Connect() error {   b.Log.Fatalf("Failed to save initial sync token: %v", err)   }   - syncer := b.mc.Syncer.(*mautrix.DefaultSyncer) + syncer := b.mc.Syncer.(*mautrix.DefaultSyncer) //nolint:forcetypeassert // We're only using DefaultSyncer   syncer.OnEventType(event.EventMessage, func(ctx context.Context, evt *event.Event) {   // Check if we are still in the initial sync phase   if !initialSyncComplete { @@ -1806 +1877 @@ func (b *Bmatrix) Connect() error {   if syncErr != nil {   b.Log.Debugf("Sync() returned %v, retrying in 5 seconds...\n", syncErr)   time.Sleep(time.Second * 5) +   continue   }   @@ -4817 +4897 @@ func (b *Bmatrix) NewHttpRequest(method, uri string, body io.Reader) (*http.Requ  }    func (b *Bmatrix) handlematrix() { - syncer := b.mc.Syncer.(*mautrix.DefaultSyncer) + syncer := b.mc.Syncer.(*mautrix.DefaultSyncer) //nolint:forcetypeassert // We're only using DefaultSyncer   syncer.OnEventType(event.EventRedaction, b.handleRedactionEvent)   syncer.OnEventType(event.EventMessage, b.handleMessageEvent)   syncer.OnEventType(event.StateMember, b.handleMemberChange) @@ -5426 +5507 @@ func (b *Bmatrix) handleReply(ev *event.Event, rmsg config.Message) bool {   }     rmsg.Text = body +   rmsg.ParentID = relation.InReplyTo.EventID.String()   b.Remote <- rmsg   @@ -579144 +588164 @@ func (b *Bmatrix) handleMemberChange(ctx context.Context, ev *event.Event) {   }  }   +//nolint:funlen // This function is necessarily long because it is an event handler  func (b *Bmatrix) handleRedactionEvent(ctx context.Context, ev *event.Event) {   b.Log.Debugf("== Receiving redaction event: %#v", ev) - if ev.Sender != b.UserID { - b.RLock() - channel, ok := b.RoomMap[ev.RoomID] - b.RUnlock() - if !ok { - b.Log.Debugf("Unknown room %s", ev.RoomID) - return - }   - // Create our message - rmsg := config.Message{ - Username: b.getDisplayName(ev.Sender), - Channel: channel, - Account: b.Account, - UserID: ev.Sender.String(), - ID: ev.ID.String(), - Avatar: b.getAvatarURL(ev.Sender), - } + if ev.Sender == b.UserID { + return + }   - // Remove homeserver suffix if configured - if b.GetBool("NoHomeServerSuffix") { - re := regexp.MustCompile(`\s+\(@.*`) - rmsg.Username = re.ReplaceAllString(rmsg.Username, `$1`) - } + b.RLock() + channel, ok := b.RoomMap[ev.RoomID] + b.RUnlock()   - // Delete event - if ev.Type == event.EventRedaction { - rmsg.Event = config.EventMsgDelete - rmsg.ID = ev.Redacts.String() - rmsg.Text = config.EventMsgDelete - b.Remote <- rmsg - return - } + if !ok { + b.Log.Debugf("Unknown room %s", ev.RoomID) + return + }   - // Text must be a string - if rmsg.Text, ok = ev.Content.GetRaw()["body"].(string); !ok { - contentBytes, err := json.Marshal(ev) - if err != nil { - b.Log.Errorf("Error marshalling event content to JSON: %v", err) - return - } + // Create our message + rmsg := config.Message{ + Username: b.getDisplayName(ctx, ev.Sender), + Channel: channel, + Account: b.Account, + UserID: ev.Sender.String(), + ID: ev.ID.String(), + Avatar: b.getAvatarURL(ctx, ev.Sender), + }   - eventString := string(contentBytes) + // Remove homeserver suffix if configured + if b.GetBool("NoHomeServerSuffix") { + re := regexp.MustCompile(`\s+\(@.*`) + rmsg.Username = re.ReplaceAllString(rmsg.Username, `$1`) + }   - b.Log.Errorf("Content[body] is not a string: %T\n%#v", ev.Content.GetRaw()["body"], eventString) - return - } + // Delete event + if ev.Type == event.EventRedaction { + rmsg.Event = config.EventMsgDelete + rmsg.ID = ev.Redacts.String()   - b.Log.Debugf("<= Sending message from %s on %s to gateway", ev.Sender, b.Account) + rmsg.Text = config.EventMsgDelete   b.Remote <- rmsg   - // not crucial, so no ratelimit check here - if err := b.mc.MarkRead(context.TODO(), ev.RoomID, ev.ID); err != nil { - b.Log.Errorf("couldn't mark message as read %s", err.Error()) + return + } + + // Text must be a string + if rmsg.Text, ok = ev.Content.GetRaw()["body"].(string); !ok { + contentBytes, err := json.Marshal(ev) + if err != nil { + b.Log.Errorf("Error marshalling event content to JSON: %v", err) + return   } + + eventString := string(contentBytes) + + b.Log.Errorf("Content[body] is not a string: %T\n%#v", ev.Content.GetRaw()["body"], eventString) + + return + } + + b.Log.Debugf("<= Sending message from %s on %s to gateway", ev.Sender, b.Account) + + b.Remote <- rmsg + + // not crucial, so no ratelimit check here + err := b.mc.MarkRead(ctx, ev.RoomID, ev.ID) + if err != nil { + b.Log.Errorf("couldn't mark message as read %s", err.Error())   }  }   +//nolint:funlen // This function is necessarily long because it is an event handler  func (b *Bmatrix) handleMessageEvent(ctx context.Context, ev *event.Event) {   b.Log.Debugf("== Receiving message event: %#v", ev) - if ev.Sender != b.UserID { - b.RLock() - channel, ok := b.RoomMap[ev.RoomID] - b.RUnlock() - if !ok { - b.Log.Debugf("Unknown room %s", ev.RoomID) - return - }   - // Create our message - rmsg := config.Message{ - Username: b.getDisplayName(ev.Sender), - Channel: channel, - Account: b.Account, - UserID: ev.Sender.String(), - ID: ev.ID.String(), - Avatar: b.getAvatarURL(ev.Sender), - } + if ev.Sender == b.UserID { + return + }   - // Remove homeserver suffix if configured - if b.GetBool("NoHomeServerSuffix") { - re := regexp.MustCompile(`\s+\(@.*`) - rmsg.Username = re.ReplaceAllString(rmsg.Username, `$1`) - } + b.RLock() + channel, ok := b.RoomMap[ev.RoomID] + b.RUnlock()   - // Delete event as a relation - if ev.Unsigned.RedactedBecause != nil { - rmsg.Event = config.EventMsgDelete - rmsg.ID = ev.Unsigned.RedactedBecause.Redacts.String() - rmsg.Text = config.EventMsgDelete - b.Remote <- rmsg - return - } + if !ok { + b.Log.Debugf("Unknown room %s", ev.RoomID) + return + }   - // Text must be a string - if rmsg.Text, ok = ev.Content.GetRaw()["body"].(string); !ok { - contentBytes, err := json.Marshal(ev) - if err != nil { - b.Log.Errorf("Error marshalling event content to JSON: %v", err) - return - } + // Create our message + rmsg := config.Message{ + Username: b.getDisplayName(ctx, ev.Sender), + Channel: channel, + Account: b.Account, + UserID: ev.Sender.String(), + ID: ev.ID.String(), + Avatar: b.getAvatarURL(ctx, ev.Sender), + }   - eventString := string(contentBytes) + // Remove homeserver suffix if configured + if b.GetBool("NoHomeServerSuffix") { + re := regexp.MustCompile(`\s+\(@.*`) + rmsg.Username = re.ReplaceAllString(rmsg.Username, `$1`) + }   - b.Log.Errorf("Content[body] is not a string: %T\n%#v", ev.Content.GetRaw()["body"], eventString) - return - } + // Delete event as a relation + if ev.Unsigned.RedactedBecause != nil { + rmsg.Event = config.EventMsgDelete + rmsg.ID = ev.Unsigned.RedactedBecause.Redacts.String()   - // Do we have a /me action - if ev.Content.AsMessage().MsgType == event.MsgEmote { - rmsg.Event = config.EventUserAction - } + rmsg.Text = config.EventMsgDelete + b.Remote <- rmsg   - // Is it an edit? - if b.handleEdit(ev, rmsg) { - return - } + return + }   - // Is it a reply? - if b.handleReply(ev, rmsg) { + // Text must be a string + if rmsg.Text, ok = ev.Content.GetRaw()["body"].(string); !ok { + contentBytes, err := json.Marshal(ev) + if err != nil { + b.Log.Errorf("Error marshalling event content to JSON: %v", err)   return   }   - // Do we have an attachment - // TODO: does matrix support multiple attachments? - if b.handleAttachment(ev, rmsg) { - return - } + eventString := string(contentBytes)   - b.Log.Debugf("<= Sending message from %s on %s to gateway", ev.Sender, b.Account) - b.Remote <- rmsg + b.Log.Errorf("Content[body] is not a string: %T\n%#v", ev.Content.GetRaw()["body"], eventString)   - // not crucial, so no ratelimit check here - if err := b.mc.MarkRead(context.TODO(), ev.RoomID, ev.ID); err != nil { - b.Log.Errorf("couldn't mark message as read %s", err.Error()) - } + return + } + + // Do we have a /me action + if ev.Content.AsMessage().MsgType == event.MsgEmote { + rmsg.Event = config.EventUserAction + } + + // Is it an edit? + if b.handleEdit(ev, rmsg) { + return + } + + // Is it a reply? + if b.handleReply(ev, rmsg) { + return + } + + // Do we have an attachment + // TODO: does matrix support multiple attachments? + if b.handleAttachment(ev, rmsg) { + return + } + + b.Log.Debugf("<= Sending message from %s on %s to gateway", ev.Sender, b.Account) + + b.Remote <- rmsg + + // not crucial, so no ratelimit check here + var err = b.mc.MarkRead(ctx, ev.RoomID, ev.ID) + if err != nil { + b.Log.Errorf("couldn't mark message as read %s", err.Error())   }  }   @@ -7866 +8158 @@ func (b *Bmatrix) handleUploadFiles(msg *config.Message, roomID id.RoomID) (stri  }    // handleUploadFile handles native upload of a file. +// +//nolint:funlen // This function is necessarily long because it is an event handler  func (b *Bmatrix) handleUploadFile(msg *config.Message, roomID id.RoomID, fi *config.FileInfo) {   username := newMatrixUsername(msg.Username)   content := bytes.NewReader(*fi.Data) @@ -8009 +8319 @@ func (b *Bmatrix) handleUploadFile(msg *config.Message, roomID id.RoomID, fi *co   Format: event.FormatHTML,   }   - _, err := b.mc.SendMessageEvent(context.TODO(), roomID, event.EventMessage, content) + _, err2 := b.mc.SendMessageEvent(context.TODO(), roomID, event.EventMessage, content)   - return err + return err2   })   if err != nil {   b.Log.Errorf("file comment failed: %#v", err) @@ -8199 +85011 @@ func (b *Bmatrix) handleUploadFile(msg *config.Message, roomID id.RoomID, fi *co   ContentLength: int64(len(*fi.Data)),   }   - res, err = b.mc.UploadMedia(context.TODO(), media) + var err2 error   - return err + res, err2 = b.mc.UploadMedia(context.TODO(), media) + + return err2   })     if err != nil { @@ -83915 +87216 @@ func (b *Bmatrix) handleUploadFile(msg *config.Message, roomID id.RoomID, fi *co   URL: id.ContentURIString(res.ContentURI.String()),   }   - _, err := b.mc.SendMessageEvent(context.TODO(), roomID, event.EventMessage, content) + _, err2 := b.mc.SendMessageEvent(context.TODO(), roomID, event.EventMessage, content)   - return err + return err2   })   if err != nil {   b.Log.Errorf("sendVideo failed: %#v", err)   }   case strings.Contains(mtype, "image"):   b.Log.Debugf("sendImage %s", res.ContentURI) +   err = b.retry(func() error {   content := event.MessageEventContent{   MsgType: event.MsgImage, @@ -8559 +8899 @@ func (b *Bmatrix) handleUploadFile(msg *config.Message, roomID id.RoomID, fi *co   URL: id.ContentURIString(res.ContentURI.String()),   }   - _, err := b.mc.SendMessageEvent(context.TODO(), roomID, event.EventMessage, content) + _, err2 := b.mc.SendMessageEvent(context.TODO(), roomID, event.EventMessage, content)   - return err + return err2   })   if err != nil {   b.Log.Errorf("sendImage failed: %#v", err) @@ -8759 +9099 @@ func (b *Bmatrix) handleUploadFile(msg *config.Message, roomID id.RoomID, fi *co   },   }   - _, err := b.mc.SendMessageEvent(context.TODO(), roomID, event.EventMessage, content) + _, err2 := b.mc.SendMessageEvent(context.TODO(), roomID, event.EventMessage, content)   - return err + return err2   })   if err != nil {   b.Log.Errorf("sendAudio failed: %#v", err) @@ -8959 +9299 @@ func (b *Bmatrix) handleUploadFile(msg *config.Message, roomID id.RoomID, fi *co   },   }   - _, err := b.mc.SendMessageEvent(context.TODO(), roomID, event.EventMessage, content) + _, err2 := b.mc.SendMessageEvent(context.TODO(), roomID, event.EventMessage, content)   - return err + return err2   })   if err != nil {   b.Log.Errorf("sendFile failed: %#v", err)