github.com/status-im/status-go@v1.1.0/multiaccounts/settings/database.go (about) 1 package settings 2 3 import ( 4 "context" 5 "database/sql" 6 "encoding/json" 7 "fmt" 8 "sync" 9 "time" 10 11 "github.com/ethereum/go-ethereum/log" 12 13 "github.com/status-im/status-go/common/dbsetup" 14 "github.com/status-im/status-go/eth-node/types" 15 "github.com/status-im/status-go/multiaccounts/errors" 16 "github.com/status-im/status-go/nodecfg" 17 "github.com/status-im/status-go/params" 18 "github.com/status-im/status-go/sqlite" 19 ) 20 21 type Notifier func(SettingField, interface{}) 22 23 var ( 24 // dbInstances holds a map of singleton instances of Database 25 dbInstances map[string]*Database 26 27 // mutex guards the instantiation of the dbInstances values, to prevent any concurrent instantiations 28 mutex sync.Mutex 29 ) 30 31 // Database sql wrapper for operations with browser objects. 32 type Database struct { 33 db *sql.DB 34 SyncQueue chan SyncSettingField 35 changesSubscriptions []chan *SyncSettingField 36 notifier Notifier 37 } 38 39 // MakeNewDB ensures that a singleton instance of Database is returned per sqlite db file 40 func MakeNewDB(db *sql.DB) (*Database, error) { 41 filename, err := dbsetup.GetDBFilename(db) 42 if err != nil { 43 return nil, err 44 } 45 46 d := &Database{ 47 db: db, 48 SyncQueue: make(chan SyncSettingField, 100), 49 } 50 51 // An empty filename means that the sqlite database is held in memory 52 // In this case we don't want to restrict the instantiation 53 if filename == "" { 54 return d, nil 55 } 56 57 // Lock to protect the map from concurrent access 58 mutex.Lock() 59 defer mutex.Unlock() 60 61 // init dbInstances if it hasn't been already 62 if dbInstances == nil { 63 dbInstances = map[string]*Database{} 64 } 65 66 // If we haven't seen this database file before make an instance 67 if _, ok := dbInstances[filename]; !ok { 68 dbInstances[filename] = d 69 } 70 71 // Check if the current dbInstance is closed, if closed assign new Database 72 if err := dbInstances[filename].db.Ping(); err != nil { 73 dbInstances[filename] = d 74 } 75 76 return dbInstances[filename], nil 77 } 78 79 func (db *Database) GetDB() *sql.DB { 80 return db.db 81 } 82 83 func (db *Database) GetSyncQueue() chan SyncSettingField { 84 return db.SyncQueue 85 } 86 87 func (db *Database) GetChangesSubscriptions() []chan *SyncSettingField { 88 return db.changesSubscriptions 89 } 90 91 func (db *Database) GetNotifier() Notifier { 92 return db.notifier 93 } 94 95 func (db *Database) SetSettingsNotifier(n Notifier) { 96 db.notifier = n 97 } 98 99 // TODO remove photoPath from settings 100 func (db *Database) CreateSettings(s Settings, n params.NodeConfig) error { 101 tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{}) 102 if err != nil { 103 return err 104 } 105 106 defer func() { 107 if err == nil { 108 err = tx.Commit() 109 return 110 } 111 // don't shadow original error 112 _ = tx.Rollback() 113 }() 114 115 _, err = tx.Exec(` 116 INSERT INTO settings ( 117 address, 118 currency, 119 current_network, 120 dapps_address, 121 device_name, 122 preferred_name, 123 display_name, 124 bio, 125 eip1581_address, 126 installation_id, 127 key_uid, 128 keycard_instance_uid, 129 keycard_paired_on, 130 keycard_pairing, 131 latest_derived_path, 132 mnemonic, 133 name, 134 networks, 135 photo_path, 136 preview_privacy, 137 public_key, 138 signing_phrase, 139 wallet_root_address, 140 synthetic_id, 141 current_user_status, 142 profile_pictures_show_to, 143 profile_pictures_visibility, 144 url_unfurling_mode, 145 mnemonic_was_not_shown, 146 wallet_token_preferences_group_by_community, 147 wallet_collectible_preferences_group_by_collection, 148 wallet_collectible_preferences_group_by_community, 149 test_networks_enabled, 150 fleet 151 ) VALUES ( 152 ?,?,?,?,?,?,?,?,?,?,?,?,?,?, 153 ?,?,?,?,?,?,?,?,?,'id',?,?,?,?,?,?,?,?,?,?)`, 154 s.Address, 155 s.Currency, 156 s.CurrentNetwork, 157 s.DappsAddress, 158 s.DeviceName, 159 s.PreferredName, 160 s.DisplayName, 161 s.Bio, 162 s.EIP1581Address, 163 s.InstallationID, 164 s.KeyUID, 165 s.KeycardInstanceUID, 166 s.KeycardPairedOn, 167 s.KeycardPairing, 168 s.LatestDerivedPath, 169 s.Mnemonic, 170 s.Name, 171 s.Networks, 172 s.PhotoPath, 173 s.PreviewPrivacy, 174 s.PublicKey, 175 s.SigningPhrase, 176 s.WalletRootAddress, 177 s.CurrentUserStatus, 178 s.ProfilePicturesShowTo, 179 s.ProfilePicturesVisibility, 180 s.URLUnfurlingMode, 181 s.MnemonicWasNotShown, 182 s.TokenGroupByCommunity, 183 s.CollectibleGroupByCollection, 184 s.CollectibleGroupByCommunity, 185 s.TestNetworksEnabled, 186 s.Fleet, 187 ) 188 if err != nil { 189 return err 190 } 191 192 if s.DisplayName != "" { 193 now := time.Now().Unix() 194 query := db.buildUpdateSyncClockQueryForField(DisplayName) 195 _, err := tx.Exec(query, uint64(now), uint64(now)) 196 if err != nil { 197 return err 198 } 199 } 200 201 return nodecfg.SaveConfigWithTx(tx, &n) 202 } 203 204 func (db *Database) getSettingFieldFromReactName(reactName string) (SettingField, error) { 205 for _, s := range SettingFieldRegister { 206 if s.GetReactName() == reactName { 207 return s, nil 208 } 209 } 210 return SettingField{}, errors.ErrInvalidConfig 211 } 212 213 func (db *Database) makeSelectRow(setting SettingField) *sql.Row { 214 query := "SELECT %s FROM settings WHERE synthetic_id = 'id'" 215 query = fmt.Sprintf(query, setting.GetDBName()) 216 return db.db.QueryRow(query) 217 } 218 219 func (db *Database) makeSelectString(setting SettingField) (string, error) { 220 var result sql.NullString 221 err := db.makeSelectRow(setting).Scan(&result) 222 if err == sql.ErrNoRows { 223 return "", nil 224 } 225 if result.Valid { 226 return result.String, nil 227 } 228 return "", err 229 } 230 231 func (db *Database) saveSetting(setting SettingField, value interface{}) error { 232 query := "UPDATE settings SET %s = ? WHERE synthetic_id = 'id'" 233 query = fmt.Sprintf(query, setting.GetDBName()) 234 235 update, err := db.db.Prepare(query) 236 if err != nil { 237 return err 238 } 239 240 _, err = update.Exec(value) 241 242 if err != nil { 243 return err 244 } 245 246 if db.notifier != nil { 247 db.notifier(setting, value) 248 } 249 250 return nil 251 } 252 253 func (db *Database) parseSaveAndSyncSetting(sf SettingField, value interface{}) (err error) { 254 if sf.ValueCastHandler() != nil { 255 value, err = sf.ValueCastHandler()(value) 256 if err != nil { 257 return err 258 } 259 } 260 261 if sf.ValueHandler() != nil { 262 value, err = sf.ValueHandler()(value) 263 if err != nil { 264 return err 265 } 266 } 267 268 // TODO(samyoul) this is ugly as hell need a more elegant solution 269 if NodeConfig.GetReactName() == sf.GetReactName() { 270 if err = nodecfg.SaveNodeConfig(db.db, value.(*params.NodeConfig)); err != nil { 271 return err 272 } 273 value = nil 274 } 275 276 err = db.saveSetting(sf, value) 277 if err != nil { 278 return err 279 } 280 281 if sf.GetDBName() == DBColumnMnemonic { 282 mnemonicRemoved := value == nil || value.(string) == "" 283 err = db.saveSetting(MnemonicRemoved, mnemonicRemoved) 284 if err != nil { 285 return err 286 } 287 sf = MnemonicRemoved 288 value = mnemonicRemoved 289 } 290 291 if sf.CanSync(FromInterface) { 292 db.SyncQueue <- SyncSettingField{sf, value} 293 } 294 295 db.postChangesToSubscribers(&SyncSettingField{sf, value}) 296 297 return nil 298 } 299 300 // SaveSetting stores data from any non-sync source 301 // If the field requires syncing the field data is pushed on to the SyncQueue 302 func (db *Database) SaveSetting(setting string, value interface{}) error { 303 sf, err := db.getSettingFieldFromReactName(setting) 304 if err != nil { 305 return err 306 } 307 308 return db.parseSaveAndSyncSetting(sf, value) 309 } 310 311 // SaveSettingField is identical in functionality to SaveSetting, except the setting parameter is a SettingField and 312 // doesn't require any SettingFieldRegister lookup. 313 // This func is useful if you already know the SettingField to save 314 func (db *Database) SaveSettingField(sf SettingField, value interface{}) error { 315 return db.parseSaveAndSyncSetting(sf, value) 316 } 317 318 func (db *Database) DeleteMnemonic() error { 319 return db.saveSetting(Mnemonic, nil) 320 } 321 322 // SaveSyncSetting stores setting data from a sync protobuf source, note it does not call SettingField.ValueHandler() 323 // nor does this function attempt to write to the Database.SyncQueue, 324 // yet it still writes to Database.changesSubscriptions. 325 func (db *Database) SaveSyncSetting(setting SettingField, value interface{}, clock uint64) error { 326 ls, err := db.GetSettingLastSynced(setting) 327 if err != nil { 328 return err 329 } 330 if clock <= ls { 331 return errors.ErrNewClockOlderThanCurrent 332 } 333 334 err = db.SetSettingLastSynced(setting, clock) 335 if err != nil { 336 return err 337 } 338 339 err = db.saveSetting(setting, value) 340 if err != nil { 341 return err 342 } 343 344 db.postChangesToSubscribers(&SyncSettingField{setting, value}) 345 return nil 346 } 347 348 func (db *Database) GetSettingLastSynced(setting SettingField) (result uint64, err error) { 349 query := "SELECT %s FROM settings_sync_clock WHERE synthetic_id = 'id'" 350 query = fmt.Sprintf(query, setting.GetDBName()) 351 352 err = db.db.QueryRow(query).Scan(&result) 353 if err != nil { 354 return 0, err 355 } 356 357 return result, nil 358 } 359 360 func (db *Database) buildUpdateSyncClockQueryForField(setting SettingField) string { 361 query := "UPDATE settings_sync_clock SET %s = ? WHERE synthetic_id = 'id' AND %s < ?" 362 return fmt.Sprintf(query, setting.GetDBName(), setting.GetDBName()) 363 } 364 365 func (db *Database) SetSettingLastSynced(setting SettingField, clock uint64) error { 366 query := db.buildUpdateSyncClockQueryForField(setting) 367 368 _, err := db.db.Exec(query, clock, clock) 369 return err 370 } 371 372 func (db *Database) GetSettings() (Settings, error) { 373 var s Settings 374 err := db.db.QueryRow(` 375 SELECT 376 address, anon_metrics_should_send, chaos_mode, currency, current_network, 377 custom_bootnodes, custom_bootnodes_enabled, dapps_address, display_name, bio, eip1581_address, fleet, 378 hide_home_tooltip, installation_id, key_uid, keycard_instance_uid, keycard_paired_on, keycard_pairing, 379 last_updated, latest_derived_path, link_preview_request_enabled, link_previews_enabled_sites, log_level, 380 mnemonic, mnemonic_removed, name, networks, notifications_enabled, push_notifications_server_enabled, 381 push_notifications_from_contacts_only, remote_push_notifications_enabled, send_push_notifications, 382 push_notifications_block_mentions, photo_path, pinned_mailservers, preferred_name, preview_privacy, public_key, 383 remember_syncing_choice, signing_phrase, stickers_packs_installed, stickers_packs_pending, stickers_recent_stickers, 384 syncing_on_mobile_network, default_sync_period, use_mailservers, messages_from_contacts_only, usernames, appearance, 385 profile_pictures_show_to, profile_pictures_visibility, wallet_root_address, wallet_set_up_passed, wallet_visible_tokens, 386 waku_bloom_filter_mode, webview_allow_permission_requests, current_user_status, send_status_updates, gif_recents, 387 gif_favorites, opensea_enabled, last_backup, backup_enabled, telemetry_server_url, auto_message_enabled, gif_api_key, 388 test_networks_enabled, mutual_contact_enabled, profile_migration_needed, is_goerli_enabled, wallet_token_preferences_group_by_community, url_unfurling_mode, 389 mnemonic_was_not_shown, wallet_show_community_asset_when_sending_tokens, wallet_display_assets_below_balance, 390 wallet_display_assets_below_balance_threshold, wallet_collectible_preferences_group_by_collection, wallet_collectible_preferences_group_by_community, 391 peer_syncing_enabled 392 FROM 393 settings 394 WHERE 395 synthetic_id = 'id'`).Scan( 396 &s.Address, 397 &s.AnonMetricsShouldSend, 398 &s.ChaosMode, 399 &s.Currency, 400 &s.CurrentNetwork, 401 &s.CustomBootnodes, 402 &s.CustomBootnodesEnabled, 403 &s.DappsAddress, 404 &s.DisplayName, 405 &s.Bio, 406 &s.EIP1581Address, 407 &s.Fleet, 408 &s.HideHomeTooltip, 409 &s.InstallationID, 410 &s.KeyUID, 411 &s.KeycardInstanceUID, 412 &s.KeycardPairedOn, 413 &s.KeycardPairing, 414 &s.LastUpdated, 415 &s.LatestDerivedPath, 416 &s.LinkPreviewRequestEnabled, 417 &s.LinkPreviewsEnabledSites, 418 &s.LogLevel, 419 &s.Mnemonic, 420 &s.MnemonicRemoved, 421 &s.Name, 422 &s.Networks, 423 &s.NotificationsEnabled, 424 &s.PushNotificationsServerEnabled, 425 &s.PushNotificationsFromContactsOnly, 426 &s.RemotePushNotificationsEnabled, 427 &s.SendPushNotifications, 428 &s.PushNotificationsBlockMentions, 429 &s.PhotoPath, 430 &s.PinnedMailserver, 431 &s.PreferredName, 432 &s.PreviewPrivacy, 433 &s.PublicKey, 434 &s.RememberSyncingChoice, 435 &s.SigningPhrase, 436 &s.StickerPacksInstalled, 437 &s.StickerPacksPending, 438 &s.StickersRecentStickers, 439 &s.SyncingOnMobileNetwork, 440 &s.DefaultSyncPeriod, 441 &s.UseMailservers, 442 &s.MessagesFromContactsOnly, 443 &s.Usernames, 444 &s.Appearance, 445 &s.ProfilePicturesShowTo, 446 &s.ProfilePicturesVisibility, 447 &s.WalletRootAddress, 448 &s.WalletSetUpPassed, 449 &s.WalletVisibleTokens, 450 &s.WakuBloomFilterMode, 451 &s.WebViewAllowPermissionRequests, 452 &sqlite.JSONBlob{Data: &s.CurrentUserStatus}, 453 &s.SendStatusUpdates, 454 &sqlite.JSONBlob{Data: &s.GifRecents}, 455 &sqlite.JSONBlob{Data: &s.GifFavorites}, 456 &s.OpenseaEnabled, 457 &s.LastBackup, 458 &s.BackupEnabled, 459 &s.TelemetryServerURL, 460 &s.AutoMessageEnabled, 461 &s.GifAPIKey, 462 &s.TestNetworksEnabled, 463 &s.MutualContactEnabled, 464 &s.ProfileMigrationNeeded, 465 &s.IsGoerliEnabled, 466 &s.TokenGroupByCommunity, 467 &s.URLUnfurlingMode, 468 &s.MnemonicWasNotShown, 469 &s.ShowCommunityAssetWhenSendingTokens, 470 &s.DisplayAssetsBelowBalance, 471 &s.DisplayAssetsBelowBalanceThreshold, 472 &s.CollectibleGroupByCollection, 473 &s.CollectibleGroupByCommunity, 474 &s.PeerSyncingEnabled, 475 ) 476 477 return s, err 478 } 479 480 // We should remove this and realated things once mobile team starts usign `settings_notifications` package 481 func (db *Database) GetNotificationsEnabled() (result bool, err error) { 482 err = db.makeSelectRow(NotificationsEnabled).Scan(&result) 483 if err == sql.ErrNoRows { 484 return result, nil 485 } 486 return result, err 487 } 488 489 func (db *Database) GetProfilePicturesVisibility() (result int, err error) { 490 err = db.makeSelectRow(ProfilePicturesVisibility).Scan(&result) 491 if err == sql.ErrNoRows { 492 return result, nil 493 } 494 return result, err 495 } 496 497 func (db *Database) GetPublicKey() (string, error) { 498 return db.makeSelectString(PublicKey) 499 } 500 501 func (db *Database) GetFleet() (string, error) { 502 return db.makeSelectString(Fleet) 503 } 504 505 func (db *Database) GetDappsAddress() (rst types.Address, err error) { 506 err = db.makeSelectRow(DappsAddress).Scan(&rst) 507 if err == sql.ErrNoRows { 508 return rst, nil 509 } 510 return 511 } 512 513 func (db *Database) GetPinnedMailservers() (rst map[string]string, err error) { 514 rst = make(map[string]string) 515 var pinnedMailservers string 516 err = db.db.QueryRow("SELECT COALESCE(pinned_mailservers, '') FROM settings WHERE synthetic_id = 'id'").Scan(&pinnedMailservers) 517 if err == sql.ErrNoRows || pinnedMailservers == "" { 518 return rst, nil 519 } 520 521 err = json.Unmarshal([]byte(pinnedMailservers), &rst) 522 if err != nil { 523 return nil, err 524 } 525 return 526 } 527 528 func (db *Database) CanUseMailservers() (result bool, err error) { 529 err = db.makeSelectRow(UseMailservers).Scan(&result) 530 if err == sql.ErrNoRows { 531 return result, nil 532 } 533 return result, err 534 } 535 536 func (db *Database) CanSyncOnMobileNetwork() (result bool, err error) { 537 err = db.makeSelectRow(SyncingOnMobileNetwork).Scan(&result) 538 if err == sql.ErrNoRows { 539 return result, nil 540 } 541 return result, err 542 } 543 544 func (db *Database) GetDefaultSyncPeriod() (result uint32, err error) { 545 err = db.makeSelectRow(DefaultSyncPeriod).Scan(&result) 546 if err == sql.ErrNoRows { 547 return result, nil 548 } 549 return result, err 550 } 551 552 func (db *Database) GetMessagesFromContactsOnly() (result bool, err error) { 553 err = db.makeSelectRow(MessagesFromContactsOnly).Scan(&result) 554 if err == sql.ErrNoRows { 555 return result, nil 556 } 557 return result, err 558 } 559 560 func (db *Database) GetProfilePicturesShowTo() (result int64, err error) { 561 err = db.makeSelectRow(ProfilePicturesShowTo).Scan(&result) 562 if err == sql.ErrNoRows { 563 return result, nil 564 } 565 return result, err 566 } 567 568 func (db *Database) GetLatestDerivedPath() (result uint, err error) { 569 err = db.makeSelectRow(LatestDerivedPath).Scan(&result) 570 return 571 } 572 573 func (db *Database) GetCurrentStatus(status interface{}) error { 574 err := db.makeSelectRow(CurrentUserStatus).Scan(&sqlite.JSONBlob{Data: &status}) 575 if err == sql.ErrNoRows { 576 return nil 577 } 578 return err 579 } 580 581 func (db *Database) ShouldBroadcastUserStatus() (result bool, err error) { 582 err = db.makeSelectRow(SendStatusUpdates).Scan(&result) 583 // If the `send_status_updates` value is nil the sql.ErrNoRows will be returned 584 // because this feature is opt out, `true` should be returned in the case where no value is found 585 if err == sql.ErrNoRows { 586 return true, nil 587 } 588 return result, err 589 } 590 591 func (db *Database) BackupEnabled() (result bool, err error) { 592 err = db.makeSelectRow(BackupEnabled).Scan(&result) 593 if err == sql.ErrNoRows { 594 return true, nil 595 } 596 return result, err 597 } 598 599 func (db *Database) AutoMessageEnabled() (result bool, err error) { 600 err = db.makeSelectRow(AutoMessageEnabled).Scan(&result) 601 if err == sql.ErrNoRows { 602 return true, nil 603 } 604 return result, err 605 } 606 607 func (db *Database) LastBackup() (result uint64, err error) { 608 err = db.makeSelectRow(LastBackup).Scan(&result) 609 if err == sql.ErrNoRows { 610 return 0, nil 611 } 612 return result, err 613 } 614 615 func (db *Database) SetLastBackup(time uint64) error { 616 return db.SaveSettingField(LastBackup, time) 617 } 618 619 func (db *Database) SetBackupFetched(fetched bool) error { 620 return db.SaveSettingField(BackupFetched, fetched) 621 } 622 623 func (db *Database) BackupFetched() (result bool, err error) { 624 err = db.makeSelectRow(BackupFetched).Scan(&result) 625 if err == sql.ErrNoRows { 626 return true, nil 627 } 628 return result, err 629 } 630 631 func (db *Database) ENSName() (string, error) { 632 return db.makeSelectString(PreferredName) 633 } 634 635 func (db *Database) DeviceName() (string, error) { 636 return db.makeSelectString(DeviceName) 637 } 638 639 func (db *Database) DisplayName() (string, error) { 640 return db.makeSelectString(DisplayName) 641 } 642 643 func (db *Database) Bio() (string, error) { 644 return db.makeSelectString(Bio) 645 } 646 647 func (db *Database) Mnemonic() (string, error) { 648 return db.makeSelectString(Mnemonic) 649 } 650 651 func (db *Database) MnemonicRemoved() (result bool, err error) { 652 err = db.makeSelectRow(MnemonicRemoved).Scan(&result) 653 if err == sql.ErrNoRows { 654 return result, nil 655 } 656 return result, err 657 } 658 659 func (db *Database) GetMnemonicWasNotShown() (result bool, err error) { 660 err = db.makeSelectRow(MnemonicWasNotShown).Scan(&result) 661 if err == sql.ErrNoRows { 662 return result, nil 663 } 664 return result, err 665 } 666 667 func (db *Database) GifAPIKey() (string, error) { 668 return db.makeSelectString(GifAPIKey) 669 } 670 671 func (db *Database) MutualContactEnabled() (result bool, err error) { 672 err = db.makeSelectRow(MutualContactEnabled).Scan(&result) 673 return result, err 674 } 675 676 func (db *Database) GifRecents() (recents json.RawMessage, err error) { 677 err = db.makeSelectRow(GifRecents).Scan(&sqlite.JSONBlob{Data: &recents}) 678 if err == sql.ErrNoRows { 679 return nil, err 680 } 681 return recents, nil 682 } 683 684 func (db *Database) GifFavorites() (favorites json.RawMessage, err error) { 685 err = db.makeSelectRow(GifFavourites).Scan(&sqlite.JSONBlob{Data: &favorites}) 686 if err == sql.ErrNoRows { 687 return nil, err 688 } 689 return favorites, nil 690 } 691 692 func (db *Database) GetPreferredUsername() (string, error) { 693 return db.makeSelectString(PreferredName) 694 } 695 696 func (db *Database) GetCurrency() (string, error) { 697 return db.makeSelectString(Currency) 698 } 699 700 func (db *Database) GetInstalledStickerPacks() (rst *json.RawMessage, err error) { 701 err = db.makeSelectRow(StickersPacksInstalled).Scan(&rst) 702 return 703 } 704 705 func (db *Database) GetPendingStickerPacks() (rst *json.RawMessage, err error) { 706 err = db.makeSelectRow(StickersPacksPending).Scan(&rst) 707 return 708 } 709 710 func (db *Database) GetRecentStickers() (rst *json.RawMessage, err error) { 711 err = db.makeSelectRow(StickersRecentStickers).Scan(&rst) 712 return 713 } 714 715 func (db *Database) SetPinnedMailservers(mailservers map[string]string) error { 716 return db.SaveSettingField(PinnedMailservers, mailservers) 717 } 718 719 func (db *Database) SetUseMailservers(value bool) error { 720 return db.SaveSettingField(UseMailservers, value) 721 } 722 723 func (db *Database) GetWalletRootAddress() (rst types.Address, err error) { 724 err = db.makeSelectRow(WalletRootAddress).Scan(&rst) 725 if err == sql.ErrNoRows { 726 return rst, nil 727 } 728 return 729 } 730 731 func (db *Database) GetEIP1581Address() (rst types.Address, err error) { 732 err = db.makeSelectRow(EIP1581Address).Scan(&rst) 733 if err == sql.ErrNoRows { 734 return rst, nil 735 } 736 return 737 } 738 739 func (db *Database) GetMasterAddress() (rst types.Address, err error) { 740 err = db.makeSelectRow(MasterAddress).Scan(&rst) 741 if err == sql.ErrNoRows { 742 return rst, nil 743 } 744 return 745 } 746 747 func (db *Database) GetTestNetworksEnabled() (result bool, err error) { 748 err = db.makeSelectRow(TestNetworksEnabled).Scan(&result) 749 if err == sql.ErrNoRows { 750 return result, nil 751 } 752 return result, err 753 } 754 755 func (db *Database) GetIsGoerliEnabled() (result bool, err error) { 756 err = db.makeSelectRow(IsGoerliEnabled).Scan(&result) 757 if err == sql.ErrNoRows { 758 return result, nil 759 } 760 return result, err 761 } 762 763 func (db *Database) SetPeerSyncingEnabled(value bool) error { 764 return db.SaveSettingField(PeerSyncingEnabled, value) 765 } 766 767 func (db *Database) SetSyncingOnMobileNetwork(value bool) error { 768 err := db.SaveSettingField(SyncingOnMobileNetwork, value) 769 if err != nil { 770 return err 771 } 772 return db.SaveSettingField(RememberSyncingChoice, true) 773 } 774 775 func (db *Database) GetPeerSyncingEnabled() (result bool, err error) { 776 err = db.makeSelectRow(PeerSyncingEnabled).Scan(&result) 777 if err == sql.ErrNoRows { 778 return result, nil 779 } 780 return result, err 781 } 782 783 func (db *Database) GetTokenGroupByCommunity() (result bool, err error) { 784 err = db.makeSelectRow(TokenGroupByCommunity).Scan(&result) 785 if err == sql.ErrNoRows { 786 return result, nil 787 } 788 return result, err 789 } 790 791 func (db *Database) SetTokenGroupByCommunity(value bool) error { 792 return db.SaveSettingField(TokenGroupByCommunity, value) 793 } 794 795 func (db *Database) GetCollectibleGroupByCollection() (result bool, err error) { 796 err = db.makeSelectRow(CollectibleGroupByCollection).Scan(&result) 797 if err == sql.ErrNoRows { 798 return result, nil 799 } 800 return result, err 801 } 802 803 func (db *Database) SetCollectibleGroupByCollection(value bool) error { 804 return db.SaveSettingField(CollectibleGroupByCollection, value) 805 } 806 807 func (db *Database) GetCollectibleGroupByCommunity() (result bool, err error) { 808 err = db.makeSelectRow(CollectibleGroupByCommunity).Scan(&result) 809 if err == sql.ErrNoRows { 810 return result, nil 811 } 812 return result, err 813 } 814 815 func (db *Database) SetCollectibleGroupByCommunity(value bool) error { 816 return db.SaveSettingField(CollectibleGroupByCommunity, value) 817 } 818 819 func (db *Database) GetTelemetryServerURL() (string, error) { 820 return db.makeSelectString(TelemetryServerURL) 821 } 822 823 func (db *Database) ProfileMigrationNeeded() (result bool, err error) { 824 err = db.makeSelectRow(ProfileMigrationNeeded).Scan(&result) 825 return result, err 826 } 827 828 func (db *Database) URLUnfurlingMode() (result int64, err error) { 829 err = db.makeSelectRow(URLUnfurlingMode).Scan(&result) 830 if err == sql.ErrNoRows { 831 return result, nil 832 } 833 return result, err 834 } 835 836 func (db *Database) SubscribeToChanges() chan *SyncSettingField { 837 s := make(chan *SyncSettingField, 100) 838 db.changesSubscriptions = append(db.changesSubscriptions, s) 839 return s 840 } 841 842 func (db *Database) postChangesToSubscribers(change *SyncSettingField) { 843 // Publish on channels, drop if buffer is full 844 for _, s := range db.changesSubscriptions { 845 select { 846 case s <- change: 847 default: 848 log.Warn("settings changes subscription channel full, dropping message") 849 } 850 } 851 } 852 853 func (db *Database) MnemonicWasShown() error { 854 return db.SaveSettingField(MnemonicWasNotShown, false) 855 }