Add support for redactions. Fixes #19

This commit is contained in:
Tulir Asokan 2019-06-16 20:42:13 +03:00
parent 691708a76e
commit d1d129f6cf
6 changed files with 142 additions and 1 deletions

2
go.mod
View File

@ -25,7 +25,7 @@ require (
gopkg.in/russross/blackfriday.v2 v2.0.1 gopkg.in/russross/blackfriday.v2 v2.0.1
gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2 gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2
gopkg.in/yaml.v2 v2.2.2 gopkg.in/yaml.v2 v2.2.2
maunium.net/go/mautrix v0.1.0-alpha.3.0.20190616163219-6b4bce05f314 maunium.net/go/mautrix v0.1.0-alpha.3.0.20190616174145-055ff7b0fa6a
maunium.net/go/mauview v0.0.0-20190606152754-de9e0a754a5d maunium.net/go/mauview v0.0.0-20190606152754-de9e0a754a5d
maunium.net/go/tcell v0.0.0-20190606152714-9a88fc07b3ed maunium.net/go/tcell v0.0.0-20190606152714-9a88fc07b3ed
) )

2
go.sum
View File

@ -98,6 +98,8 @@ maunium.net/go/mautrix v0.1.0-alpha.3.0.20190616140407-62f6f484857e h1:W3NG02SHY
maunium.net/go/mautrix v0.1.0-alpha.3.0.20190616140407-62f6f484857e/go.mod h1:O+QWJP3H7BZEzIBSrECKpnpRnEKBwaoWVEu/yZwVwxg= maunium.net/go/mautrix v0.1.0-alpha.3.0.20190616140407-62f6f484857e/go.mod h1:O+QWJP3H7BZEzIBSrECKpnpRnEKBwaoWVEu/yZwVwxg=
maunium.net/go/mautrix v0.1.0-alpha.3.0.20190616163219-6b4bce05f314 h1:wGlIqs/L+ErBbAHbkpM4AlFi+9+z9Bsle4xD4Gw+y3k= maunium.net/go/mautrix v0.1.0-alpha.3.0.20190616163219-6b4bce05f314 h1:wGlIqs/L+ErBbAHbkpM4AlFi+9+z9Bsle4xD4Gw+y3k=
maunium.net/go/mautrix v0.1.0-alpha.3.0.20190616163219-6b4bce05f314/go.mod h1:O+QWJP3H7BZEzIBSrECKpnpRnEKBwaoWVEu/yZwVwxg= maunium.net/go/mautrix v0.1.0-alpha.3.0.20190616163219-6b4bce05f314/go.mod h1:O+QWJP3H7BZEzIBSrECKpnpRnEKBwaoWVEu/yZwVwxg=
maunium.net/go/mautrix v0.1.0-alpha.3.0.20190616174145-055ff7b0fa6a h1:DenEIDOOumsU8zDzj5ePQOSaKsxjAxW7UESJ2xo1lxM=
maunium.net/go/mautrix v0.1.0-alpha.3.0.20190616174145-055ff7b0fa6a/go.mod h1:O+QWJP3H7BZEzIBSrECKpnpRnEKBwaoWVEu/yZwVwxg=
maunium.net/go/mauview v0.0.0-20190606152754-de9e0a754a5d h1:H4wZ4vMVnOh5QFsb4xZtssgpv3DDEkBRzQ8iyEg2fX0= maunium.net/go/mauview v0.0.0-20190606152754-de9e0a754a5d h1:H4wZ4vMVnOh5QFsb4xZtssgpv3DDEkBRzQ8iyEg2fX0=
maunium.net/go/mauview v0.0.0-20190606152754-de9e0a754a5d/go.mod h1:GL+akv58wNFzzX4IKLvryKx0F/AcYKHql35DiBzBc/w= maunium.net/go/mauview v0.0.0-20190606152754-de9e0a754a5d/go.mod h1:GL+akv58wNFzzX4IKLvryKx0F/AcYKHql35DiBzBc/w=
maunium.net/go/tcell v0.0.0-20190606152714-9a88fc07b3ed h1:sAcUrUZG2LFWBTkTtLKPQvHPHFM5d6huAhr5ZZuxtbQ= maunium.net/go/tcell v0.0.0-20190606152714-9a88fc07b3ed h1:sAcUrUZG2LFWBTkTtLKPQvHPHFM5d6huAhr5ZZuxtbQ=

View File

@ -21,6 +21,7 @@ import (
"compress/gzip" "compress/gzip"
"encoding/binary" "encoding/binary"
"encoding/gob" "encoding/gob"
"errors"
sync "github.com/sasha-s/go-deadlock" sync "github.com/sasha-s/go-deadlock"
bolt "go.etcd.io/bbolt" bolt "go.etcd.io/bbolt"
@ -107,6 +108,37 @@ func (hm *HistoryManager) Get(room *rooms.Room, eventID string) (event *mautrix.
return return
} }
var EventNotFoundError = errors.New("event not found")
func (hm *HistoryManager) Update(room *rooms.Room, eventID string, update func(event *mautrix.Event) error) error {
return hm.db.Update(func (tx *bolt.Tx) error {
rid := []byte(room.ID)
eventIDs := tx.Bucket(bucketRoomEventIDs).Bucket(rid)
if eventIDs == nil {
return nil
}
streamIndex := eventIDs.Get([]byte(eventID))
if streamIndex == nil {
return nil
}
stream := tx.Bucket(bucketRoomStreams).Bucket(rid)
eventData := stream.Get(streamIndex)
if eventData == nil {
return EventNotFoundError
}
if event, err := unmarshalEvent(eventData); err != nil {
return err
} else if err = update(event); err != nil {
return err
} else if eventData, err = marshalEvent(event); err != nil {
return err
} else {
return stream.Put(streamIndex, eventData)
}
})
}
func (hm *HistoryManager) Append(room *rooms.Room, events []*mautrix.Event) error { func (hm *HistoryManager) Append(room *rooms.Room, events []*mautrix.Event) error {
return hm.store(room, events, true) return hm.store(room, events, true)
} }

