mirror of https://gitlab.com/etke.cc/emm.git
187 lines
4.0 KiB
Go
187 lines
4.0 KiB
Go
package matrix
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"time"
|
|
|
|
"maunium.net/go/mautrix"
|
|
"maunium.net/go/mautrix/event"
|
|
"maunium.net/go/mautrix/id"
|
|
)
|
|
|
|
// Page is a amount of messages per page
|
|
const Page = 100
|
|
|
|
// Message struct
|
|
type Message struct {
|
|
// ID is a matrix event id of the message
|
|
ID id.EventID
|
|
// Replace is a matrix ID of old (replaced) event
|
|
Replace id.EventID
|
|
// ReplacedNote is a text note usable from template to mark replaced message as updated
|
|
ReplacedNote string
|
|
// Author is a matrix id of the sender
|
|
Author id.UserID
|
|
// Text is the message body in plaintext/markdown format
|
|
Text string
|
|
// HTML is the message body in html format
|
|
HTML string
|
|
// CreatedAt is a timestamp, format: 2006-01-02 15:04 UTC
|
|
CreatedAt string
|
|
// CreatedAtFull is a time.Time object
|
|
CreatedAtFull time.Time
|
|
}
|
|
|
|
var (
|
|
msgmap map[id.EventID]*Message
|
|
filter = &mautrix.FilterPart{
|
|
Types: []event.Type{event.EventMessage},
|
|
NotTypes: []event.Type{event.EventReaction, event.StateMember},
|
|
}
|
|
)
|
|
|
|
// Messages of the room
|
|
// Note on limit - the output slice may be less size than limit you sent in the following cases:
|
|
// * room contains less messages than limit
|
|
// * some room messages don't contain body/formatted body
|
|
func Messages(limit int) ([]*Message, error) {
|
|
var err error
|
|
msgmap = make(map[id.EventID]*Message, 0)
|
|
if limit > Page {
|
|
err = paginate(limit)
|
|
} else {
|
|
err = load()
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
messages := make([]*Message, 0, len(msgmap))
|
|
for _, message := range msgmap {
|
|
messages = append(messages, message)
|
|
}
|
|
log.Println("loaded", len(messages), "messages total")
|
|
|
|
return messages, nil
|
|
}
|
|
|
|
func paginate(limit int) error {
|
|
ctx := context.Background()
|
|
var token string
|
|
page := 1
|
|
for i := Page; i < limit; {
|
|
var chunks *mautrix.RespMessages
|
|
log.Println("requesting messages from", room, "page =", page)
|
|
err := retry(func() error {
|
|
var messagesErr error
|
|
chunks, messagesErr = client.Messages(ctx, room, token, "", 'b', filter, Page)
|
|
|
|
return messagesErr
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(chunks.Chunk) == 0 {
|
|
log.Println("no more messages")
|
|
break
|
|
}
|
|
|
|
processEvents(chunks)
|
|
token = chunks.End
|
|
if len(chunks.Chunk) < Page {
|
|
log.Println("it was the last page")
|
|
break
|
|
}
|
|
|
|
i += Page
|
|
page++
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func load() error {
|
|
ctx := context.Background()
|
|
var chunks *mautrix.RespMessages
|
|
log.Println("requesting messages from", room, "without pagination")
|
|
err := retry(func() error {
|
|
var messagesErr error
|
|
chunks, messagesErr = client.Messages(ctx, room, "", "", 'b', filter, Page)
|
|
|
|
return messagesErr
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
processEvents(chunks)
|
|
return nil
|
|
}
|
|
|
|
func processEvents(resp *mautrix.RespMessages) {
|
|
log.Println("parsing messages chunk:", len(resp.Chunk), "events")
|
|
for _, evt := range resp.Chunk {
|
|
_, ignore := ignored[evt.Sender]
|
|
if ignore {
|
|
continue
|
|
}
|
|
|
|
message := parseMessage(evt)
|
|
if message == nil {
|
|
continue
|
|
}
|
|
addMessage(message)
|
|
}
|
|
}
|
|
|
|
func addMessage(message *Message) {
|
|
if message.Replace != "" {
|
|
message.ID = message.Replace
|
|
message.ReplacedNote = " (updated)"
|
|
}
|
|
|
|
msg, ok := msgmap[message.ID]
|
|
if !ok {
|
|
msgmap[message.ID] = message
|
|
return
|
|
}
|
|
|
|
if msg.CreatedAtFull.Before(message.CreatedAtFull) {
|
|
msgmap[message.ID] = message
|
|
}
|
|
}
|
|
|
|
func parseMessage(evt *event.Event) *Message {
|
|
err := evt.Content.ParseRaw(event.EventMessage)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
var replace id.EventID
|
|
content := evt.Content.AsMessage()
|
|
text := content.Body
|
|
html := content.FormattedBody
|
|
if content.NewContent != nil {
|
|
text = content.NewContent.Body
|
|
html = content.NewContent.FormattedBody
|
|
}
|
|
if content.RelatesTo != nil {
|
|
replace = content.RelatesTo.GetReplaceID()
|
|
}
|
|
|
|
if text == "" && html == "" {
|
|
return nil
|
|
}
|
|
|
|
createdAt := time.UnixMilli(evt.Timestamp).UTC()
|
|
return &Message{
|
|
ID: evt.ID,
|
|
Replace: replace,
|
|
Author: evt.Sender,
|
|
Text: text,
|
|
HTML: html,
|
|
CreatedAt: createdAt.Format("2006-01-02 15:04 MST"),
|
|
CreatedAtFull: createdAt,
|
|
}
|
|
}
|