From 3cdb625c5edb90ad6c55bacc2daea51385952750 Mon Sep 17 00:00:00 2001 From: Bohdan Horbeshko Date: Mon, 31 Jan 2022 09:31:05 -0500 Subject: [PATCH] Mark expired online statuses as away --- telegram/client.go | 10 ++++++++++ telegram/handlers.go | 4 ++-- telegram/utils.go | 35 +++++++++++++++++++++++++++++------ xmpp/component.go | 19 +++++++++++++++++++ xmpp/handlers.go | 2 +- 5 files changed, 61 insertions(+), 9 deletions(-) diff --git a/telegram/client.go b/telegram/client.go index 8813df0..5220c2d 100644 --- a/telegram/client.go +++ b/telegram/client.go @@ -34,6 +34,12 @@ func stringToLogConstant(c string) int32 { return level } +// DelayedStatus describes an online status expiring on timeout +type DelayedStatus struct { + TimestampOnline int64 + TimestampExpired int64 +} + // Client stores the metadata for lazily invoked TDlib instance type Client struct { client *client.Client @@ -50,6 +56,9 @@ type Client struct { cache *cache.Cache online bool + DelayedStatuses map[int64]*DelayedStatus + DelayedStatusesLock sync.Mutex + locks clientLocks } @@ -115,6 +124,7 @@ func NewClient(conf config.TelegramConfig, jid string, component *xmpp.Component content: &conf.Content, cache: cache.NewCache(), options: options, + DelayedStatuses: make(map[int64]*DelayedStatus), locks: clientLocks{ chatMessageLocks: make(map[int64]*sync.Mutex), }, diff --git a/telegram/handlers.go b/telegram/handlers.go index 63f981f..4b44463 100644 --- a/telegram/handlers.go +++ b/telegram/handlers.go @@ -119,13 +119,13 @@ func (c *Client) updateHandler() { // new user discovered func (c *Client) updateUser(update *client.UpdateUser) { c.cache.SetUser(update.User.Id, update.User) - show, status := c.userStatusToText(update.User.Status) + show, status := c.userStatusToText(update.User.Status, update.User.Id) go c.ProcessStatusUpdate(update.User.Id, status, show) } // user status changed func (c *Client) updateUserStatus(update *client.UpdateUserStatus) { - show, status := c.userStatusToText(update.Status) + show, status := c.userStatusToText(update.Status, update.UserId) go c.ProcessStatusUpdate(update.UserId, status, show, gateway.SPImmed(false)) } diff --git a/telegram/utils.go b/telegram/utils.go index 4de55c6..fad1bc0 100644 --- a/telegram/utils.go +++ b/telegram/utils.go @@ -94,14 +94,27 @@ func (c *Client) GetContactByID(id int64, chat *client.Chat) (*client.Chat, *cli return chat, user, nil } -func (c *Client) userStatusToText(status client.UserStatus) (string, string) { +func (c *Client) userStatusToText(status client.UserStatus, chatID int64) (string, string) { var show, textStatus string switch status.UserStatusType() { case client.TypeUserStatusOnline: + onlineStatus, _ := status.(*client.UserStatusOnline) + + c.DelayedStatusesLock.Lock() + c.DelayedStatuses[chatID] = &DelayedStatus{ + TimestampOnline: time.Now().Unix(), + TimestampExpired: int64(onlineStatus.Expires), + } + c.DelayedStatusesLock.Unlock() + textStatus = "Online" case client.TypeUserStatusRecently: show, textStatus = "dnd", "Last seen recently" + + c.DelayedStatusesLock.Lock() + delete(c.DelayedStatuses, chatID) + c.DelayedStatusesLock.Unlock() case client.TypeUserStatusLastWeek: show, textStatus = "unavailable", "Last seen last week" case client.TypeUserStatusLastMonth: @@ -111,20 +124,30 @@ func (c *Client) userStatusToText(status client.UserStatus) (string, string) { case client.TypeUserStatusOffline: offlineStatus, _ := status.(*client.UserStatusOffline) // this will stop working in 2038 O\ - elapsed := time.Now().Unix() - int64(offlineStatus.WasOnline) + wasOnline := int64(offlineStatus.WasOnline) + elapsed := time.Now().Unix() - wasOnline if elapsed < 3600 { show = "away" } else { show = "xa" } - textStatus = time.Unix(int64(offlineStatus.WasOnline), 0). - In(c.Session.TimezoneToLocation()). - Format("Last seen at 15:04 02/01/2006") + textStatus = c.LastSeenStatus(wasOnline) + + c.DelayedStatusesLock.Lock() + delete(c.DelayedStatuses, chatID) + c.DelayedStatusesLock.Unlock() } return show, textStatus } +// LastSeenStatus formats a timestamp to a "Last seen at" string +func (c *Client) LastSeenStatus(timestamp int64) string { + return time.Unix(int64(timestamp), 0). + In(c.Session.TimezoneToLocation()). + Format("Last seen at 15:04 02/01/2006") +} + // ProcessStatusUpdate sets contact status func (c *Client) ProcessStatusUpdate(chatID int64, status string, show string, args ...args.V) error { if !c.Online() { @@ -161,7 +184,7 @@ func (c *Client) ProcessStatusUpdate(chatID int64, status string, show string, a if status == "" { if user != nil { - show, status = c.userStatusToText(user.Status) + show, status = c.userStatusToText(user.Status, chatID) } else { show, status = "chat", chat.Title } diff --git a/xmpp/component.go b/xmpp/component.go index fb5732e..e22b221 100644 --- a/xmpp/component.go +++ b/xmpp/component.go @@ -85,6 +85,25 @@ func heartbeat(component *xmpp.Component) { // status updater thread for { time.Sleep(60e9) + now := time.Now().Unix() + + sessionLock.Lock() + for _, session := range sessions { + session.DelayedStatusesLock.Lock() + for chatID, delayedStatus := range session.DelayedStatuses { + if delayedStatus.TimestampExpired <= now { + go session.ProcessStatusUpdate( + chatID, + session.LastSeenStatus(delayedStatus.TimestampOnline), + "away", + ) + delete(session.DelayedStatuses, chatID) + } + } + session.DelayedStatusesLock.Unlock() + } + sessionLock.Unlock() + for key, presence := range gateway.Queue { err = gateway.ResumableSend(component, presence) if err != nil { diff --git a/xmpp/handlers.go b/xmpp/handlers.go index 6770e3a..5db8df6 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -189,8 +189,8 @@ func handlePresence(s xmpp.Sender, p stanza.Presence) { for status := range session.StatusesRange() { go session.ProcessStatusUpdate( status.ID, - status.XMPP, status.Description, + status.XMPP, gateway.SPImmed(false), ) }