View File

@ -209,6 +209,7 @@ func (c *Container) OnLogin() {
// Just pass encrypted events as messages, they'll show up with an encryption unsupported message. // Just pass encrypted events as messages, they'll show up with an encryption unsupported message.
c.syncer.OnEventType(mautrix.EventEncrypted, c.HandleMessage) c.syncer.OnEventType(mautrix.EventEncrypted, c.HandleMessage)
c.syncer.OnEventType(mautrix.EventSticker, c.HandleMessage) c.syncer.OnEventType(mautrix.EventSticker, c.HandleMessage)
c.syncer.OnEventType(mautrix.EventRedaction, c.HandleRedaction)
c.syncer.OnEventType(mautrix.StateAliases, c.HandleMessage) c.syncer.OnEventType(mautrix.StateAliases, c.HandleMessage)
c.syncer.OnEventType(mautrix.StateCanonicalAlias, c.HandleMessage) c.syncer.OnEventType(mautrix.StateCanonicalAlias, c.HandleMessage)
c.syncer.OnEventType(mautrix.StateTopic, c.HandleMessage) c.syncer.OnEventType(mautrix.StateTopic, c.HandleMessage)
@ -307,6 +308,41 @@ func (c *Container) SendPreferencesToMatrix() {
} }
} }
func (c *Container) HandleRedaction(source EventSource, evt *mautrix.Event) {
room := c.GetOrCreateRoom(evt.RoomID)
var redactedEvt *mautrix.Event
err := c.history.Update(room, evt.Redacts, func(redacted *mautrix.Event) error {
redacted.Unsigned.RedactedBy = evt.ID
redacted.Unsigned.RedactedBecause = evt
redactedEvt = redacted
return nil
})
if err != nil {
debug.Print("Failed to mark", evt.Redacts, "as redacted:", err)
}
if !room.Loaded() {
return
}
mainView := c.ui.MainView()
roomView := mainView.GetRoom(evt.RoomID)
if roomView == nil {
debug.Printf("Failed to handle event %v: No room view found.", evt)
return
}
// TODO make this less hacky?
message := roomView.ParseEvent(redactedEvt)
if message != nil {
roomView.AddMessage(message)
if c.syncer.FirstSyncDone {
c.ui.Render()
}
}
}
// HandleMessage is the event handler for the m.room.message timeline event. // HandleMessage is the event handler for the m.room.message timeline event.
func (c *Container) HandleMessage(source EventSource, evt *mautrix.Event) { func (c *Container) HandleMessage(source EventSource, evt *mautrix.Event) {
room := c.GetOrCreateRoom(evt.RoomID) room := c.GetOrCreateRoom(evt.RoomID)

View File

@ -69,6 +69,9 @@ func directParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix
if member != nil { if member != nil {
displayname = member.Displayname displayname = member.Displayname
} }
if evt.Unsigned.RedactedBecause != nil || evt.Type == mautrix.EventRedaction {
return NewRedactedMessage(evt, displayname)
}
switch evt.Type { switch evt.Type {
case mautrix.EventSticker: case mautrix.EventSticker:
evt.Content.MsgType = mautrix.MsgImage evt.Content.MsgType = mautrix.MsgImage

View File

@ -0,0 +1,68 @@
// gomuks - A terminal Matrix client written in Go.
// Copyright (C) 2019 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package messages
import (
ifc "maunium.net/go/gomuks/interface"
"maunium.net/go/mautrix"
"maunium.net/go/mauview"
"maunium.net/go/tcell"
"maunium.net/go/gomuks/config"
)
type RedactedMessage struct{}
func NewRedactedMessage(event *mautrix.Event, displayname string) *UIMessage {
return newUIMessage(event, displayname, &RedactedMessage{})
}
func (msg *RedactedMessage) Clone() MessageRenderer {
return &RedactedMessage{}
}
func (msg *RedactedMessage) NotificationContent() string {
return ""
}
func (msg *RedactedMessage) PlainText() string {
return "[redacted]"
}
func (msg *RedactedMessage) String() string {
return "&messages.RedactedMessage{}"
}
func (msg *RedactedMessage) CalculateBuffer(prefs config.UserPreferences, width int, uiMsg *UIMessage) {
}
func (msg *RedactedMessage) Height() int {
return 1
}
const RedactionChar = '█'
const RedactionMaxWidth = 40
var RedactionStyle = tcell.StyleDefault.Foreground(tcell.NewRGBColor(50, 0, 0))
func (msg *RedactedMessage) Draw(screen mauview.Screen) {
w, _ := screen.Size()
for x := 0; x < w && x < RedactionMaxWidth; x++ {
screen.SetContent(x, 0, RedactionChar, nil, RedactionStyle)
}
}
func (msg *RedactedMessage) RegisterMatrix(matrix ifc.MatrixContainer) {}