Take all history attributes into account conscientiously

This commit is contained in:
Bohdan Horbeshko 2025-05-18 04:27:25 -04:00
parent 538b9bca8b
commit f1b5774490
3 changed files with 111 additions and 12 deletions

View file

@ -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 { if err != nil {
return err.Error(), true, false return err.Error(), true, false
} }

View file

@ -93,6 +93,44 @@ const (
MembersListBannedAndAdministrators 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 // GetContactByUsername resolves username to user id retrieves user and chat information
func (c *Client) GetContactByUsername(username string) (*client.Chat, *client.User, error) { func (c *Client) GetContactByUsername(username string) (*client.Chat, *client.User, error) {
if !c.Online() { 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 // 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 // save the nickname in this MUC, also as a marker of join
c.locks.mucCacheLock.Lock() c.locks.mucCacheLock.Lock()
mucState, ok := c.mucCache[chatId] 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 newMessages *client.Messages
var messages []*client.Message var messages []*client.Message
var err error var err error
var fromId int64 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 { if len(messages) > 0 {
fromId = messages[len(messages)-1].Id 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{ newMessages, err = c.client.GetChatHistory(&client.GetChatHistoryRequest{
ChatId: chatID, ChatId: chatID,
FromMessageId: fromId, FromMessageId: fromId,
Limit: limit, Limit: safetyLimit,
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
messages = append(messages, newMessages.Messages...) if len(newMessages.Messages) == 0 {
if len(newMessages.Messages) == 0 || len(messages) >= int(limit) {
break 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 return messages, nil

View file

@ -7,6 +7,7 @@ import (
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"time"
"dev.narayana.im/narayana/telegabber/persistence" "dev.narayana.im/narayana/telegabber/persistence"
"dev.narayana.im/narayana/telegabber/telegram" "dev.narayana.im/narayana/telegabber/telegram"
@ -544,11 +545,24 @@ func handleMUCPresence(s xmpp.Sender, p stanza.Presence, mucExt stanza.MucPresen
return return
} }
limit, ok := mucExt.History.MaxStanzas.Get() log.Debugf("%#v", mucExt)
if !ok { maxStanzas, maxStanzasOk := mucExt.History.MaxStanzas.Get()
limit = 20 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)
} }
} }
} }