status-go/protocol/messenger_response.go

776 lines
24 KiB
Go

package protocol
import (
"encoding/json"
"github.com/status-im/status-go/protocol/identity"
"github.com/status-im/status-go/services/browsers"
"github.com/status-im/status-go/services/wallet"
"github.com/status-im/status-go/appmetrics"
"github.com/status-im/status-go/images"
"github.com/status-im/status-go/multiaccounts/accounts"
"github.com/status-im/status-go/multiaccounts/keypairs"
"github.com/status-im/status-go/multiaccounts/settings"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/communities"
"github.com/status-im/status-go/protocol/discord"
"github.com/status-im/status-go/protocol/encryption/multidevice"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/verification"
localnotifications "github.com/status-im/status-go/services/local-notifications"
"github.com/status-im/status-go/services/mailservers"
)
type RemovedMessage struct {
ChatID string `json:"chatId"`
MessageID string `json:"messageId"`
DeletedBy string `json:"deletedBy,omitempty"`
}
type ClearedHistory struct {
ChatID string `json:"chatId"`
ClearedAt uint64 `json:"clearedAt"`
}
type MessengerResponse struct {
Contacts []*Contact
Installations []*multidevice.Installation
Invitations []*GroupChatInvitation
CommunityChanges []*communities.CommunityChanges
RequestsToJoinCommunity []*communities.RequestToJoin
AnonymousMetrics []*appmetrics.AppMetric
Mailservers []mailservers.Mailserver
Bookmarks []*browsers.Bookmark
Settings []*settings.SyncSettingField
IdentityImages []images.IdentityImage
Accounts []*accounts.Account
DiscordCategories []*discord.Category
DiscordChannels []*discord.Channel
DiscordOldestMessageTimestamp int
BackupHandled bool
// notifications a list of notifications derived from messenger events
// that are useful to notify the user about
notifications map[string]*localnotifications.Notification
chats map[string]*Chat
removedChats map[string]bool
removedMessages map[string]*RemovedMessage
communities map[string]*communities.Community
communitiesSettings map[string]*communities.CommunitySettings
activityCenterNotifications map[string]*ActivityCenterNotification
activityCenterState *ActivityCenterState
messages map[string]*common.Message
pinMessages map[string]*common.PinMessage
discordMessages map[string]*protobuf.DiscordMessage
discordMessageAttachments map[string]*protobuf.DiscordMessageAttachment
discordMessageAuthors map[string]*protobuf.DiscordMessageAuthor
currentStatus *UserStatus
statusUpdates map[string]UserStatus
clearedHistories map[string]*ClearedHistory
verificationRequests map[string]*verification.Request
trustStatus map[string]verification.TrustStatus
emojiReactions map[string]*EmojiReaction
savedAddresses map[string]*wallet.SavedAddress
keycards []*keypairs.KeyPair
keycardActions []*keypairs.KeycardAction
socialLinkSettings []*identity.SocialLink
}
func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
responseItem := struct {
Chats []*Chat `json:"chats,omitempty"`
RemovedChats []string `json:"removedChats,omitempty"`
RemovedMessages []*RemovedMessage `json:"removedMessages,omitempty"`
Messages []*common.Message `json:"messages,omitempty"`
Contacts []*Contact `json:"contacts,omitempty"`
Installations []*multidevice.Installation `json:"installations,omitempty"`
PinMessages []*common.PinMessage `json:"pinMessages,omitempty"`
EmojiReactions []*EmojiReaction `json:"emojiReactions,omitempty"`
Invitations []*GroupChatInvitation `json:"invitations,omitempty"`
CommunityChanges []*communities.CommunityChanges `json:"communityChanges,omitempty"`
RequestsToJoinCommunity []*communities.RequestToJoin `json:"requestsToJoinCommunity,omitempty"`
Mailservers []mailservers.Mailserver `json:"mailservers,omitempty"`
Bookmarks []*browsers.Bookmark `json:"bookmarks,omitempty"`
ClearedHistories []*ClearedHistory `json:"clearedHistories,omitempty"`
VerificationRequests []*verification.Request `json:"verificationRequests,omitempty"`
TrustStatus map[string]verification.TrustStatus `json:"trustStatus,omitempty"`
// Notifications a list of notifications derived from messenger events
// that are useful to notify the user about
Notifications []*localnotifications.Notification `json:"notifications"`
Communities []*communities.Community `json:"communities,omitempty"`
CommunitiesSettings []*communities.CommunitySettings `json:"communitiesSettings,omitempty"`
ActivityCenterNotifications []*ActivityCenterNotification `json:"activityCenterNotifications,omitempty"`
ActivityCenterState *ActivityCenterState `json:"activityCenterState,omitempty"`
CurrentStatus *UserStatus `json:"currentStatus,omitempty"`
StatusUpdates []UserStatus `json:"statusUpdates,omitempty"`
Settings []*settings.SyncSettingField `json:"settings,omitempty"`
IdentityImages []images.IdentityImage `json:"identityImages,omitempty"`
Accounts []*accounts.Account `json:"accounts,omitempty"`
DiscordCategories []*discord.Category `json:"discordCategories,omitempty"`
DiscordChannels []*discord.Channel `json:"discordChannels,omitempty"`
DiscordOldestMessageTimestamp int `json:"discordOldestMessageTimestamp"`
DiscordMessages []*protobuf.DiscordMessage `json:"discordMessages,omitempty"`
DiscordMessageAttachments []*protobuf.DiscordMessageAttachment `json:"discordMessageAtachments,omitempty"`
SavedAddresses []*wallet.SavedAddress `json:"savedAddresses,omitempty"`
Keycards []*keypairs.KeyPair `json:"keycards,omitempty"`
KeycardActions []*keypairs.KeycardAction `json:"keycardActions,omitempty"`
SocialLinkSettings []*identity.SocialLink `json:"socialLinkSettings,omitempty"`
}{
Contacts: r.Contacts,
Installations: r.Installations,
Invitations: r.Invitations,
CommunityChanges: r.CommunityChanges,
RequestsToJoinCommunity: r.RequestsToJoinCommunity,
Mailservers: r.Mailservers,
Bookmarks: r.Bookmarks,
CurrentStatus: r.currentStatus,
Settings: r.Settings,
IdentityImages: r.IdentityImages,
Accounts: r.Accounts,
Messages: r.Messages(),
VerificationRequests: r.VerificationRequests(),
SavedAddresses: r.SavedAddresses(),
Notifications: r.Notifications(),
Chats: r.Chats(),
Communities: r.Communities(),
CommunitiesSettings: r.CommunitiesSettings(),
RemovedChats: r.RemovedChats(),
RemovedMessages: r.RemovedMessages(),
ClearedHistories: r.ClearedHistories(),
ActivityCenterNotifications: r.ActivityCenterNotifications(),
ActivityCenterState: r.ActivityCenterState(),
PinMessages: r.PinMessages(),
EmojiReactions: r.EmojiReactions(),
StatusUpdates: r.StatusUpdates(),
DiscordCategories: r.DiscordCategories,
DiscordChannels: r.DiscordChannels,
DiscordOldestMessageTimestamp: r.DiscordOldestMessageTimestamp,
Keycards: r.AllKnownKeycards(),
KeycardActions: r.KeycardActions(),
SocialLinkSettings: r.SocialLinkSettings(),
}
responseItem.TrustStatus = r.TrustStatus()
return json.Marshal(responseItem)
}
func (r *MessengerResponse) Chats() []*Chat {
var chats []*Chat
for _, chat := range r.chats {
chats = append(chats, chat)
}
return chats
}
func (r *MessengerResponse) RemovedChats() []string {
var chats []string
for chatID := range r.removedChats {
chats = append(chats, chatID)
}
return chats
}
func (r *MessengerResponse) RemovedMessages() []*RemovedMessage {
var messages []*RemovedMessage
for messageID := range r.removedMessages {
messages = append(messages, r.removedMessages[messageID])
}
return messages
}
func (r *MessengerResponse) ClearedHistories() []*ClearedHistory {
var clearedHistories []*ClearedHistory
for chatID := range r.clearedHistories {
clearedHistories = append(clearedHistories, r.clearedHistories[chatID])
}
return clearedHistories
}
func (r *MessengerResponse) Communities() []*communities.Community {
var communities []*communities.Community
for _, c := range r.communities {
communities = append(communities, c)
}
return communities
}
func (r *MessengerResponse) CommunitiesSettings() []*communities.CommunitySettings {
var settings []*communities.CommunitySettings
for _, s := range r.communitiesSettings {
settings = append(settings, s)
}
return settings
}
func (r *MessengerResponse) Notifications() []*localnotifications.Notification {
var notifications []*localnotifications.Notification
for _, n := range r.notifications {
notifications = append(notifications, n)
}
return notifications
}
func (r *MessengerResponse) VerificationRequests() []*verification.Request {
var verifications []*verification.Request
for _, v := range r.verificationRequests {
verifications = append(verifications, v)
}
return verifications
}
func (r *MessengerResponse) PinMessages() []*common.PinMessage {
var pinMessages []*common.PinMessage
for _, pm := range r.pinMessages {
pinMessages = append(pinMessages, pm)
}
return pinMessages
}
func (r *MessengerResponse) TrustStatus() map[string]verification.TrustStatus {
if len(r.trustStatus) == 0 {
return nil
}
result := make(map[string]verification.TrustStatus)
for contactID, trustStatus := range r.trustStatus {
result[contactID] = trustStatus
}
return result
}
func (r *MessengerResponse) StatusUpdates() []UserStatus {
var userStatus []UserStatus
for pk, s := range r.statusUpdates {
s.PublicKey = pk
userStatus = append(userStatus, s)
}
return userStatus
}
func (r *MessengerResponse) IsEmpty() bool {
return len(r.chats)+
len(r.messages)+
len(r.pinMessages)+
len(r.Contacts)+
len(r.Bookmarks)+
len(r.clearedHistories)+
len(r.Settings)+
len(r.Installations)+
len(r.Invitations)+
len(r.emojiReactions)+
len(r.communities)+
len(r.CommunityChanges)+
len(r.removedChats)+
len(r.removedMessages)+
len(r.Mailservers)+
len(r.IdentityImages)+
len(r.Accounts)+
len(r.notifications)+
len(r.statusUpdates)+
len(r.activityCenterNotifications)+
len(r.trustStatus)+
len(r.verificationRequests)+
len(r.RequestsToJoinCommunity)+
len(r.savedAddresses)+
len(r.keycards)+
len(r.keycardActions) == 0 &&
len(r.socialLinkSettings) == 0 &&
r.currentStatus == nil &&
r.activityCenterState == nil
}
// Merge takes another response and appends the new Chats & new Messages and replaces
// the existing Messages & Chats if they have the same ID
func (r *MessengerResponse) Merge(response *MessengerResponse) error {
if len(response.Invitations)+
len(response.RequestsToJoinCommunity)+
len(response.Mailservers)+
len(response.Bookmarks)+
len(response.clearedHistories)+
len(response.DiscordChannels)+
len(response.DiscordCategories) != 0 {
return ErrNotImplemented
}
r.AddChats(response.Chats())
r.AddRemovedChats(response.RemovedChats())
r.AddRemovedMessages(response.RemovedMessages())
r.AddNotifications(response.Notifications())
r.AddMessages(response.Messages())
r.AddContacts(response.Contacts)
r.AddCommunities(response.Communities())
r.AddPinMessages(response.PinMessages())
r.AddVerificationRequests(response.VerificationRequests())
r.AddTrustStatuses(response.trustStatus)
r.AddActivityCenterNotifications(response.ActivityCenterNotifications())
r.AddEmojiReactions(response.EmojiReactions())
r.AddInstallations(response.Installations)
r.AddSavedAddresses(response.SavedAddresses())
r.AddAllKnownKeycards(response.AllKnownKeycards())
r.AddKeycardActions(response.KeycardActions())
r.AddSocialLinkSettings(response.SocialLinkSettings())
r.CommunityChanges = append(r.CommunityChanges, response.CommunityChanges...)
r.BackupHandled = response.BackupHandled
return nil
}
func (r *MessengerResponse) AddCommunities(communities []*communities.Community) {
for _, overrideCommunity := range communities {
r.AddCommunity(overrideCommunity)
}
}
func (r *MessengerResponse) AddCommunity(c *communities.Community) {
if r.communities == nil {
r.communities = make(map[string]*communities.Community)
}
r.communities[c.IDString()] = c
}
func (r *MessengerResponse) AddCommunitySettings(c *communities.CommunitySettings) {
if r.communitiesSettings == nil {
r.communitiesSettings = make(map[string]*communities.CommunitySettings)
}
r.communitiesSettings[c.CommunityID] = c
}
func (r *MessengerResponse) AddRequestToJoinCommunity(requestToJoin *communities.RequestToJoin) {
r.RequestsToJoinCommunity = append(r.RequestsToJoinCommunity, requestToJoin)
}
func (r *MessengerResponse) AddSetting(s *settings.SyncSettingField) {
r.Settings = append(r.Settings, s)
}
func (r *MessengerResponse) AddBookmark(bookmark *browsers.Bookmark) {
r.Bookmarks = append(r.Bookmarks, bookmark)
}
func (r *MessengerResponse) AddBookmarks(bookmarks []*browsers.Bookmark) {
for _, b := range bookmarks {
r.AddBookmark(b)
}
}
func (r *MessengerResponse) AddVerificationRequest(vr *verification.Request) {
if r.verificationRequests == nil {
r.verificationRequests = make(map[string]*verification.Request)
}
r.verificationRequests[vr.ID] = vr
}
func (r *MessengerResponse) AddVerificationRequests(vrs []*verification.Request) {
for _, vr := range vrs {
r.AddVerificationRequest(vr)
}
}
func (r *MessengerResponse) AddTrustStatus(contactID string, trustStatus verification.TrustStatus) {
if r.trustStatus == nil {
r.trustStatus = make(map[string]verification.TrustStatus)
}
r.trustStatus[contactID] = trustStatus
}
func (r *MessengerResponse) AddTrustStatuses(ts map[string]verification.TrustStatus) {
if r.trustStatus == nil {
r.trustStatus = make(map[string]verification.TrustStatus)
}
for k, v := range ts {
r.trustStatus[k] = v
}
}
func (r *MessengerResponse) AddChat(c *Chat) {
if r.chats == nil {
r.chats = make(map[string]*Chat)
}
r.chats[c.ID] = c
}
func (r *MessengerResponse) AddChats(chats []*Chat) {
for _, c := range chats {
r.AddChat(c)
}
}
func (r *MessengerResponse) AddEmojiReactions(ers []*EmojiReaction) {
for _, e := range ers {
r.AddEmojiReaction(e)
}
}
func (r *MessengerResponse) AddEmojiReaction(er *EmojiReaction) {
if r.emojiReactions == nil {
r.emojiReactions = make(map[string]*EmojiReaction)
}
r.emojiReactions[er.ID()] = er
}
func (r *MessengerResponse) EmojiReactions() []*EmojiReaction {
var ers []*EmojiReaction
for _, er := range r.emojiReactions {
ers = append(ers, er)
}
return ers
}
func (r *MessengerResponse) AddSavedAddresses(ers []*wallet.SavedAddress) {
for _, e := range ers {
r.AddSavedAddress(e)
}
}
func (r *MessengerResponse) AddSavedAddress(er *wallet.SavedAddress) {
if r.savedAddresses == nil {
r.savedAddresses = make(map[string]*wallet.SavedAddress)
}
r.savedAddresses[er.ID()] = er
}
func (r *MessengerResponse) SavedAddresses() []*wallet.SavedAddress {
var ers []*wallet.SavedAddress
for _, er := range r.savedAddresses {
ers = append(ers, er)
}
return ers
}
func (r *MessengerResponse) AddAllKnownKeycards(keycards []*keypairs.KeyPair) {
r.keycards = append(r.keycards, keycards...)
}
func (r *MessengerResponse) AllKnownKeycards() []*keypairs.KeyPair {
return r.keycards
}
func (r *MessengerResponse) AddKeycardAction(keycardAction *keypairs.KeycardAction) {
r.keycardActions = append(r.keycardActions, keycardAction)
}
func (r *MessengerResponse) AddKeycardActions(keycardActions []*keypairs.KeycardAction) {
r.keycardActions = append(r.keycardActions, keycardActions...)
}
func (r *MessengerResponse) KeycardActions() []*keypairs.KeycardAction {
return r.keycardActions
}
func (r *MessengerResponse) AddSocialLinkSetting(socialLinkSettings *identity.SocialLink) {
r.socialLinkSettings = append(r.socialLinkSettings, socialLinkSettings)
}
func (r *MessengerResponse) AddSocialLinkSettings(socialLinkSettings []*identity.SocialLink) {
r.socialLinkSettings = append(r.socialLinkSettings, socialLinkSettings...)
}
func (r *MessengerResponse) SocialLinkSettings() []*identity.SocialLink {
return r.socialLinkSettings
}
func (r *MessengerResponse) AddNotification(n *localnotifications.Notification) {
if r.notifications == nil {
r.notifications = make(map[string]*localnotifications.Notification)
}
r.notifications[n.ID.String()] = n
}
func (r *MessengerResponse) ClearNotifications() {
r.notifications = nil
}
func (r *MessengerResponse) AddNotifications(notifications []*localnotifications.Notification) {
for _, c := range notifications {
r.AddNotification(c)
}
}
func (r *MessengerResponse) AddRemovedChats(chats []string) {
for _, c := range chats {
r.AddRemovedChat(c)
}
}
func (r *MessengerResponse) AddRemovedChat(chatID string) {
if r.removedChats == nil {
r.removedChats = make(map[string]bool)
}
r.removedChats[chatID] = true
}
func (r *MessengerResponse) AddRemovedMessages(messages []*RemovedMessage) {
for _, m := range messages {
r.AddRemovedMessage(m)
}
}
func (r *MessengerResponse) AddRemovedMessage(rm *RemovedMessage) {
if r.removedMessages == nil {
r.removedMessages = make(map[string]*RemovedMessage)
}
r.removedMessages[rm.MessageID] = rm
// Remove original message from the map
if len(r.messages) != 0 && r.messages[rm.MessageID] != nil {
delete(r.messages, rm.MessageID)
}
}
func (r *MessengerResponse) AddClearedHistory(ch *ClearedHistory) {
if r.clearedHistories == nil {
r.clearedHistories = make(map[string]*ClearedHistory)
}
existingClearedHistory, ok := r.clearedHistories[ch.ChatID]
if !ok || existingClearedHistory.ClearedAt < ch.ClearedAt {
r.clearedHistories[ch.ChatID] = ch
}
}
func (r *MessengerResponse) AddActivityCenterNotifications(ns []*ActivityCenterNotification) {
for _, n := range ns {
r.AddActivityCenterNotification(n)
}
}
func (r *MessengerResponse) AddActivityCenterNotification(n *ActivityCenterNotification) {
if r.activityCenterNotifications == nil {
r.activityCenterNotifications = make(map[string]*ActivityCenterNotification)
}
r.activityCenterNotifications[n.ID.String()] = n
}
func (r *MessengerResponse) RemoveActivityCenterNotification(id string) bool {
if r.activityCenterNotifications == nil {
return false
}
if _, ok := r.activityCenterNotifications[id]; ok {
delete(r.activityCenterNotifications, id)
return true
}
return false
}
func (r *MessengerResponse) ActivityCenterNotifications() []*ActivityCenterNotification {
var ns []*ActivityCenterNotification
for _, n := range r.activityCenterNotifications {
ns = append(ns, n)
}
return ns
}
func (r *MessengerResponse) SetActivityCenterState(activityCenterState *ActivityCenterState) {
r.activityCenterState = activityCenterState
}
func (r *MessengerResponse) ActivityCenterState() *ActivityCenterState {
return r.activityCenterState
}
func (r *MessengerResponse) AddPinMessage(pm *common.PinMessage) {
if r.pinMessages == nil {
r.pinMessages = make(map[string]*common.PinMessage)
}
r.pinMessages[pm.ID] = pm
}
func (r *MessengerResponse) AddPinMessages(pms []*common.PinMessage) {
for _, pm := range pms {
r.AddPinMessage(pm)
}
}
func (r *MessengerResponse) SetCurrentStatus(status UserStatus) {
r.currentStatus = &status
}
func (r *MessengerResponse) AddStatusUpdate(upd UserStatus) {
if r.statusUpdates == nil {
r.statusUpdates = make(map[string]UserStatus)
}
r.statusUpdates[upd.PublicKey] = upd
}
func (r *MessengerResponse) DiscordMessages() []*protobuf.DiscordMessage {
var ms []*protobuf.DiscordMessage
for _, m := range r.discordMessages {
ms = append(ms, m)
}
return ms
}
func (r *MessengerResponse) DiscordMessageAuthors() []*protobuf.DiscordMessageAuthor {
var authors []*protobuf.DiscordMessageAuthor
for _, author := range r.discordMessageAuthors {
authors = append(authors, author)
}
return authors
}
func (r *MessengerResponse) DiscordMessageAttachments() []*protobuf.DiscordMessageAttachment {
var attachments []*protobuf.DiscordMessageAttachment
for _, a := range r.discordMessageAttachments {
attachments = append(attachments, a)
}
return attachments
}
func (r *MessengerResponse) Messages() []*common.Message {
var ms []*common.Message
for _, m := range r.messages {
ms = append(ms, m)
}
return ms
}
func (r *MessengerResponse) AddDiscordMessageAuthor(author *protobuf.DiscordMessageAuthor) {
if r.discordMessageAuthors == nil {
r.discordMessageAuthors = make(map[string]*protobuf.DiscordMessageAuthor)
}
r.discordMessageAuthors[author.Id] = author
}
func (r *MessengerResponse) AddDiscordMessageAttachment(attachment *protobuf.DiscordMessageAttachment) {
if r.discordMessageAttachments == nil {
r.discordMessageAttachments = make(map[string]*protobuf.DiscordMessageAttachment)
}
r.discordMessageAttachments[attachment.Id] = attachment
}
func (r *MessengerResponse) AddDiscordMessageAttachments(attachments []*protobuf.DiscordMessageAttachment) {
for _, attachment := range attachments {
r.AddDiscordMessageAttachment(attachment)
}
}
func (r *MessengerResponse) AddDiscordMessage(message *protobuf.DiscordMessage) {
if r.discordMessages == nil {
r.discordMessages = make(map[string]*protobuf.DiscordMessage)
}
r.discordMessages[message.Id] = message
}
func (r *MessengerResponse) AddMessages(ms []*common.Message) {
for _, m := range ms {
r.AddMessage(m)
}
}
func (r *MessengerResponse) AddMessage(message *common.Message) {
if r.messages == nil {
r.messages = make(map[string]*common.Message)
}
if message.Deleted {
return
}
r.messages[message.ID] = message
}
func (r *MessengerResponse) AddContact(c *Contact) {
for idx, c1 := range r.Contacts {
if c1.ID == c.ID {
r.Contacts[idx] = c
return
}
}
r.Contacts = append(r.Contacts, c)
}
func (r *MessengerResponse) AddContacts(contacts []*Contact) {
for idx := range contacts {
r.AddContact(contacts[idx])
}
}
func (r *MessengerResponse) AddInstallation(i *multidevice.Installation) {
for idx, i1 := range r.Installations {
if i1.ID == i.ID {
r.Installations[idx] = i
return
}
}
r.Installations = append(r.Installations, i)
}
func (r *MessengerResponse) AddInstallations(installations []*multidevice.Installation) {
for idx := range installations {
r.AddInstallation(installations[idx])
}
}
func (r *MessengerResponse) SetMessages(messages []*common.Message) {
r.messages = make(map[string]*common.Message)
r.AddMessages(messages)
}
func (r *MessengerResponse) GetMessage(messageID string) *common.Message {
if r.messages == nil {
return nil
}
return r.messages[messageID]
}
func (r *MessengerResponse) AddDiscordCategory(dc *discord.Category) {
for idx, c := range r.DiscordCategories {
if dc.ID == c.ID {
r.DiscordCategories[idx] = dc
return
}
}
r.DiscordCategories = append(r.DiscordCategories, dc)
}
func (r *MessengerResponse) AddDiscordChannel(dc *discord.Channel) {
for idx, c := range r.DiscordChannels {
if dc.ID == c.ID {
r.DiscordChannels[idx] = dc
return
}
}
r.DiscordChannels = append(r.DiscordChannels, dc)
}
func (r *MessengerResponse) HasDiscordCategory(id string) bool {
for _, c := range r.DiscordCategories {
if id == c.ID {
return true
}
}
return false
}
func (r *MessengerResponse) HasDiscordChannel(id string) bool {
for _, c := range r.DiscordChannels {
if id == c.ID {
return true
}
}
return false
}