perf(login)!: Set-up messenger filters outside login flow (#5229)
Fixes the slow login in mobile devices when users have joined large communities, such as the Status one. A user would get stuck for almost 20s in some devices. We identified that the step to set-up filters in the messenger is potentially expensive and that it is not critical to happen before the node.login signal is emitted. The solution presented in this PR is to set-up filters inside messenger.Start(), which the client already calls immediately after login. With this change, users of the mobile app can login pretty fast even when they joined large communities. They can immediately interact with other parts of the app even if filter initialization is running in the background, like Wallet, Activity Center, Settings, and Profile. Breaking changes: in the mobile repository, we had to change where the endpoint wakuext_startMessenger was called and the order of a few events to process chats. So essentially ordering, but no data changes. - Root issue https://github.com/status-im/status-mobile/issues/20059 - Related mobile PR https://github.com/status-im/status-mobile/pull/20173
This commit is contained in:
parent
39a7d41135
commit
dbed69d155
|
@ -287,9 +287,15 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
err = messenger.Init()
|
||||
err = messenger.InitInstallations()
|
||||
if err != nil {
|
||||
logger.Error("failed to init messenger", "error", err)
|
||||
logger.Error("failed to init messenger installations", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = messenger.InitFilters()
|
||||
if err != nil {
|
||||
logger.Error("failed to init messenger filters", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -424,11 +430,11 @@ func printUsage() {
|
|||
usage := `
|
||||
Usage: statusd [options]
|
||||
Examples:
|
||||
statusd # run regular Whisper node that joins Status network
|
||||
statusd -c ./default.json # run node with configuration specified in ./default.json file
|
||||
statusd -c ./default.json -c ./standalone.json # run node with configuration specified in ./default.json file, after merging ./standalone.json file
|
||||
statusd -c ./default.json -metrics # run node with configuration specified in ./default.json file, and expose ethereum metrics with debug_metrics jsonrpc call
|
||||
statusd -c ./default.json -log DEBUG --seed-phrase="test test test test test test test test test test test junk" --password=password # run node with configuration specified in ./default.json file, and import account with seed phrase and password
|
||||
statusd # run regular Whisper node that joins Status network
|
||||
statusd -c ./default.json # run node with configuration specified in ./default.json file
|
||||
statusd -c ./default.json -c ./standalone.json # run node with configuration specified in ./default.json file, after merging ./standalone.json file
|
||||
statusd -c ./default.json -metrics # run node with configuration specified in ./default.json file, and expose ethereum metrics with debug_metrics jsonrpc call
|
||||
statusd -c ./default.json -log DEBUG --seed-phrase="test test test test test test test test test test test junk" --password=password # run node with configuration specified in ./default.json file, and import account with seed phrase and password
|
||||
|
||||
Options:
|
||||
`
|
||||
|
|
|
@ -726,6 +726,11 @@ func (m *Messenger) Start() (*MessengerResponse, error) {
|
|||
}
|
||||
m.started = true
|
||||
|
||||
err := m.InitFilters()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
now := time.Now().UnixMilli()
|
||||
if err := m.settings.CheckAndDeleteExpiredKeypairsAndAccounts(uint64(now)); err != nil {
|
||||
return nil, err
|
||||
|
@ -1663,9 +1668,27 @@ func (m *Messenger) handlePushNotificationClientRegistrations(c chan struct{}) {
|
|||
}()
|
||||
}
|
||||
|
||||
// Init analyzes chats and contacts in order to setup filters
|
||||
func (m *Messenger) InitInstallations() error {
|
||||
installations, err := m.encryptor.GetOurInstallations(&m.identity.PublicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, installation := range installations {
|
||||
m.allInstallations.Store(installation.ID, installation)
|
||||
}
|
||||
|
||||
err = m.setInstallationHostname()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitFilters analyzes chats and contacts in order to setup filters
|
||||
// which are responsible for retrieving messages.
|
||||
func (m *Messenger) Init() error {
|
||||
func (m *Messenger) InitFilters() error {
|
||||
|
||||
// Seed the for color generation
|
||||
rand.Seed(time.Now().Unix())
|
||||
|
@ -1852,20 +1875,6 @@ func (m *Messenger) Init() error {
|
|||
publicKeys = append(publicKeys, publicKey)
|
||||
}
|
||||
|
||||
installations, err := m.encryptor.GetOurInstallations(&m.identity.PublicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, installation := range installations {
|
||||
m.allInstallations.Store(installation.ID, installation)
|
||||
}
|
||||
|
||||
err = m.setInstallationHostname()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = m.transport.InitFilters(filtersToInit, publicKeys)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -106,7 +106,12 @@ func newTestMessenger(waku types.Waku, config testMessengerConfig) (*Messenger,
|
|||
m.retrievedMessagesIteratorFactory = config.messagesOrderController.newMessagesIterator
|
||||
}
|
||||
|
||||
err = m.Init()
|
||||
err = m.InitInstallations()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = m.InitFilters()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -150,6 +150,8 @@ func (m *Messenger) setInstallationHostname() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// NOTE: imd.Name is always empty in this else branch, which leads to the
|
||||
// result of Sprintf having a trailing whitespace.
|
||||
imd.Name = fmt.Sprintf("%s %s", hn, imd.Name)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,11 @@ import (
|
|||
"image"
|
||||
"image/png"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
userimage "github.com/status-im/status-go/images"
|
||||
"github.com/status-im/status-go/server"
|
||||
"github.com/status-im/status-go/services/browsers"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
@ -403,3 +405,23 @@ func (s *MessengerInstallationSuite) TestSyncInstallationNewMessages() {
|
|||
s.Require().NoError(bob2.Shutdown())
|
||||
s.Require().NoError(alice.Shutdown())
|
||||
}
|
||||
|
||||
func (s *MessengerInstallationSuite) TestInitInstallations() {
|
||||
m, err := newMessengerWithKey(s.shh, s.privateKey, s.logger, nil)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// m.InitInstallations is already called when we set-up the messenger for
|
||||
// testing, thus this test has no act phase.
|
||||
// err = m.InitInstallations()
|
||||
|
||||
// We get one installation when the messenger initializes installations
|
||||
// correctly.
|
||||
s.Require().Equal(1, m.allInstallations.Len())
|
||||
|
||||
deviceName, err := server.GetDeviceName()
|
||||
s.Require().NoError(err)
|
||||
installation, ok := m.allInstallations.Load(m.installationID)
|
||||
s.Require().True(ok)
|
||||
s.Require().Equal(deviceName+" ", installation.InstallationMetadata.Name)
|
||||
s.Require().Equal(runtime.GOOS, installation.InstallationMetadata.DeviceType)
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ func (n *testNode) PeersCount() int {
|
|||
return 1
|
||||
}
|
||||
|
||||
func (s *MessengerSuite) TestInit() {
|
||||
func (s *MessengerSuite) TestInitFilters() {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Prep func()
|
||||
|
@ -174,7 +174,7 @@ func (s *MessengerSuite) TestInit() {
|
|||
for _, tc := range testCases {
|
||||
s.Run(tc.Name, func() {
|
||||
tc.Prep()
|
||||
err := s.m.Init()
|
||||
err := s.m.InitFilters()
|
||||
s.Require().NoError(err)
|
||||
filters := s.m.transport.Filters()
|
||||
expectedFilters += tc.AddedFilters
|
||||
|
|
|
@ -184,7 +184,11 @@ func (s *Service) InitProtocol(nodeName string, identity *ecdsa.PrivateKey, appD
|
|||
if s.config.ProcessBackedupMessages {
|
||||
s.messenger.EnableBackedupMessagesProcessing()
|
||||
}
|
||||
return messenger.Init()
|
||||
|
||||
// Be mindful of adding more initialization code, as it can easily
|
||||
// impact login times for mobile users. For example, we avoid calling
|
||||
// messenger.InitFilters here.
|
||||
return s.messenger.InitInstallations()
|
||||
}
|
||||
|
||||
func (s *Service) StartMessenger() (*protocol.MessengerResponse, error) {
|
||||
|
|
Loading…
Reference in New Issue