Use message store to reference the same message from multiple models

This commit is contained in:
Christian Muehlhaeuser 2019-05-23 15:24:01 +02:00
parent cab56f17d4
commit 0487a7bd15
No known key found for this signature in database
GPG key ID: 3CF9FA45CA1EBB7E
3 changed files with 197 additions and 78 deletions

View file

@ -3,55 +3,10 @@ package main
import (
"fmt"
"log"
"strings"
"github.com/muesli/telephant/accounts"
)
// messageFromEvent creates a new Message object from an incoming MessageEvent.
func messageFromEvent(event accounts.MessageEvent) *Message {
var p = NewMessage(nil)
p.MessageID = event.Post.MessageID
p.PostURL = event.Post.URL
p.Name = event.Post.AuthorName
p.Author = event.Post.Author
p.AuthorURL = event.Post.AuthorURL
p.AuthorID = event.Post.AuthorID
p.Avatar = event.Post.Avatar
p.Body = strings.TrimSpace(event.Post.Body)
p.CreatedAt = event.Post.CreatedAt
p.Reply = event.Reply
p.ReplyToID = event.Post.ReplyToID
p.ReplyToAuthor = event.Post.ReplyToAuthor
p.Forward = event.Forward
p.Mention = event.Mention
p.Like = event.Like
p.Followed = event.Followed
p.Actor = event.Post.Actor
p.ActorName = event.Post.ActorName
p.ActorID = event.Post.ActorID
p.Liked = event.Post.Liked
p.Shared = event.Post.Shared
if len(event.Media) > 0 {
for _, v := range event.Media {
p.MediaPreview = append(p.MediaPreview, v.Preview)
p.MediaURL = append(p.MediaURL, v.URL)
}
}
if p.Followed {
p.Actor = event.Follow.Account
p.ActorName = event.Follow.Name
p.Avatar = event.Follow.Avatar
p.AuthorURL = event.Follow.ProfileURL
p.AuthorID = event.Follow.ProfileID
p.Following = event.Follow.Following
p.FollowedBy = event.Follow.FollowedBy
}
return p
}
// handleEvents handles incoming events and puts them into the right models
func handleEvents(eventsIn chan interface{}, messages *MessageModel) {
for {

View file

@ -53,42 +53,11 @@ type MessageModel struct {
_ func(*Message) `slot:"addMessage"`
_ func(*Message) `slot:"appendMessage"`
_ func(row int) `slot:"removeMessage"`
_ func(int) `slot:"removeMessage"`
_ func(string) `slot:"removeMessageID"`
_ func() `slot:"clear"`
}
// Message represents a single message
type Message struct {
core.QObject
Name string
MessageID string
PostURL string
Author string
AuthorURL string
AuthorID string
Avatar string
Body string
CreatedAt time.Time
Actor string
ActorName string
ActorID string
Reply bool
ReplyToID string
ReplyToAuthor string
Forward bool
Mention bool
Like bool
Followed bool
Following bool
FollowedBy bool
MediaPreview []string
MediaURL []string
Editing bool
Liked bool
Shared bool
}
func (m *MessageModel) init() {
m.SetRoles(map[int]*core.QByteArray{
Name: core.NewQByteArray2("name", -1),
@ -161,6 +130,10 @@ func (m *MessageModel) data(index *core.QModelIndex, role int) *core.QVariant {
}
var p = m.Messages()[len(m.Messages())-1-index.Row()]
if p == nil {
return core.NewQVariant()
}
switch role {
case Name:
{
@ -294,6 +267,7 @@ func (m *MessageModel) clear() {
func (m *MessageModel) addMessage(p *Message) {
m.BeginInsertRows(core.NewQModelIndex(), 0, 0)
addMessage(m, p)
m.SetMessages(append(m.Messages(), p))
m.EndInsertRows()
@ -304,6 +278,7 @@ func (m *MessageModel) addMessage(p *Message) {
func (m *MessageModel) appendMessage(p *Message) {
m.BeginInsertRows(core.NewQModelIndex(), len(m.Messages()), len(m.Messages()))
addMessage(m, p)
m.SetMessages(append([]*Message{p}, m.Messages()...))
m.EndInsertRows()
}
@ -311,10 +286,21 @@ func (m *MessageModel) appendMessage(p *Message) {
func (m *MessageModel) removeMessage(row int) {
trow := len(m.Messages()) - 1 - row
m.BeginRemoveRows(core.NewQModelIndex(), row, row)
removeMessage(m, m.Messages()[trow])
m.SetMessages(append(m.Messages()[:trow], m.Messages()[trow+1:]...))
m.EndRemoveRows()
}
func (m *MessageModel) removeMessageID(id string) {
for idx, v := range m.Messages() {
if v.MessageID == id {
trow := len(m.Messages()) - 1 - idx
m.removeMessage(trow)
break
}
}
}
func (m *MessageModel) updateMessageTime() {
if len(m.Messages()) > 0 {
var fIndex = m.Index(0, 0, core.NewQModelIndex())

178
messagestore.go Normal file
View file

@ -0,0 +1,178 @@
package main
import (
"fmt"
"log"
"strings"
"sync"
"time"
"github.com/davecgh/go-spew/spew"
"github.com/muesli/telephant/accounts"
"github.com/therecipe/qt/core"
)
// Message holds the data for a message
type Message struct {
core.QObject
Name string
MessageID string
PostURL string
Author string
AuthorURL string
AuthorID string
Avatar string
Body string
CreatedAt time.Time
Actor string
ActorName string
ActorID string
Reply bool
ReplyToID string
ReplyToAuthor string
Forward bool
Mention bool
Like bool
Followed bool
Following bool
FollowedBy bool
MediaPreview []string
MediaURL []string
Editing bool
Liked bool
Shared bool
}
var (
store = make(map[string]*Message)
modelReferences = make(map[string][]*MessageModel)
mutex sync.RWMutex
)
func addMessage(model *MessageModel, m *Message) {
fmt.Println("store", m.MessageID)
mutex.Lock()
defer mutex.Unlock()
store[m.MessageID] = m
modelReferences[m.MessageID] = append(modelReferences[m.MessageID], model)
}
func removeMessage(model *MessageModel, m *Message) {
fmt.Println("remove", m.MessageID)
mutex.RLock()
ref := modelReferences[m.MessageID]
mutex.RUnlock()
var models []*MessageModel
for _, v := range ref {
if v == model {
continue
}
models = append(models, v)
}
mutex.Lock()
defer mutex.Unlock()
if len(models) == 0 {
// last reference to message has been deleted
delete(modelReferences, m.MessageID)
delete(store, m.MessageID)
} else {
modelReferences[m.MessageID] = models
}
}
func deleteMessage(id string) {
fmt.Println("delete", id)
mutex.RLock()
ref := modelReferences[id]
mutex.RUnlock()
for _, v := range ref {
v.RemoveMessageID(id)
for idx, m := range v.Messages() {
if m.MessageID == id {
trow := len(v.Messages()) - 1 - idx
fmt.Println("Found message, deleting from model...", idx, trow)
v.RemoveMessage(trow)
break
}
}
}
fmt.Println("done deleting")
}
func getMessage(id string) *Message {
mutex.RLock()
defer mutex.RUnlock()
return store[id]
}
// messageFromEvent creates a new Message object from an incoming MessageEvent.
func messageFromEvent(event accounts.MessageEvent) *Message {
p := getMessage(event.Post.MessageID)
if p == nil {
p = NewMessage(nil)
}
p.Forward = event.Forward
p.Mention = event.Mention
p.Like = event.Like
p.Followed = event.Followed
p.Reply = event.Reply
if event.Post.MessageID != "" {
p.MessageID = event.Post.MessageID
p.PostURL = event.Post.URL
p.Name = event.Post.AuthorName
p.Author = event.Post.Author
p.AuthorURL = event.Post.AuthorURL
p.AuthorID = event.Post.AuthorID
p.Avatar = event.Post.Avatar
p.Body = strings.TrimSpace(event.Post.Body)
p.CreatedAt = event.Post.CreatedAt
p.ReplyToID = event.Post.ReplyToID
p.ReplyToAuthor = event.Post.ReplyToAuthor
p.Actor = event.Post.Actor
p.ActorName = event.Post.ActorName
p.ActorID = event.Post.ActorID
p.Liked = event.Post.Liked
p.Shared = event.Post.Shared
// parse attachments
p.MediaPreview = []string{}
p.MediaURL = []string{}
if len(event.Media) > 0 {
for _, v := range event.Media {
p.MediaPreview = append(p.MediaPreview, v.Preview)
p.MediaURL = append(p.MediaURL, v.URL)
}
}
}
if event.Followed {
p.MessageID = event.Follow.Account
p.Actor = event.Follow.Account
p.ActorName = event.Follow.Name
p.Avatar = event.Follow.Avatar
p.AuthorURL = event.Follow.ProfileURL
p.AuthorID = event.Follow.ProfileID
p.Following = event.Follow.Following
p.FollowedBy = event.Follow.FollowedBy
}
if p.MessageID == "" {
spw := &spew.ConfigState{Indent: " ", DisableCapacities: true, DisablePointerAddresses: true}
log.Println("Invalid message received:", spw.Sdump(event))
}
return p
}