Skip to content

Commit

Permalink
chats list performance
Browse files Browse the repository at this point in the history
  • Loading branch information
flexsurfer committed Sep 20, 2021
1 parent fb21876 commit 59eeed9
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 15 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.87.0
0.87.1
57 changes: 57 additions & 0 deletions protocol/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,63 @@ type Chat struct {
SyncedFrom uint32 `json:"syncedFrom,omitempty"`
}

type ChatPreview struct {
// ID is the id of the chat, for public chats it is the name e.g. status, for one-to-one
// is the hex encoded public key and for group chats is a random uuid appended with
// the hex encoded pk of the creator of the chat
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Color string `json:"color"`
// Active indicates whether the chat has been soft deleted
Active bool `json:"active"`

ChatType ChatType `json:"chatType"`

// Timestamp indicates the last time this chat has received/sent a message
Timestamp int64 `json:"timestamp"`
// LastClockValue indicates the last clock value to be used when sending messages
LastClockValue uint64 `json:"lastClockValue"`
// DeletedAtClockValue indicates the clock value at time of deletion, messages
// with lower clock value of this should be discarded
DeletedAtClockValue uint64 `json:"deletedAtClockValue"`

// Denormalized fields
UnviewedMessagesCount uint `json:"unviewedMessagesCount"`
UnviewedMentionsCount uint `json:"unviewedMentionsCount"`

// Generated username name of the chat for one-to-ones
Alias string `json:"alias,omitempty"`
// Identicon generated from public key
Identicon string `json:"identicon"`

// Muted is used to check whether we want to receive
// push notifications for this chat
Muted bool `json:"muted,omitempty"`

// Public key of user profile
Profile string `json:"profile,omitempty"`

// CommunityID is the id of the community it belongs to
CommunityID string `json:"communityId,omitempty"`

// CategoryID is the id of the community category this chat belongs to.
CategoryID string `json:"categoryId,omitempty"`

// Joined is a timestamp that indicates when the chat was joined
Joined int64 `json:"joined,omitempty"`

// SyncedTo is the time up until it has synced with a mailserver
SyncedTo uint32 `json:"syncedTo,omitempty"`

// SyncedFrom is the time from when it was synced with a mailserver
SyncedFrom uint32 `json:"syncedFrom,omitempty"`

Text string `json:"text,omitempty"`

ContentType protobuf.ChatMessage_ContentType `json:"contentType,omitempty"`
}

func (c *Chat) PublicKey() (*ecdsa.PublicKey, error) {
// For one to one chatID is an encoded public key
if c.ChatType != ChatTypeOneToOne {
Expand Down
10 changes: 0 additions & 10 deletions protocol/messenger.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ type Messenger struct {
shouldPublishContactCode bool
systemMessagesTranslations *systemMessageTranslationsMap
allChats *chatMap
latestNActiveChats []*Chat
allContacts *contactMap
allInstallations *installationMap
modifiedInstallations *stringBoolMap
Expand Down Expand Up @@ -1031,7 +1030,6 @@ func (m *Messenger) Init() error {
// Get chat IDs and public keys from the existing chats.
// TODO: Get only active chats by the query.
chats, err := m.persistence.Chats()
i := 0
if err != nil {
return err
}
Expand All @@ -1043,14 +1041,6 @@ func (m *Messenger) Init() error {

m.allChats.Store(chat.ID, chat)

// if a user has thousands of chats
// we want to have quick access to the latest 60 sorted active chats, to show them first to the user
// 60 is the 3 screens of chats, so when user will scroll to the end we'll load all chats
if i < 60 {
m.latestNActiveChats = append(m.latestNActiveChats, chat)
i++
}

if !chat.Active || chat.Timeline() {
continue
}
Expand Down
54 changes: 52 additions & 2 deletions protocol/messenger_chats.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"

"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/requests"
"github.com/status-im/status-go/protocol/transport"
)
Expand All @@ -20,8 +21,57 @@ func (m *Messenger) Chats() []*Chat {
return chats
}

func (m *Messenger) LatestActiveChats() []*Chat {
return m.latestNActiveChats
func (m *Messenger) ChatsPreview() []*ChatPreview {
var chats []*ChatPreview

m.allChats.Range(func(chatID string, chat *Chat) (shouldContinue bool) {
if chat.Active {
chatPreview := &ChatPreview{
ID: chat.ID,
Name: chat.Name,
Description: chat.Description,
Color: chat.Color,
Active: chat.Active,
ChatType: chat.ChatType,
Timestamp: chat.Timestamp,
LastClockValue: chat.LastClockValue,
DeletedAtClockValue: chat.DeletedAtClockValue,
UnviewedMessagesCount: chat.UnviewedMessagesCount,
UnviewedMentionsCount: chat.UnviewedMentionsCount,
Alias: chat.Alias,
Identicon: chat.Identicon,
Muted: chat.Muted,
Profile: chat.Profile,
CommunityID: chat.CommunityID,
CategoryID: chat.CategoryID,
Joined: chat.Joined,
SyncedTo: chat.SyncedTo,
SyncedFrom: chat.SyncedFrom,
}
if chat.LastMessage != nil {
chatPreview.ContentType = chat.LastMessage.ContentType
if chat.LastMessage.ContentType == protobuf.ChatMessage_TEXT_PLAIN {
if len(chat.LastMessage.Text) > 200 {
chatPreview.Text = chat.LastMessage.Text[:200]
} else {
chatPreview.Text = chat.LastMessage.Text
}
}
}

chats = append(chats, chatPreview)
}

return true
})

return chats
}

func (m *Messenger) Chat(chatID string) *Chat {
chat, _ := m.allChats.Load(chatID)

return chat
}

func (m *Messenger) ActiveChats() []*Chat {
Expand Down
8 changes: 6 additions & 2 deletions services/ext/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,12 @@ func (api *PublicAPI) Chats(parent context.Context) []*protocol.Chat {
return api.service.messenger.Chats()
}

func (api *PublicAPI) LatestActiveChats(parent context.Context) []*protocol.Chat {
return api.service.messenger.LatestActiveChats()
func (api *PublicAPI) ChatsPreview(parent context.Context) []*protocol.ChatPreview {
return api.service.messenger.ChatsPreview()
}

func (api *PublicAPI) Chat(parent context.Context, chatID string) *protocol.Chat {
return api.service.messenger.Chat(chatID)
}

func (api *PublicAPI) ActiveChats(parent context.Context) []*protocol.Chat {
Expand Down

0 comments on commit 59eeed9

Please sign in to comment.