status-go/protocol/messenger_chats.go

231 lines
5.0 KiB
Go

package protocol
import (
"context"
"errors"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/requests"
"github.com/status-im/status-go/protocol/transport"
)
func (m *Messenger) Chats() []*Chat {
var chats []*Chat
m.allChats.Range(func(chatID string, chat *Chat) (shouldContinue bool) {
chats = append(chats, chat)
return true
})
return chats
}
func (m *Messenger) ActiveChats() []*Chat {
m.mutex.Lock()
defer m.mutex.Unlock()
var chats []*Chat
m.allChats.Range(func(chatID string, c *Chat) bool {
if c.Active {
chats = append(chats, c)
}
return true
})
return chats
}
func (m *Messenger) CreateOneToOneChat(request *requests.CreateOneToOneChat) (*MessengerResponse, error) {
if err := request.Validate(); err != nil {
return nil, err
}
chatID := request.ID.String()
pk, err := common.HexToPubkey(chatID)
if err != nil {
return nil, err
}
chat, ok := m.allChats.Load(chatID)
if !ok {
chat = CreateOneToOneChat(chatID, pk, m.getTimesource())
}
chat.Active = true
filters, err := m.Join(chat)
if err != nil {
return nil, err
}
err = m.saveChat(chat)
if err != nil {
return nil, err
}
// TODO(Samyoul) remove storing of an updated reference pointer?
m.allChats.Store(chatID, chat)
response := &MessengerResponse{
Filters: filters,
}
response.AddChat(chat)
return response, nil
}
func (m *Messenger) DeleteChat(chatID string) error {
return m.deleteChat(chatID)
}
func (m *Messenger) deleteChat(chatID string) error {
err := m.persistence.DeleteChat(chatID)
if err != nil {
return err
}
chat, ok := m.allChats.Load(chatID)
if ok && chat.Active && chat.Public() {
m.allChats.Delete(chatID)
return m.reregisterForPushNotifications()
}
return nil
}
func (m *Messenger) SaveChat(chat *Chat) error {
return m.saveChat(chat)
}
func (m *Messenger) DeactivateChat(chatID string) (*MessengerResponse, error) {
return m.deactivateChat(chatID)
}
func (m *Messenger) deactivateChat(chatID string) (*MessengerResponse, error) {
var response MessengerResponse
chat, ok := m.allChats.Load(chatID)
if !ok {
return nil, ErrChatNotFound
}
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
err := m.persistence.DeactivateChat(chat, clock)
if err != nil {
return nil, err
}
// We re-register as our options have changed and we don't want to
// receive PN from mentions in this chat anymore
if chat.Public() {
err := m.reregisterForPushNotifications()
if err != nil {
return nil, err
}
}
// TODO(samyoul) remove storing of an updated reference pointer?
m.allChats.Store(chatID, chat)
response.AddChat(chat)
// TODO: Remove filters
return &response, nil
}
func (m *Messenger) saveChats(chats []*Chat) error {
err := m.persistence.SaveChats(chats)
if err != nil {
return err
}
for _, chat := range chats {
m.allChats.Store(chat.ID, chat)
}
return nil
}
func (m *Messenger) saveChat(chat *Chat) error {
previousChat, ok := m.allChats.Load(chat.ID)
if chat.OneToOne() {
// We clear all notifications so it pops up again
if !chat.Active {
err := m.persistence.DeleteActivityCenterNotification(types.FromHex(chat.ID))
if err != nil {
return err
}
}
name, identicon, err := generateAliasAndIdenticon(chat.ID)
if err != nil {
return err
}
chat.Alias = name
chat.Identicon = identicon
}
// Sync chat if it's a new active public chat, but not a timeline chat
if !ok && chat.Active && chat.Public() && !chat.ProfileUpdates() && !chat.Timeline() {
if err := m.syncPublicChat(context.Background(), chat); err != nil {
return err
}
}
// We check if it's a new chat, or chat.Active has changed
// we check here, but we only re-register once the chat has been
// saved an added
shouldRegisterForPushNotifications := chat.Public() && (!ok && chat.Active) || (ok && chat.Active != previousChat.Active)
err := m.persistence.SaveChat(*chat)
if err != nil {
return err
}
// TODO(samyoul) remove storing of an updated reference pointer?
m.allChats.Store(chat.ID, chat)
if shouldRegisterForPushNotifications {
// Re-register for push notifications, as we want to receive mentions
if err := m.reregisterForPushNotifications(); err != nil {
return err
}
}
return nil
}
func (m *Messenger) Join(chat *Chat) ([]*transport.Filter, error) {
switch chat.ChatType {
case ChatTypeOneToOne:
pk, err := chat.PublicKey()
if err != nil {
return nil, err
}
f, err := m.transport.JoinPrivate(pk)
if err != nil {
return nil, err
}
return []*transport.Filter{f}, nil
case ChatTypePrivateGroupChat:
members, err := chat.MembersAsPublicKeys()
if err != nil {
return nil, err
}
return m.transport.JoinGroup(members)
case ChatTypePublic, ChatTypeProfile, ChatTypeTimeline:
f, err := m.transport.JoinPublic(chat.ID)
if err != nil {
return nil, err
}
return []*transport.Filter{f}, nil
default:
return nil, errors.New("chat is neither public nor private")
}
}