Mark expired online statuses as away

This commit is contained in:
Bohdan Horbeshko 2022-01-31 09:31:05 -05:00
parent 8c20aaa30d
commit 3cdb625c5e
5 changed files with 61 additions and 9 deletions

View file

@ -34,6 +34,12 @@ func stringToLogConstant(c string) int32 {
return level 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 // Client stores the metadata for lazily invoked TDlib instance
type Client struct { type Client struct {
client *client.Client client *client.Client
@ -50,6 +56,9 @@ type Client struct {
cache *cache.Cache cache *cache.Cache
online bool online bool
DelayedStatuses map[int64]*DelayedStatus
DelayedStatusesLock sync.Mutex
locks clientLocks locks clientLocks
} }
@ -115,6 +124,7 @@ func NewClient(conf config.TelegramConfig, jid string, component *xmpp.Component
content: &conf.Content, content: &conf.Content,
cache: cache.NewCache(), cache: cache.NewCache(),
options: options, options: options,
DelayedStatuses: make(map[int64]*DelayedStatus),
locks: clientLocks{ locks: clientLocks{
chatMessageLocks: make(map[int64]*sync.Mutex), chatMessageLocks: make(map[int64]*sync.Mutex),
}, },

View file

@ -119,13 +119,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) {
c.cache.SetUser(update.User.Id, update.User) 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) go c.ProcessStatusUpdate(update.User.Id, status, show)
} }
// user status changed // user status changed
func (c *Client) updateUserStatus(update *client.UpdateUserStatus) { 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)) go c.ProcessStatusUpdate(update.UserId, status, show, gateway.SPImmed(false))
} }

View file

@ -94,14 +94,27 @@ func (c *Client) GetContactByID(id int64, chat *client.Chat) (*client.Chat, *cli
return chat, user, nil 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 var show, textStatus string
switch status.UserStatusType() { switch status.UserStatusType() {
case client.TypeUserStatusOnline: 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" textStatus = "Online"
case client.TypeUserStatusRecently: case client.TypeUserStatusRecently:
show, textStatus = "dnd", "Last seen recently" show, textStatus = "dnd", "Last seen recently"
c.DelayedStatusesLock.Lock()
delete(c.DelayedStatuses, chatID)
c.DelayedStatusesLock.Unlock()
case client.TypeUserStatusLastWeek: case client.TypeUserStatusLastWeek:
show, textStatus = "unavailable", "Last seen last week" show, textStatus = "unavailable", "Last seen last week"
case client.TypeUserStatusLastMonth: case client.TypeUserStatusLastMonth:
@ -111,20 +124,30 @@ func (c *Client) userStatusToText(status client.UserStatus) (string, string) {
case client.TypeUserStatusOffline: case client.TypeUserStatusOffline:
offlineStatus, _ := status.(*client.UserStatusOffline) offlineStatus, _ := status.(*client.UserStatusOffline)
// this will stop working in 2038 O\ // 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 { if elapsed < 3600 {
show = "away" show = "away"
} else { } else {
show = "xa" show = "xa"
} }
textStatus = time.Unix(int64(offlineStatus.WasOnline), 0). textStatus = c.LastSeenStatus(wasOnline)
In(c.Session.TimezoneToLocation()).
Format("Last seen at 15:04 02/01/2006") c.DelayedStatusesLock.Lock()
delete(c.DelayedStatuses, chatID)
c.DelayedStatusesLock.Unlock()
} }
return show, textStatus 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 // ProcessStatusUpdate sets contact status
func (c *Client) ProcessStatusUpdate(chatID int64, status string, show string, args ...args.V) error { func (c *Client) ProcessStatusUpdate(chatID int64, status string, show string, args ...args.V) error {
if !c.Online() { if !c.Online() {
@ -161,7 +184,7 @@ func (c *Client) ProcessStatusUpdate(chatID int64, status string, show string, a
if status == "" { if status == "" {
if user != nil { if user != nil {
show, status = c.userStatusToText(user.Status) show, status = c.userStatusToText(user.Status, chatID)
} else { } else {
show, status = "chat", chat.Title show, status = "chat", chat.Title
} }

View file

@ -85,6 +85,25 @@ func heartbeat(component *xmpp.Component) {
// status updater thread // status updater thread
for { for {
time.Sleep(60e9) 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 { for key, presence := range gateway.Queue {
err = gateway.ResumableSend(component, presence) err = gateway.ResumableSend(component, presence)
if err != nil { if err != nil {

View file

@ -189,8 +189,8 @@ func handlePresence(s xmpp.Sender, p stanza.Presence) {
for status := range session.StatusesRange() { for status := range session.StatusesRange() {
go session.ProcessStatusUpdate( go session.ProcessStatusUpdate(
status.ID, status.ID,
status.XMPP,
status.Description, status.Description,
status.XMPP,
gateway.SPImmed(false), gateway.SPImmed(false),
) )
} }