Set room avatar for DM portals

This commit is contained in:
Tulir Asokan 2023-09-05 01:34:47 +03:00
parent a415444fc0
commit 95c0cfa983
6 changed files with 85 additions and 23 deletions

View file

@ -55,6 +55,10 @@ func (pq *PortalQuery) GetByKey(ctx context.Context, key Key) (*Portal, error) {
return get[*Portal](pq, ctx, "SELECT id, receiver, self_user, other_user, type, mxid, name, name_set, encrypted, in_space FROM portal WHERE id=$1 AND receiver=$2", key.ID, key.Receiver) return get[*Portal](pq, ctx, "SELECT id, receiver, self_user, other_user, type, mxid, name, name_set, encrypted, in_space FROM portal WHERE id=$1 AND receiver=$2", key.ID, key.Receiver)
} }
func (pq *PortalQuery) GetByOtherUser(ctx context.Context, key Key) (*Portal, error) {
return get[*Portal](pq, ctx, "SELECT id, receiver, self_user, other_user, type, mxid, name, name_set, encrypted, in_space FROM portal WHERE other_user=$1 AND receiver=$2", key.ID, key.Receiver)
}
func (pq *PortalQuery) GetByMXID(ctx context.Context, mxid id.RoomID) (*Portal, error) { func (pq *PortalQuery) GetByMXID(ctx context.Context, mxid id.RoomID) (*Portal, error) {
return get[*Portal](pq, ctx, "SELECT id, receiver, self_user, other_user, type, mxid, name, name_set, encrypted, in_space FROM portal WHERE mxid=$1", mxid) return get[*Portal](pq, ctx, "SELECT id, receiver, self_user, other_user, type, mxid, name, name_set, encrypted, in_space FROM portal WHERE mxid=$1", mxid)
} }

View file

