status-go/protocol/messenger_sync_settings.go

140 lines
3.8 KiB
Go
Raw Normal View History

Sync Settings (#2478) * Sync Settings * Added valueHandlers and Database singleton Some issues remain, need a way to comparing incoming sql.DB to check if the connection is to a different file or not. Maybe make singleton instance per filename * Added functionality to check the sqlite filename * Refactor of Database.SaveSyncSettings to be used as a handler * Implemented inteface for setting sync protobuf factories * Refactored and completed adhoc send setting sync * Tidying up * Immutability refactor * Refactor settings into dedicated package * Breakout structs * Tidy up * Refactor of bulk settings sync * Bug fixes * Addressing feedback * Fix code dropped during rebase * Fix for db closed * Fix for node config related crashes * Provisional fix for type assertion - issue 2 * Adding robust type assertion checks * Partial fix for null literal db storage and json encoding * Fix for passively handling nil sql.DB, and checking if elem has len and if len is 0 * Added test for preferred name behaviour * Adding saved sync settings to MessengerResponse * Completed granular initial sync and clock from network on save * add Settings to isEmpty * Refactor of protobufs, partially done * Added syncSetting receiver handling, some bug fixes * Fix for sticker packs * Implement inactive flag on sync protobuf factory * Refactor of types and structs * Added SettingField.CanSync functionality * Addressing rebase artifact * Refactor of Setting SELECT queries * Refactor of string return queries * VERSION bump and migration index bump * Deactiveate Sync Settings * Deactiveated preferred_name and send_status_updates Co-authored-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2022-03-23 18:47:00 +00:00
package protocol
import (
"context"
"encoding/json"
Sync Settings (#2478) * Sync Settings * Added valueHandlers and Database singleton Some issues remain, need a way to comparing incoming sql.DB to check if the connection is to a different file or not. Maybe make singleton instance per filename * Added functionality to check the sqlite filename * Refactor of Database.SaveSyncSettings to be used as a handler * Implemented inteface for setting sync protobuf factories * Refactored and completed adhoc send setting sync * Tidying up * Immutability refactor * Refactor settings into dedicated package * Breakout structs * Tidy up * Refactor of bulk settings sync * Bug fixes * Addressing feedback * Fix code dropped during rebase * Fix for db closed * Fix for node config related crashes * Provisional fix for type assertion - issue 2 * Adding robust type assertion checks * Partial fix for null literal db storage and json encoding * Fix for passively handling nil sql.DB, and checking if elem has len and if len is 0 * Added test for preferred name behaviour * Adding saved sync settings to MessengerResponse * Completed granular initial sync and clock from network on save * add Settings to isEmpty * Refactor of protobufs, partially done * Added syncSetting receiver handling, some bug fixes * Fix for sticker packs * Implement inactive flag on sync protobuf factory * Refactor of types and structs * Added SettingField.CanSync functionality * Addressing rebase artifact * Refactor of Setting SELECT queries * Refactor of string return queries * VERSION bump and migration index bump * Deactiveate Sync Settings * Deactiveated preferred_name and send_status_updates Co-authored-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2022-03-23 18:47:00 +00:00
"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/protobuf"
)
// syncSettings syncs all settings that are syncable
func (m *Messenger) syncSettings() error {
logger := m.logger.Named("syncSettings")
s, err := m.settings.GetSettings()
if err != nil {
return err
}
// Do not use the network clock, use the db value
_, chat := m.getLastClockWithRelatedChat()
var errs []error
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))
return err
}
// Build protobuf
rm, 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))
errs = append(errs, err)
}
_, 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))
}
}
if len(errs) != 0 {
// return just the first error, the others have been logged
return errs[0]
}
return nil
}
// handleSyncSetting parses incoming *protobuf.SyncSetting and stores the setting data if needed
func (m *Messenger) handleSyncSetting(response *MessengerResponse, syncSetting *protobuf.SyncSetting) error {
sf, err := settings.GetFieldFromProtobufType(syncSetting.Type)
if err != nil {
m.logger.Error(
"handleSyncSetting - settings.GetFieldFromProtobufType",
zap.Error(err),
zap.Any("syncSetting", syncSetting),
)
return err
}
spf := sf.SyncProtobufFactory()
if spf == nil {
m.logger.Warn("handleSyncSetting - received protobuf for setting with no SyncProtobufFactory", zap.Any("SettingField", sf))
return nil
}
if spf.Inactive() {
m.logger.Warn("handleSyncSetting - received protobuf for inactive sync setting", zap.Any("SettingField", sf))
return nil
}
value := spf.ExtractValueFromProtobuf()(syncSetting)
err = m.settings.SaveSyncSetting(sf, value, syncSetting.Clock)
if err == errors.ErrNewClockOlderThanCurrent {
m.logger.Info("handleSyncSetting - SaveSyncSetting :", zap.Error(err))
return nil
}
if err != nil {
return err
}
if v, ok := value.([]byte); ok {
value = json.RawMessage(v)
}
Sync Settings (#2478) * Sync Settings * Added valueHandlers and Database singleton Some issues remain, need a way to comparing incoming sql.DB to check if the connection is to a different file or not. Maybe make singleton instance per filename * Added functionality to check the sqlite filename * Refactor of Database.SaveSyncSettings to be used as a handler * Implemented inteface for setting sync protobuf factories * Refactored and completed adhoc send setting sync * Tidying up * Immutability refactor * Refactor settings into dedicated package * Breakout structs * Tidy up * Refactor of bulk settings sync * Bug fixes * Addressing feedback * Fix code dropped during rebase * Fix for db closed * Fix for node config related crashes * Provisional fix for type assertion - issue 2 * Adding robust type assertion checks * Partial fix for null literal db storage and json encoding * Fix for passively handling nil sql.DB, and checking if elem has len and if len is 0 * Added test for preferred name behaviour * Adding saved sync settings to MessengerResponse * Completed granular initial sync and clock from network on save * add Settings to isEmpty * Refactor of protobufs, partially done * Added syncSetting receiver handling, some bug fixes * Fix for sticker packs * Implement inactive flag on sync protobuf factory * Refactor of types and structs * Added SettingField.CanSync functionality * Addressing rebase artifact * Refactor of Setting SELECT queries * Refactor of string return queries * VERSION bump and migration index bump * Deactiveate Sync Settings * Deactiveated preferred_name and send_status_updates Co-authored-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2022-03-23 18:47:00 +00:00
response.Settings = append(response.Settings, &settings.SyncSettingField{SettingField: sf, Value: value})
return 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
}
}
}()
}