From b8fcac6ae24dd5e07f366741f0f282f33b18b503 Mon Sep 17 00:00:00 2001 From: bodqhrohro Date: Sun, 5 Jan 2020 15:03:10 +0200 Subject: [PATCH] Resend chat statuses on probe presence --- telegram/cache/cache.go | 63 +++++++++++++++++++++++++++++++++++++---- telegram/handlers.go | 6 ++-- telegram/utils.go | 12 ++++++-- xmpp/handlers.go | 9 ++++++ 4 files changed, 79 insertions(+), 11 deletions(-) diff --git a/telegram/cache/cache.go b/telegram/cache/cache.go index d1d16f9..b799709 100644 --- a/telegram/cache/cache.go +++ b/telegram/cache/cache.go @@ -6,20 +6,30 @@ import ( "github.com/zelenin/go-tdlib/client" ) +// Status stores formatted data for XMPP presence +type Status struct { + ID int64 + XMPP string + Description string +} + // Cache allows operating the chats and users cache in // a thread-safe manner type Cache struct { - chats map[int64]*client.Chat - users map[int32]*client.User - chatsLock sync.Mutex - usersLock sync.Mutex + chats map[int64]*client.Chat + users map[int32]*client.User + statuses map[int64]*Status + chatsLock sync.Mutex + usersLock sync.Mutex + statusesLock sync.Mutex } // NewCache initializes a cache func NewCache() *Cache { return &Cache{ - chats: map[int64]*client.Chat{}, - users: map[int32]*client.User{}, + chats: map[int64]*client.Chat{}, + users: map[int32]*client.User{}, + statuses: map[int64]*Status{}, } } @@ -49,6 +59,26 @@ func (cache *Cache) UsersKeys() []int32 { return keys } +// StatusesRange loops through the map in a thread-safe manner +func (cache *Cache) StatusesRange() chan *Status { + cache.statusesLock.Lock() + + statusChan := make(chan *Status, 1) + + go func() { + defer func() { + cache.statusesLock.Unlock() + close(statusChan) + }() + + for _, status := range cache.statuses { + statusChan <- status + } + }() + + return statusChan +} + // GetChat retrieves chat by id if it's present in the cache func (cache *Cache) GetChat(id int64) (*client.Chat, bool) { cache.chatsLock.Lock() @@ -67,6 +97,15 @@ func (cache *Cache) GetUser(id int32) (*client.User, bool) { return user, ok } +// GetStatus retrieves status by id if it's present in the cache +func (cache *Cache) GetStatus(id int64) (*Status, bool) { + cache.statusesLock.Lock() + defer cache.statusesLock.Unlock() + + status, ok := cache.statuses[id] + return status, ok +} + // SetChat stores a chat in the cache func (cache *Cache) SetChat(id int64, chat *client.Chat) { cache.chatsLock.Lock() @@ -82,3 +121,15 @@ func (cache *Cache) SetUser(id int32, user *client.User) { cache.users[id] = user } + +// SetStatus stores a status in the cache +func (cache *Cache) SetStatus(id int64, show string, status string) { + cache.statusesLock.Lock() + defer cache.statusesLock.Unlock() + + cache.statuses[id] = &Status{ + ID: id, + XMPP: show, + Description: status, + } +} diff --git a/telegram/handlers.go b/telegram/handlers.go index aaa1e3d..aef8286 100644 --- a/telegram/handlers.go +++ b/telegram/handlers.go @@ -120,13 +120,13 @@ func (c *Client) updateHandler() { func (c *Client) updateUser(update *client.UpdateUser) { c.cache.SetUser(update.User.Id, update.User) show, status := c.userStatusToText(update.User.Status) - go c.processStatusUpdate(int64(update.User.Id), status, show) + go c.ProcessStatusUpdate(int64(update.User.Id), status, show) } // user status changed func (c *Client) updateUserStatus(update *client.UpdateUserStatus) { show, status := c.userStatusToText(update.Status) - go c.processStatusUpdate(int64(update.UserId), status, show, gateway.SPImmed(false)) + go c.ProcessStatusUpdate(int64(update.UserId), status, show, gateway.SPImmed(false)) } // new chat discovered @@ -166,7 +166,7 @@ func (c *Client) updateNewChat(update *client.UpdateNewChat) { } if update.Chat.Id < 0 { - c.processStatusUpdate(update.Chat.Id, update.Chat.Title, "chat") + c.ProcessStatusUpdate(update.Chat.Id, update.Chat.Title, "chat") } }() } diff --git a/telegram/utils.go b/telegram/utils.go index b3e815f..8de1f5f 100644 --- a/telegram/utils.go +++ b/telegram/utils.go @@ -14,6 +14,7 @@ import ( "strings" "time" + "dev.narayana.im/narayana/telegabber/telegram/cache" "dev.narayana.im/narayana/telegabber/xmpp/gateway" log "github.com/sirupsen/logrus" @@ -129,8 +130,8 @@ func (c *Client) userStatusToText(status client.UserStatus) (string, string) { return show, textStatus } -// set contact status -func (c *Client) processStatusUpdate(chatID int64, status string, show string, args ...args.V) error { +// ProcessStatusUpdate sets contact status +func (c *Client) ProcessStatusUpdate(chatID int64, status string, show string, args ...args.V) error { if !c.Online() { return nil } @@ -171,6 +172,8 @@ func (c *Client) processStatusUpdate(chatID int64, status string, show string, a } } + c.cache.SetStatus(chatID, show, status) + gateway.SendPresence( c.xmpp, c.jid, @@ -512,3 +515,8 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, messageID int } } } + +// StatusesRange proxies the following function from unexported cache +func (c *Client) StatusesRange() chan *cache.Status { + return c.cache.StatusesRange() +} diff --git a/xmpp/handlers.go b/xmpp/handlers.go index 2addd7b..8778423 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -176,6 +176,15 @@ func handlePresence(s xmpp.Sender, p stanza.Presence) { err = session.Connect() if err != nil { log.Error(errors.Wrap(err, "TDlib connection failure")) + } else { + for status := range session.StatusesRange() { + go session.ProcessStatusUpdate( + status.ID, + status.XMPP, + status.Description, + gateway.SPImmed(false), + ) + } } }() }