@ -1,4 +1,4 @@
-- v0 -> v6: Latest revision -- v0 -> v8: Latest revision
CREATE TABLE "user" ( CREATE TABLE "user" (
-- only: postgres -- only: postgres
@ -54,6 +54,7 @@ CREATE TABLE portal (
CONSTRAINT portal_user_fkey FOREIGN KEY (receiver) REFERENCES "user"(rowid) ON DELETE CASCADE, CONSTRAINT portal_user_fkey FOREIGN KEY (receiver) REFERENCES "user"(rowid) ON DELETE CASCADE,
CONSTRAINT portal_puppet_fkey FOREIGN KEY (other_user, receiver) REFERENCES puppet(id, receiver) ON DELETE CASCADE CONSTRAINT portal_puppet_fkey FOREIGN KEY (other_user, receiver) REFERENCES puppet(id, receiver) ON DELETE CASCADE
); );
CREATE INDEX ON portal(receiver, other_user);
CREATE TABLE message ( CREATE TABLE message (
conv_id TEXT NOT NULL, conv_id TEXT NOT NULL,

View file

@ -0,0 +1,2 @@
-- v8: Add index for DM portals
CREATE INDEX ON portal(receiver, other_user);

View file

@ -57,6 +57,7 @@ type GMBridge struct {
managementRoomsLock sync.Mutex managementRoomsLock sync.Mutex
portalsByMXID map[id.RoomID]*Portal portalsByMXID map[id.RoomID]*Portal
portalsByKey map[database.Key]*Portal portalsByKey map[database.Key]*Portal
portalsByOtherUser map[database.Key]*Portal
portalsLock sync.Mutex portalsLock sync.Mutex
puppetsByKey map[database.Key]*Puppet puppetsByKey map[database.Key]*Puppet
puppetsLock sync.Mutex puppetsLock sync.Mutex
@ -158,6 +159,7 @@ func main() {
managementRooms: make(map[id.RoomID]*User), managementRooms: make(map[id.RoomID]*User),
portalsByMXID: make(map[id.RoomID]*Portal), portalsByMXID: make(map[id.RoomID]*Portal),
portalsByKey: make(map[database.Key]*Portal), portalsByKey: make(map[database.Key]*Portal),
portalsByOtherUser: make(map[database.Key]*Portal),
puppetsByKey: make(map[database.Key]*Puppet), puppetsByKey: make(map[database.Key]*Puppet),
} }
br.Bridge = bridge.Bridge{ br.Bridge = bridge.Bridge{
@ -166,8 +168,8 @@ func main() {
Description: "A Matrix-Google Messages puppeting bridge.", Description: "A Matrix-Google Messages puppeting bridge.",
Version: "0.1.0", Version: "0.1.0",
ProtocolName: "Google Messages", ProtocolName: "Google Messages",
BeeperServiceName: "googlesms", BeeperServiceName: "gmessages",
BeeperNetworkName: "googlesms", BeeperNetworkName: "gmessages",
CryptoPickleKey: "go.mau.fi/mautrix-gmessages", CryptoPickleKey: "go.mau.fi/mautrix-gmessages",

View file

@ -106,6 +106,27 @@ func (br *GMBridge) GetPortalByKey(key database.Key) *Portal {
return portal return portal
} }
func (br *GMBridge) GetPortalByOtherUser(key database.Key) *Portal {
br.portalsLock.Lock()
defer br.portalsLock.Unlock()
portal, ok := br.portalsByOtherUser[key]
if !ok {
dbPortal, err := br.DB.Portal.GetByKey(context.TODO(), key)
if err != nil {
br.ZLog.Err(err).Object("portal_key", key).Msg("Failed to get portal from database")
return nil
}
if dbPortal != nil {
existingPortal, ok := br.portalsByKey[dbPortal.Key]
if ok {
return existingPortal
}
}
return br.loadDBPortal(dbPortal, nil)
}
return portal
}
func (br *GMBridge) GetExistingPortalByKey(key database.Key) *Portal { func (br *GMBridge) GetExistingPortalByKey(key database.Key) *Portal {
br.portalsLock.Lock() br.portalsLock.Lock()
defer br.portalsLock.Unlock() defer br.portalsLock.Unlock()
@ -180,6 +201,9 @@ func (br *GMBridge) loadDBPortal(dbPortal *database.Portal, key *database.Key) *
if len(portal.MXID) > 0 { if len(portal.MXID) > 0 {
br.portalsByMXID[portal.MXID] = portal br.portalsByMXID[portal.MXID] = portal
} }
if len(portal.OtherUserID) > 0 {
br.portalsByOtherUser[database.Key{ID: portal.OtherUserID, Receiver: portal.Receiver}] = portal
}
return portal return portal
} }
@ -1241,6 +1265,12 @@ func (portal *Portal) SyncParticipants(source *User, metadata *gmproto.Conversat
Str("new_other_user_id", firstParticipant.ID.ParticipantID). Str("new_other_user_id", firstParticipant.ID.ParticipantID).
Msg("Found other user ID in DM") Msg("Found other user ID in DM")
portal.OtherUserID = firstParticipant.ID.ParticipantID portal.OtherUserID = firstParticipant.ID.ParticipantID
portal.bridge.portalsLock.Lock()
portal.bridge.portalsByOtherUser[database.Key{
ID: portal.OtherUserID,
Receiver: portal.Receiver,
}] = portal
portal.bridge.portalsLock.Unlock()
changed = true changed = true
} }
if portal.MXID != "" { if portal.MXID != "" {
@ -1486,11 +1516,18 @@ func (portal *Portal) CreateMatrixRoom(user *User, conv *gmproto.Conversation, i
} }
members := portal.UpdateMetadata(user, conv) members := portal.UpdateMetadata(user, conv)
var avatarURL id.ContentURI
if portal.IsPrivateChat() && portal.GetDMPuppet() == nil { if portal.IsPrivateChat() {
puppet := portal.GetDMPuppet()
if puppet == nil {
portal.zlog.Error().Msg("Didn't find ghost of other user in DM :(") portal.zlog.Error().Msg("Didn't find ghost of other user in DM :(")
return fmt.Errorf("ghost not found") return fmt.Errorf("ghost not found")
} }
if portal.shouldSetDMRoomMetadata() {
avatarURL = puppet.AvatarMXC
}
}
intent := portal.MainIntent() intent := portal.MainIntent()
if err = intent.EnsureRegistered(); err != nil { if err = intent.EnsureRegistered(); err != nil {
@ -1530,6 +1567,14 @@ func (portal *Portal) CreateMatrixRoom(user *User, conv *gmproto.Conversation, i
invite = append(invite, portal.bridge.Bot.UserID) invite = append(invite, portal.bridge.Bot.UserID)
} }
} }
if !avatarURL.IsEmpty() {
initialState = append(initialState, &event.Event{
Type: event.StateRoomAvatar,
Content: event.Content{
Parsed: &event.RoomAvatarEventContent{URL: avatarURL},
},
})
}
creationContent := make(map[string]interface{}) creationContent := make(map[string]interface{})
if !portal.bridge.Config.Bridge.FederateRooms { if !portal.bridge.Config.Bridge.FederateRooms {

View file

@ -214,7 +214,8 @@ func (puppet *Puppet) UpdateAvatar(source *User) bool {
} }
puppet.AvatarUpdateTS = time.Now() puppet.AvatarUpdateTS = time.Now()
if len(resp.Thumbnail) == 0 { if len(resp.Thumbnail) == 0 {
if puppet.AvatarHash == [32]byte{} { if puppet.AvatarHash == [32]byte{} && puppet.AvatarMXC.IsEmpty() {
puppet.AvatarSet = true
return true return true
} }
puppet.AvatarHash = [32]byte{} puppet.AvatarHash = [32]byte{}
@ -223,7 +224,7 @@ func (puppet *Puppet) UpdateAvatar(source *User) bool {
} else { } else {
thumbData := resp.Thumbnail[0].GetData() thumbData := resp.Thumbnail[0].GetData()
hash := sha256.Sum256(thumbData.GetImageBuffer()) hash := sha256.Sum256(thumbData.GetImageBuffer())
if hash == puppet.AvatarHash { if hash == puppet.AvatarHash && puppet.AvatarSet {
return true return true
} }
puppet.AvatarHash = hash puppet.AvatarHash = hash
@ -249,6 +250,22 @@ func (puppet *Puppet) UpdateAvatar(source *User) bool {
return true return true
} }
func (puppet *Puppet) updatePortalAvatar() {
portal := puppet.bridge.GetPortalByOtherUser(puppet.Key)
if portal == nil {
return
}
portal.roomCreateLock.Lock()
defer portal.roomCreateLock.Unlock()
if portal.MXID == "" || !portal.shouldSetDMRoomMetadata() {
return
}
_, err := portal.MainIntent().SetRoomAvatar(portal.MXID, puppet.AvatarMXC)
if err != nil {
puppet.log.Err(err).Str("room_id", portal.MXID.String()).Msg("Failed to update DM room avatar")
}
}
func (puppet *Puppet) UpdateName(formattedPhone, fullName, firstName string) bool { func (puppet *Puppet) UpdateName(formattedPhone, fullName, firstName string) bool {
newName := puppet.bridge.Config.Bridge.FormatDisplayname(formattedPhone, fullName, firstName) newName := puppet.bridge.Config.Bridge.FormatDisplayname(formattedPhone, fullName, firstName)
if puppet.Name != newName || !puppet.NameSet { if puppet.Name != newName || !puppet.NameSet {
@ -259,7 +276,6 @@ func (puppet *Puppet) UpdateName(formattedPhone, fullName, firstName string) boo
if err == nil { if err == nil {
puppet.log.Debug().Str("old_name", oldName).Str("new_name", newName).Msg("Updated displayname") puppet.log.Debug().Str("old_name", oldName).Str("new_name", newName).Msg("Updated displayname")
puppet.NameSet = true puppet.NameSet = true
go puppet.updatePortalName()
} else { } else {
puppet.log.Warn().Err(err).Msg("Failed to set displayname") puppet.log.Warn().Err(err).Msg("Failed to set displayname")
} }
@ -296,14 +312,6 @@ func (puppet *Puppet) UpdateContactInfo() bool {
} }
} }
func (puppet *Puppet) updatePortalAvatar() {
// TODO implement
}
func (puppet *Puppet) updatePortalName() {
// TODO implement
}
func (puppet *Puppet) Sync(source *User, contact *gmproto.Participant) { func (puppet *Puppet) Sync(source *User, contact *gmproto.Participant) {
err := puppet.DefaultIntent().EnsureRegistered() err := puppet.DefaultIntent().EnsureRegistered()
if err != nil { if err != nil {