Basic backlogging

This commit is contained in:
Alex 2020-02-21 19:28:00 +01:00
parent e1b838d304
commit b0644c3a17
5 changed files with 51 additions and 5 deletions

View File

@ -230,7 +230,7 @@ func (a *Account) eventInternal(event *Event) error {
err = mx.RoomInvite(mx_room_id, mx_user_id)
if err != nil {
if strings.Contains(err.Error(), "already in the room") {
err = nil
return nil
}
return err
}
@ -260,6 +260,16 @@ func (a *Account) eventInternal(event *Event) error {
}
}
if event.Id != "" {
cache_key := fmt.Sprintf("%s/event_seen/%s/%s",
a.Protocol, mx_room_id, event.Id)
if !dbCacheTestAndSet(cache_key, "yes") {
// false: cache key was not modified, meaning we
// already saw the event
return nil
}
}
typ := "m.text"
if event.Type == EVENT_ACTION {
typ = "m.emote"

View File

@ -98,6 +98,11 @@ const (
type Event struct {
Type EventType
// If non-empty, the event Id is used to deduplicate events in a channel
// This is usefull for backends that provide a backlog of channel messages
// when (re-)joining a room
Id string
// UserID of the user that sent the event
// If this is a direct message event, this event can only have been authored
// by the user we are talking to (and not by ourself)
@ -120,12 +125,18 @@ type Event struct {
type UserInfo struct {
DisplayName string
// If non-empty, the Filename of the avatar object will be used by Easybridge
// to deduplicate the update events and prevent needless reuploads.
// Example strategy that works for the mattermost backend: use the update timestamp as fictious file name
Avatar MediaObject
}
type RoomInfo struct {
Name string
Topic string
// Same deduplication comment as for UserInfo.Avatar
Picture MediaObject
}

View File

@ -354,6 +354,22 @@ func (mm *Mattermost) handleConnected() {
} else {
log.Warnf("Could not get channel members: %s", resp.Error)
}
// Read backlog
// TODO: remember what was the last seen post in this channel
backlog, resp := mm.conn.Client.GetPostsForChannel(ch.Id, 0, 1000, "")
if resp.Error == nil {
for i := 0; i < len(backlog.Order); i++ {
post_id := backlog.Order[len(backlog.Order)-i-1]
post := backlog.Posts[post_id]
post_time := time.Unix(post.CreateAt/1000, 0)
post.Message = fmt.Sprintf("[%s] %s",
post_time.Format("2006-01-02 15:04:05 MST"), post.Message)
mm.handlePost(ch.Name, post, true)
}
} else {
log.Warnf("Could not get channel backlog: %s", resp.Error)
}
}
}
@ -425,6 +441,10 @@ func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error {
return err
}
return mm.handlePost(channel_name, &post, false)
}
func (mm *Mattermost) handlePost(channel_name string, post *model.Post, only_messages bool) error {
// Skip self messages
if post.UserId == mm.conn.User.Id {
return nil
@ -440,6 +460,7 @@ func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error {
// Build message event
msg_ev := &Event{
Id: post.Id,
Author: userId,
Text: post.Message,
Type: EVENT_MESSAGE,
@ -489,10 +510,12 @@ func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error {
mm.ensureJoined(user, roomId)
if post.Type == "system_header_change" {
new_header := post.Props["new_header"].(string)
mm.handler.RoomInfoUpdated(roomId, userId, &RoomInfo{
Topic: new_header,
})
if !only_messages {
new_header := post.Props["new_header"].(string)
mm.handler.RoomInfoUpdated(roomId, userId, &RoomInfo{
Topic: new_header,
})
}
} else if post.Type == "" || post.Type == "me" {
msg_ev.Room = roomId
mm.handler.Event(msg_ev)

View File

@ -102,6 +102,7 @@ func readRegistration(file string) mxlib.Registration {
AsToken: hex.EncodeToString(rnd[:32]),
HsToken: hex.EncodeToString(rnd[32:]),
SenderLocalpart: "_ezbr_",
RateLimited: false,
Namespaces: mxlib.RegistrationNamespaceSet{
Users: []mxlib.RegistrationNamespace{
mxlib.RegistrationNamespace{

View File

@ -10,6 +10,7 @@ type Registration struct {
AsToken string `yaml:"as_token"`
HsToken string `yaml:"hs_token"`
SenderLocalpart string `yaml:"sender_localpart"`
RateLimited bool `yaml:"rate_limited"`
Namespaces RegistrationNamespaceSet `yaml:"namespaces"`
}