status-im/status-go

View on GitHub
multiaccounts/settings/structs.go

Summary

Maintainability
A
0 mins
Test Coverage
A
94%
package settings

import (
    "encoding/json"
    "reflect"

    accountJson "github.com/status-im/status-go/account/json"
    "github.com/status-im/status-go/eth-node/types"
    "github.com/status-im/status-go/params"
    "github.com/status-im/status-go/protocol/common"
    "github.com/status-im/status-go/protocol/protobuf"
)

type ValueHandler func(interface{}) (interface{}, error)
type ValueCastHandler func(interface{}) (interface{}, error)
type SyncSettingProtobufFactoryInterface func(interface{}, uint64, string) (*common.RawMessage, *protobuf.SyncSetting, error)
type SyncSettingProtobufFactoryStruct func(Settings, uint64, string) (*common.RawMessage, *protobuf.SyncSetting, error)
type SyncSettingProtobufToValue func(setting *protobuf.SyncSetting) interface{}

// SyncProtobufFactory represents a collection of functionality to generate and parse *protobuf.SyncSetting
type SyncProtobufFactory struct {
    inactive          bool
    fromInterface     SyncSettingProtobufFactoryInterface
    fromStruct        SyncSettingProtobufFactoryStruct
    valueFromProtobuf SyncSettingProtobufToValue
    protobufType      protobuf.SyncSetting_Type
}

func (spf *SyncProtobufFactory) Inactive() bool {
    return spf.inactive
}

func (spf *SyncProtobufFactory) FromInterface() SyncSettingProtobufFactoryInterface {
    return spf.fromInterface
}

func (spf *SyncProtobufFactory) FromStruct() SyncSettingProtobufFactoryStruct {
    return spf.fromStruct
}

func (spf *SyncProtobufFactory) ExtractValueFromProtobuf() SyncSettingProtobufToValue {
    return spf.valueFromProtobuf
}

func (spf *SyncProtobufFactory) SyncSettingProtobufType() protobuf.SyncSetting_Type {
    return spf.protobufType
}

// SyncSettingField represents a binding between a Value and a SettingField
type SyncSettingField struct {
    SettingField
    Value interface{}
}

func (s SyncSettingField) MarshalJSON() ([]byte, error) {
    alias := struct {
        Name  string      `json:"name"`
        Value interface{} `json:"value"`
    }{
        s.reactFieldName,
        s.Value,
    }

    return json.Marshal(alias)
}

// SettingField represents an individual setting in the database, it contains context dependant names and optional
// pre-store value parsing, along with optional *SyncProtobufFactory
type SettingField struct {
    reactFieldName      string
    dBColumnName        string
    valueHandler        ValueHandler
    syncProtobufFactory *SyncProtobufFactory
    valueCastHandler    ValueCastHandler
}

func (s SettingField) GetReactName() string {
    return s.reactFieldName
}

func (s SettingField) GetDBName() string {
    return s.dBColumnName
}

func (s SettingField) ValueHandler() ValueHandler {
    return s.valueHandler
}

func (s SettingField) ValueCastHandler() ValueCastHandler {
    return s.valueCastHandler
}

func (s SettingField) SyncProtobufFactory() *SyncProtobufFactory {
    return s.syncProtobufFactory
}

// CanSync checks if a SettingField has functions supporting the syncing of
func (s SettingField) CanSync(source SyncSource) bool {
    spf := s.syncProtobufFactory

    if spf == nil {
        return false
    }

    if spf.inactive {
        return false
    }

    switch source {
    case FromInterface:
        return spf.fromInterface != nil
    case FromStruct:
        return spf.fromStruct != nil
    default:
        return false
    }
}

func (s SettingField) Equals(other SettingField) bool {
    return s.reactFieldName == other.reactFieldName
}

