status-go/protocol/messenger_sync_settings.go
Sale Djenic 1340a55c1d feat: backup profile data to waku and sync them from waku
Changes applied here introduce backing up profile data (display name and identity
images) to waku and fetch them from waku. Information about those data is sent
as a separate signal to a client via `sync.from.waku.profile` signal.

New signal `sync.from.waku.progress` is introduced which will be used to notify a client
about the progress of fetching data from waku.
2022-12-23 15:07:14 +01:00

156 lines
4.4 KiB
Go

package protocol
import (
"context"
"encoding/json"
"go.uber.org/zap"
"github.com/status-im/status-go/multiaccounts/errors"
"github.com/status-im/status-go/multiaccounts/settings"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/protobuf"
)
// syncSettings syncs all settings that are syncable
func (m *Messenger) prepareSyncSettingsMessages(currentClock uint64) (resultRaw []*common.RawMessage, resultSync []*protobuf.SyncSetting, errors []error) {
s, err := m.settings.GetSettings()
if err != nil {
errors = append(errors, err)
return
}
logger := m.logger.Named("prepareSyncSettings")
// Do not use the network clock, use the db value
_, chat := m.getLastClockWithRelatedChat()
for _, sf := range settings.SettingFieldRegister {
if sf.CanSync(settings.FromStruct) {
// Pull clock from the db
clock, err := m.settings.GetSettingLastSynced(sf)
if err != nil {
logger.Error("m.settings.GetSettingLastSynced", zap.Error(err), zap.Any("SettingField", sf))
errors = append(errors, err)
return
}
if clock == 0 {
clock = currentClock
}
// Build protobuf
rm, sm, err := sf.SyncProtobufFactory().FromStruct()(s, clock, chat.ID)
if err != nil {
// Collect errors to give other sync messages a chance to send
logger.Error("SyncProtobufFactory.Struct", zap.Error(err))
errors = append(errors, err)
}
resultRaw = append(resultRaw, rm)
resultSync = append(resultSync, sm)
}
}
return
}
func (m *Messenger) syncSettings() error {
logger := m.logger.Named("syncSettings")
clock, _ := m.getLastClockWithRelatedChat()
rawMessages, _, errors := m.prepareSyncSettingsMessages(clock)
if len(errors) != 0 {
// return just the first error, the others have been logged
return errors[0]
}
for _, rm := range rawMessages {
_, err := m.dispatchMessage(context.Background(), *rm)
if err != nil {
logger.Error("dispatchMessage", zap.Error(err))
return err
}
logger.Debug("dispatchMessage success", zap.Any("rm", rm))
}
return nil
}
// extractSyncSetting parses incoming *protobuf.SyncSetting and stores the setting data if needed
func (m *Messenger) extractSyncSetting(syncSetting *protobuf.SyncSetting) (*settings.SyncSettingField, error) {
sf, err := settings.GetFieldFromProtobufType(syncSetting.Type)
if err != nil {
m.logger.Error(
"extractSyncSetting - settings.GetFieldFromProtobufType",
zap.Error(err),
zap.Any("syncSetting", syncSetting),
)
return nil, err
}
spf := sf.SyncProtobufFactory()
if spf == nil {
m.logger.Warn("extractSyncSetting - received protobuf for setting with no SyncProtobufFactory", zap.Any("SettingField", sf))
return nil, nil
}
if spf.Inactive() {
m.logger.Warn("extractSyncSetting - received protobuf for inactive sync setting", zap.Any("SettingField", sf))
return nil, nil
}
value := spf.ExtractValueFromProtobuf()(syncSetting)
err = m.settings.SaveSyncSetting(sf, value, syncSetting.Clock)
if err == errors.ErrNewClockOlderThanCurrent {
m.logger.Info("extractSyncSetting - SaveSyncSetting :", zap.Error(err))
return nil, nil
}
if err != nil {
return nil, err
}
if v, ok := value.([]byte); ok {
value = json.RawMessage(v)
}
return &settings.SyncSettingField{SettingField: sf, Value: value}, nil
}
// startSyncSettingsLoop watches the m.settings.SyncQueue and sends a sync message in response to a settings update
func (m *Messenger) startSyncSettingsLoop() {
go func() {
logger := m.logger.Named("SyncSettingsLoop")
for {
select {
case s := <-m.settings.SyncQueue:
if s.CanSync(settings.FromInterface) {
logger.Debug("setting for sync received from settings.SyncQueue")
clock, chat := m.getLastClockWithRelatedChat()
// Only the messenger has access to the clock, so set the settings sync clock here.
err := m.settings.SetSettingLastSynced(s.SettingField, clock)
if err != nil {
logger.Error("m.settings.SetSettingLastSynced", zap.Error(err))
break
}
rm, _, err := s.SyncProtobufFactory().FromInterface()(s.Value, clock, chat.ID)
if err != nil {
logger.Error("SyncProtobufFactory().FromInterface", zap.Error(err), zap.Any("SyncSettingField", s))
break
}
_, err = m.dispatchMessage(context.Background(), *rm)
if err != nil {
logger.Error("dispatchMessage", zap.Error(err))
break
}
logger.Debug("message dispatched")
}
case <-m.quit:
return
}
}
}()
}