231 lines
5.0 KiB
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")
|
|
}
|
|
}
|