Reflect name change of Telegram user in all MUCs

This commit is contained in:
Bohdan Horbeshko 2023-10-03 18:56:37 -04:00
parent b8a57c06b6
commit 1e7e761c6c
5 changed files with 113 additions and 21 deletions

View file

@ -41,6 +41,25 @@ type DelayedStatus struct {
TimestampExpired int64 TimestampExpired int64
} }
// MUCState holds MUC metadata
type MUCState struct {
Resources map[string]bool
Members map[int64]*MUCMember
}
// MUCMember represents a MUC member
type MUCMember struct {
Nickname string
Affiliation string
}
func NewMUCState() *MUCState {
return &MUCState{
Resources: make(map[string]bool),
Members: make(map[int64]*MUCMember),
}
}
// Client stores the metadata for lazily invoked TDlib instance // Client stores the metadata for lazily invoked TDlib instance
type Client struct { type Client struct {
client *client.Client client *client.Client
@ -64,7 +83,7 @@ type Client struct {
lastMsgHashes map[int64]uint64 lastMsgHashes map[int64]uint64
msgHashSeed maphash.Seed msgHashSeed maphash.Seed
mucResources map[int64]map[string]bool mucCache map[int64]*MUCState
locks clientLocks locks clientLocks
SendMessageLock sync.Mutex SendMessageLock sync.Mutex
@ -75,7 +94,7 @@ type clientLocks struct {
chatMessageLocks map[int64]*sync.Mutex chatMessageLocks map[int64]*sync.Mutex
resourcesLock sync.Mutex resourcesLock sync.Mutex
outboxLock sync.Mutex outboxLock sync.Mutex
mucResourcesLock sync.Mutex mucCacheLock sync.Mutex
lastMsgHashesLock sync.Mutex lastMsgHashesLock sync.Mutex
authorizerReadLock sync.Mutex authorizerReadLock sync.Mutex
@ -136,7 +155,7 @@ func NewClient(conf config.TelegramConfig, jid string, component *xmpp.Component
Session: session, Session: session,
resources: make(map[string]bool), resources: make(map[string]bool),
outbox: make(map[string]string), outbox: make(map[string]string),
mucResources: make(map[int64]map[string]bool), mucCache: make(map[int64]*MUCState),
content: &conf.Content, content: &conf.Content,
cache: cache.NewCache(), cache: cache.NewCache(),
options: options, options: options,

View file

@ -153,6 +153,13 @@ func (c *Client) updateHandler() {
// new user discovered // new user discovered
func (c *Client) updateUser(update *client.UpdateUser) { func (c *Client) updateUser(update *client.UpdateUser) {
// check if MUC nicknames should be updated
cacheUser, ok := c.cache.GetUser(update.User.Id)
if ok && (cacheUser.FirstName != update.User.FirstName || cacheUser.LastName != update.User.LastName) {
newNickname := c.GetMUCNickname(update.User.Id)
c.updateMUCsNickname(update.User.Id, newNickname)
}
c.cache.SetUser(update.User.Id, update.User) c.cache.SetUser(update.User.Id, update.User)
show, status, presenceType := c.userStatusToText(update.User.Status, update.User.Id) show, status, presenceType := c.userStatusToText(update.User.Status, update.User.Id)
go c.ProcessStatusUpdate(update.User.Id, status, show, gateway.SPType(presenceType)) go c.ProcessStatusUpdate(update.User.Id, status, show, gateway.SPType(presenceType))

View file

@ -306,21 +306,19 @@ func (c *Client) ProcessStatusUpdate(chatID int64, status string, show string, o
// JoinMUC saves MUC join fact and sends initialization data // JoinMUC saves MUC join fact and sends initialization data
func (c *Client) JoinMUC(chatId int64, resource string, limit int32) { func (c *Client) JoinMUC(chatId int64, resource string, limit int32) {
// save the nickname in this MUC, also as a marker of join // save the nickname in this MUC, also as a marker of join
c.locks.mucResourcesLock.Lock() c.locks.mucCacheLock.Lock()
oldMap, ok := c.mucResources[chatId] mucState, ok := c.mucCache[chatId]
if ok { if !ok || mucState == nil {
_, ok := oldMap[resource] mucState = NewMUCState()
if ok { c.mucCache[chatId] = mucState
// already joined, initializing anyway
} else {
oldMap[resource] = true
}
} else {
newMap := make(map[string]bool)
newMap[resource] = true
c.mucResources[chatId] = newMap
} }
c.locks.mucResourcesLock.Unlock() _, ok = mucState.Resources[resource]
if ok {
// already joined, initializing anyway
} else {
mucState.Resources[resource] = true
}
c.locks.mucCacheLock.Unlock()
c.sendMUCStatuses(chatId) c.sendMUCStatuses(chatId)
@ -332,14 +330,27 @@ func (c *Client) JoinMUC(chatId int64, resource string, limit int32) {
c.sendMUCSubject(chatId, resource) c.sendMUCSubject(chatId, resource)
} }
func (c *Client) getFullName(user *client.User) string {
fullName := user.FirstName
if user.LastName != "" {
fullName = fullName + " " + user.LastName
}
return fullName
}
func (c *Client) sendMUCStatuses(chatID int64) { func (c *Client) sendMUCStatuses(chatID int64) {
c.locks.mucCacheLock.Lock()
defer c.locks.mucCacheLock.Unlock()
mucState, ok := c.mucCache[chatID]
if !ok || mucState == nil {
mucState = NewMUCState()
c.mucCache[chatID] = mucState
}
sChatId := strconv.FormatInt(chatID, 10) sChatId := strconv.FormatInt(chatID, 10)
myNickname := "me" myNickname := "me"
if c.me != nil { if c.me != nil {
myNickname := c.me.FirstName myNickname = c.getFullName(c.me)
if c.me.LastName != "" {
myNickname = myNickname + " " + c.me.LastName
}
} }
myAffiliation := "member" myAffiliation := "member"
@ -364,6 +375,11 @@ func (c *Client) sendMUCStatuses(chatID int64) {
nickname := c.GetMUCNickname(senderId) nickname := c.GetMUCNickname(senderId)
affiliation := c.memberStatusToAffiliation(member.Status) affiliation := c.memberStatusToAffiliation(member.Status)
mucState.Members[senderId] = &MUCMember{
Nickname: nickname,
Affiliation: affiliation,
}
if c.me != nil && senderId == c.me.Id { if c.me != nil && senderId == c.me.Id {
myNickname = nickname myNickname = nickname
myAffiliation = affiliation myAffiliation = affiliation
@ -419,6 +435,49 @@ func (c *Client) GetMUCNickname(chatID int64) string {
return c.formatContact(chatID) return c.formatContact(chatID)
} }
func (c *Client) updateMUCsNickname(memberID int64, newNickname string) {
c.locks.mucCacheLock.Lock()
defer c.locks.mucCacheLock.Unlock()
for mucId, state := range c.mucCache {
oldMember, ok := state.Members[memberID]
if ok {
state.Members[memberID] = &MUCMember{
Nickname: newNickname,
Affiliation: oldMember.Affiliation,
}
sMucId := strconv.FormatInt(mucId, 10)
unavailableStatusCodes := []uint16{303, 210}
availableStatusCodes := []uint16{100, 210}
if c.me != nil && memberID == c.me.Id {
unavailableStatusCodes = append(unavailableStatusCodes, 110)
availableStatusCodes = append(availableStatusCodes, 110)
}
gateway.SendPresence(
c.xmpp,
c.jid,
gateway.SPType("unavailable"),
gateway.SPFrom(sMucId),
gateway.SPResource(oldMember.Nickname),
gateway.SPImmed(true),
gateway.SPMUCAffiliation(oldMember.Affiliation),
gateway.SPMUCNick(newNickname),
gateway.SPMUCStatusCodes(unavailableStatusCodes),
)
gateway.SendPresence(
c.xmpp,
c.jid,
gateway.SPFrom(sMucId),
gateway.SPResource(newNickname),
gateway.SPImmed(true),
gateway.SPMUCAffiliation(oldMember.Affiliation),
gateway.SPMUCStatusCodes(availableStatusCodes),
)
}
}
}
func (c *Client) formatContact(chatID int64) string { func (c *Client) formatContact(chatID int64) string {
if chatID == 0 { if chatID == 0 {
return "" return ""

View file

@ -225,6 +225,7 @@ type PresenceXMucUserItem struct {
XMLName xml.Name `xml:"item"` XMLName xml.Name `xml:"item"`
Affiliation string `xml:"affiliation,attr"` Affiliation string `xml:"affiliation,attr"`
Jid string `xml:"jid,attr"` Jid string `xml:"jid,attr"`
Nick string `xml:"nick,attr,omitempty"`
Role string `xml:"role,attr"` Role string `xml:"role,attr"`
} }

View file

@ -328,6 +328,9 @@ var SPImmed = args.NewBool(args.Default(true))
// SPMUCAffiliation is a XEP-0045 MUC affiliation // SPMUCAffiliation is a XEP-0045 MUC affiliation
var SPMUCAffiliation = args.NewString() var SPMUCAffiliation = args.NewString()
// SPMUCNick is a XEP-0045 MUC user nick
var SPMUCNick = args.NewString()
// SPMUCJid is a real jid of a MUC member // SPMUCJid is a real jid of a MUC member
var SPMUCJid = args.NewString() var SPMUCJid = args.NewString()
@ -398,6 +401,9 @@ func newPresence(bareJid string, to string, args ...args.V) stanza.Presence {
Role: affilationToRole(affiliation), Role: affilationToRole(affiliation),
}, },
} }
if SPMUCNick.IsSet(args) {
userExt.Item.Nick = SPMUCNick.Get(args)
}
if SPMUCJid.IsSet(args) { if SPMUCJid.IsSet(args) {
userExt.Item.Jid = SPMUCJid.Get(args) userExt.Item.Jid = SPMUCJid.Get(args)
} }