// Settings represents the entire setting row stored in the application db
type Settings struct {
    // required
    Address                   types.Address    `json:"address"`
    AnonMetricsShouldSend     bool             `json:"anon-metrics/should-send?,omitempty"`
    ChaosMode                 bool             `json:"chaos-mode?,omitempty"`
    Currency                  string           `json:"currency,omitempty"`
    CurrentNetwork            string           `json:"networks/current-network"`
    CustomBootnodes           *json.RawMessage `json:"custom-bootnodes,omitempty"`
    CustomBootnodesEnabled    *json.RawMessage `json:"custom-bootnodes-enabled?,omitempty"`
    DappsAddress              types.Address    `json:"dapps-address"`
    DeviceName                string           `json:"device-name"`
    DisplayName               string           `json:"display-name"`
    Bio                       string           `json:"bio,omitempty"`
    EIP1581Address            types.Address    `json:"eip1581-address"`
    Fleet                     *string          `json:"fleet,omitempty"`
    HideHomeTooltip           bool             `json:"hide-home-tooltip?,omitempty"`
    InstallationID            string           `json:"installation-id"`
    KeyUID                    string           `json:"key-uid"`
    KeycardInstanceUID        string           `json:"keycard-instance-uid,omitempty"`
    KeycardPairedOn           int64            `json:"keycard-paired-on,omitempty"`
    KeycardPairing            string           `json:"keycard-pairing,omitempty"`
    LastUpdated               *int64           `json:"last-updated,omitempty"`
    LatestDerivedPath         uint             `json:"latest-derived-path"`
    LinkPreviewRequestEnabled bool             `json:"link-preview-request-enabled,omitempty"`
    LinkPreviewsEnabledSites  *json.RawMessage `json:"link-previews-enabled-sites,omitempty"`
    LogLevel                  *string          `json:"log-level,omitempty"`
    MessagesFromContactsOnly  bool             `json:"messages-from-contacts-only"`
    Mnemonic                  *string          `json:"mnemonic,omitempty"`
    // NOTE(rasom): negation here because it safer/simpler to have false by default
    MnemonicWasNotShown  bool             `json:"mnemonic-was-not-shown?,omitempty"`
    MnemonicRemoved      bool             `json:"mnemonic-removed?,omitempty"`
    MutualContactEnabled bool             `json:"mutual-contact-enabled?"`
    Name                 string           `json:"name,omitempty"`
    Networks             *json.RawMessage `json:"networks/networks"`
    // NotificationsEnabled indicates whether local notifications should be enabled (android only)
    NotificationsEnabled bool             `json:"notifications-enabled?,omitempty"`
    PhotoPath            string           `json:"photo-path"`
    PinnedMailserver     *json.RawMessage `json:"pinned-mailservers,omitempty"`
    // PreferredName represents the user's preferred Ethereum Name Service (ENS) name.
    // If a user has multiple ENS names, they can select one as the PreferredName.
    // When PreferredName is set, it takes precedence over the DisplayName for displaying the user's name.
    // If PreferredName is empty or doesn't match any of the user's ENS names, the DisplayName is used instead.
    //
    // There is a race condition between updating DisplayName and PreferredName, where the account.Name field
    // could be incorrectly updated based on the order in which the backup messages (BackedUpProfile/BackedUpSettings) arrive.
    // To handle this race condition, the code checks the LastSynced clock value for both DisplayName and PreferredName,
    // and updates account.Name with the value that has the latest clock
    PreferredName  *string `json:"preferred-name,omitempty"`
    PreviewPrivacy bool    `json:"preview-privacy?"`
    PublicKey      string  `json:"public-key"`
    // PushNotificationsServerEnabled indicates whether we should be running a push notification server
    PushNotificationsServerEnabled bool `json:"push-notifications-server-enabled?,omitempty"`
    // PushNotificationsFromContactsOnly indicates whether we should only receive push notifications from contacts
    PushNotificationsFromContactsOnly bool `json:"push-notifications-from-contacts-only?,omitempty"`
    // PushNotificationsBlockMentions indicates whether we should receive notifications for mentions
    PushNotificationsBlockMentions bool `json:"push-notifications-block-mentions?,omitempty"`
    RememberSyncingChoice          bool `json:"remember-syncing-choice?,omitempty"`
    // RemotePushNotificationsEnabled indicates whether we should be using remote notifications (ios only for now)
    RemotePushNotificationsEnabled bool             `json:"remote-push-notifications-enabled?,omitempty"`
    SigningPhrase                  string           `json:"signing-phrase"`
    StickerPacksInstalled          *json.RawMessage `json:"stickers/packs-installed,omitempty"`
    StickerPacksPending            *json.RawMessage `json:"stickers/packs-pending,omitempty"`
    StickersRecentStickers         *json.RawMessage `json:"stickers/recent-stickers,omitempty"`
    SyncingOnMobileNetwork         bool             `json:"syncing-on-mobile-network?,omitempty"`
    // DefaultSyncPeriod is how far back in seconds we should pull messages from a mailserver
    DefaultSyncPeriod uint `json:"default-sync-period"`
    // SendPushNotifications indicates whether we should send push notifications for other clients
    SendPushNotifications bool `json:"send-push-notifications?,omitempty"`
    Appearance            uint `json:"appearance"`
    // ProfilePicturesShowTo indicates to whom the user shows their profile picture to (contacts, everyone)
    ProfilePicturesShowTo ProfilePicturesShowToType `json:"profile-pictures-show-to"`
    // ProfilePicturesVisibility indicates who we want to see profile pictures of (contacts, everyone or none)
    ProfilePicturesVisibility           ProfilePicturesVisibilityType `json:"profile-pictures-visibility"`
    UseMailservers                      bool                          `json:"use-mailservers?"`
    Usernames                           *json.RawMessage              `json:"usernames,omitempty"`
    WalletRootAddress                   types.Address                 `json:"wallet-root-address,omitempty"`
    WalletSetUpPassed                   bool                          `json:"wallet-set-up-passed?,omitempty"`
    WalletVisibleTokens                 *json.RawMessage              `json:"wallet/visible-tokens,omitempty"`
    WakuBloomFilterMode                 bool                          `json:"waku-bloom-filter-mode,omitempty"`
    WebViewAllowPermissionRequests      bool                          `json:"webview-allow-permission-requests?,omitempty"`
    SendStatusUpdates                   bool                          `json:"send-status-updates?,omitempty"`
    CurrentUserStatus                   *json.RawMessage              `json:"current-user-status"`
    GifRecents                          *json.RawMessage              `json:"gifs/recent-gifs"`
    GifFavorites                        *json.RawMessage              `json:"gifs/favorite-gifs"`
    OpenseaEnabled                      bool                          `json:"opensea-enabled?,omitempty"`
    TelemetryServerURL                  string                        `json:"telemetry-server-url,omitempty"`
    TelemetrySendPeriodMs               int                           `json:"telemetry-send-period-ms,omitempty"`
    LastBackup                          uint64                        `json:"last-backup,omitempty"`
    BackupEnabled                       bool                          `json:"backup-enabled?,omitempty"`
    AutoMessageEnabled                  bool                          `json:"auto-message-enabled?,omitempty"`
    GifAPIKey                           string                        `json:"gifs/api-key"`
    TestNetworksEnabled                 bool                          `json:"test-networks-enabled?,omitempty"`
    ProfileMigrationNeeded              bool                          `json:"profile-migration-needed,omitempty"`
    IsGoerliEnabled                     bool                          `json:"is-goerli-enabled?,omitempty"`
    TokenGroupByCommunity               bool                          `json:"token-group-by-community?,omitempty"`
    ShowCommunityAssetWhenSendingTokens bool                          `json:"show-community-asset-when-sending-tokens?,omitempty"`
    DisplayAssetsBelowBalance           bool                          `json:"display-assets-below-balance?,omitempty"`
    DisplayAssetsBelowBalanceThreshold  int64                         `json:"display-assets-below-balance-threshold,omitempty"`
    CollectibleGroupByCollection        bool                          `json:"collectible-group-by-collection?,omitempty"`
    CollectibleGroupByCommunity         bool                          `json:"collectible-group-by-community?,omitempty"`
    URLUnfurlingMode                    URLUnfurlingModeType          `json:"url-unfurling-mode,omitempty"`
    PeerSyncingEnabled                  bool                          `json:"peer-syncing-enabled?,omitempty"`
}

func (s Settings) MarshalJSON() ([]byte, error) {
    // We need this typedef in order to overcome stack overflow
    // when marshaling JSON
    type Alias Settings

    ext, err := accountJson.ExtendStructWithPubKeyData(s.PublicKey, Alias(s))
    if err != nil {
        return nil, err
    }
    return json.Marshal(ext)
}

func (s Settings) IsEmpty() bool {
    empty := reflect.Zero(reflect.TypeOf(s)).Interface()
    return reflect.DeepEqual(s, empty)
}

func (s Settings) GetFleet() string {
    if s.Fleet == nil {
        return params.FleetUndefined
    }
    return *s.Fleet
}