From f1b57744906a297398eba20d5833dc4de7599664 Mon Sep 17 00:00:00 2001 From: Bohdan Horbeshko Date: Sun, 18 May 2025 04:27:25 -0400 Subject: [PATCH] Take all history attributes into account conscientiously --- telegram/commands.go | 2 +- telegram/utils.go | 99 ++++++++++++++++++++++++++++++++++++++++---- xmpp/handlers.go | 22 ++++++++-- 3 files changed, 111 insertions(+), 12 deletions(-) diff --git a/telegram/commands.go b/telegram/commands.go index ef73c37..f1554eb 100644 --- a/telegram/commands.go +++ b/telegram/commands.go @@ -1118,7 +1118,7 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool, } } - messages, err := c.getNLastMessages(chatID, limit) + messages, err := c.getNLastMessages(chatID, NewMessageLimitMessages(limit)) if err != nil { return err.Error(), true, false } diff --git a/telegram/utils.go b/telegram/utils.go index a902a76..ae66953 100644 --- a/telegram/utils.go +++ b/telegram/utils.go @@ -93,6 +93,44 @@ const ( MembersListBannedAndAdministrators ) +const ( + MessageLimitMessages = iota + MessageLimitChars + MessageLimitSince +) + +// MessageLimitType is an enum of MUC history limit types +type MessageLimitType int + +// MessageLimit stores a MUC history limit +type MessageLimit struct { + Type MessageLimitType + Messages int32 + Chars int + Since int64 +} + +func NewMessageLimitMessages(stanzas int32) *MessageLimit { + var limit MessageLimit + limit.Type = MessageLimitMessages + limit.Messages = stanzas + return &limit +} + +func NewMessageLimitChars(chars int) *MessageLimit { + var limit MessageLimit + limit.Type = MessageLimitChars + limit.Chars = chars + return &limit +} + +func NewMessageLimitSince(since int64) *MessageLimit { + var limit MessageLimit + limit.Type = MessageLimitSince + limit.Since = since + return &limit +} + // GetContactByUsername resolves username to user id retrieves user and chat information func (c *Client) GetContactByUsername(username string) (*client.Chat, *client.User, error) { if !c.Online() { @@ -485,7 +523,7 @@ func (c *Client) ProcessStatusUpdate(chatID int64, status string, show string, o } // 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 *MessageLimit) { // save the nickname in this MUC, also as a marker of join c.locks.mucCacheLock.Lock() mucState, ok := c.mucCache[chatId] @@ -1915,13 +1953,31 @@ func (c *Client) getLastMessages(id int64, query string, from int64, count int32 }) } -func (c *Client) getNLastMessages(chatID int64, limit int32) ([]*client.Message, error) { +func (c *Client) getNLastMessages(chatID int64, limit *MessageLimit) ([]*client.Message, error) { var newMessages *client.Messages var messages []*client.Message var err error var fromId int64 + var safetyLimit int32 + var charsCount int - for _ = range make([]struct{}, limit) { // safety limit + if limit == nil { + return nil, nil + } + switch limit.Type { + case MessageLimitMessages: + safetyLimit = limit.Messages + case MessageLimitChars: + safetyLimit = int32(limit.Chars) + if safetyLimit > 1000 { + safetyLimit = 1000 + } + case MessageLimitSince: + safetyLimit = 1000 + } + + safetyLoop: + for _ = range make([]struct{}, safetyLimit) { if len(messages) > 0 { fromId = messages[len(messages)-1].Id } @@ -1929,17 +1985,46 @@ func (c *Client) getNLastMessages(chatID int64, limit int32) ([]*client.Message, newMessages, err = c.client.GetChatHistory(&client.GetChatHistoryRequest{ ChatId: chatID, FromMessageId: fromId, - Limit: limit, + Limit: safetyLimit, }) if err != nil { return nil, err } - messages = append(messages, newMessages.Messages...) - - if len(newMessages.Messages) == 0 || len(messages) >= int(limit) { + if len(newMessages.Messages) == 0 { break } + + for _, message := range newMessages.Messages { + if limit.Type == MessageLimitSince && limit.Since > int64(message.Date) { // durov… + break safetyLoop + } + + messages = append(messages, message) + + switch limit.Type { + case MessageLimitMessages: + if len(messages) >= int(limit.Messages) { + break safetyLoop + } + case MessageLimitChars: + // rough but why care + if message.Content != nil && message.Content.MessageContentType() == client.TypeMessageText { + textContent, ok := message.Content.(*client.MessageText) + if !ok { + uhOh() + } + + if textContent.Text != nil { + charsCount += len(textContent.Text.Text) + + if charsCount >= limit.Chars { + break safetyLoop + } + } + } + } + } } return messages, nil diff --git a/xmpp/handlers.go b/xmpp/handlers.go index fa32087..5868606 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -7,6 +7,7 @@ import ( "sort" "strconv" "strings" + "time" "dev.narayana.im/narayana/telegabber/persistence" "dev.narayana.im/narayana/telegabber/telegram" @@ -544,11 +545,24 @@ func handleMUCPresence(s xmpp.Sender, p stanza.Presence, mucExt stanza.MucPresen return } - limit, ok := mucExt.History.MaxStanzas.Get() - if !ok { - limit = 20 + log.Debugf("%#v", mucExt) + maxStanzas, maxStanzasOk := mucExt.History.MaxStanzas.Get() + maxChars, maxCharsOk := mucExt.History.MaxChars.Get() + seconds, secondsOk := mucExt.History.Seconds.Get() + + var limit *telegram.MessageLimit + if maxStanzasOk { + limit = telegram.NewMessageLimitMessages(int32(maxStanzas)) + } else if maxCharsOk { + limit = telegram.NewMessageLimitChars(maxChars) + } else if secondsOk { + limit = telegram.NewMessageLimitSince(time.Now().Add(time.Duration(seconds) * -time.Second).Unix()) + } else if !mucExt.History.Since.IsZero() { + limit = telegram.NewMessageLimitSince(mucExt.History.Since.Unix()) + } else { + limit = telegram.NewMessageLimitMessages(20) } - session.JoinMUC(chatId, fromResource, int32(limit)) + session.JoinMUC(chatId, fromResource, limit) } } }