467 lines
14 KiB
Go
467 lines
14 KiB
Go
package settings
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"reflect"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/status-im/status-go/protocol/common"
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
|
"github.com/status-im/status-go/sqlite"
|
|
)
|
|
|
|
var (
|
|
ErrTypeAssertionFailed = errors.New("type assertion of interface value failed")
|
|
)
|
|
|
|
func buildRawSyncSettingMessage(msg *protobuf.SyncSetting, chatID string) (*common.RawMessage, error) {
|
|
encodedMessage, err := proto.Marshal(msg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &common.RawMessage{
|
|
LocalChatID: chatID,
|
|
Payload: encodedMessage,
|
|
MessageType: protobuf.ApplicationMetadataMessage_SYNC_SETTING,
|
|
ResendAutomatically: true,
|
|
}, nil
|
|
}
|
|
|
|
// Currency
|
|
|
|
func buildRawCurrencySyncMessage(v string, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
pb := &protobuf.SyncSetting{
|
|
Type: protobuf.SyncSetting_CURRENCY,
|
|
Value: &protobuf.SyncSetting_ValueString{ValueString: v},
|
|
Clock: clock,
|
|
}
|
|
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
|
return rm, pb, err
|
|
}
|
|
|
|
func currencyProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
v, err := assertString(value)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return buildRawCurrencySyncMessage(v, clock, chatID)
|
|
}
|
|
|
|
func currencyProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
return buildRawCurrencySyncMessage(s.Currency, clock, chatID)
|
|
}
|
|
|
|
// GifFavorites
|
|
|
|
func buildRawGifFavoritesSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
pb := &protobuf.SyncSetting{
|
|
Type: protobuf.SyncSetting_GIF_FAVOURITES,
|
|
Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
|
|
Clock: clock,
|
|
}
|
|
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
|
return rm, pb, err
|
|
}
|
|
|
|
func gifFavouritesProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
v, err := assertBytes(value)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return buildRawGifFavoritesSyncMessage(v, clock, chatID)
|
|
}
|
|
|
|
func gifFavouritesProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
gf := extractJSONRawMessage(s.GifFavorites)
|
|
return buildRawGifFavoritesSyncMessage(gf, clock, chatID)
|
|
}
|
|
|
|
// GifRecents
|
|
|
|
func buildRawGifRecentsSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
pb := &protobuf.SyncSetting{
|
|
Type: protobuf.SyncSetting_GIF_RECENTS,
|
|
Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
|
|
Clock: clock,
|
|
}
|
|
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
|
return rm, pb, err
|
|
}
|
|
|
|
func gifRecentsProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
v, err := assertBytes(value)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return buildRawGifRecentsSyncMessage(v, clock, chatID)
|
|
}
|
|
|
|
func gifRecentsProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
gr := extractJSONRawMessage(s.GifRecents)
|
|
return buildRawGifRecentsSyncMessage(gr, clock, chatID)
|
|
}
|
|
|
|
// MessagesFromContactsOnly
|
|
|
|
func buildRawMessagesFromContactsOnlySyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
pb := &protobuf.SyncSetting{
|
|
Type: protobuf.SyncSetting_MESSAGES_FROM_CONTACTS_ONLY,
|
|
Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
|
|
Clock: clock,
|
|
}
|
|
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
|
return rm, pb, err
|
|
}
|
|
|
|
func messagesFromContactsOnlyProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
v, err := assertBool(value)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return buildRawMessagesFromContactsOnlySyncMessage(v, clock, chatID)
|
|
}
|
|
|
|
func messagesFromContactsOnlyProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
return buildRawMessagesFromContactsOnlySyncMessage(s.MessagesFromContactsOnly, clock, chatID)
|
|
}
|
|
|
|
// PreferredName
|
|
|
|
func buildRawPreferredNameSyncMessage(v string, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
pb := &protobuf.SyncSetting{
|
|
Type: protobuf.SyncSetting_PREFERRED_NAME,
|
|
Value: &protobuf.SyncSetting_ValueString{ValueString: v},
|
|
Clock: clock,
|
|
}
|
|
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
|
return rm, pb, err
|
|
}
|
|
|
|
func preferredNameProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
v, err := assertString(value)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return buildRawPreferredNameSyncMessage(v, clock, chatID)
|
|
}
|
|
|
|
func preferredNameProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
var pn string
|
|
if s.PreferredName != nil {
|
|
pn = *s.PreferredName
|
|
}
|
|
|
|
return buildRawPreferredNameSyncMessage(pn, clock, chatID)
|
|
}
|
|
|
|
// PreviewPrivacy
|
|
|
|
func buildRawPreviewPrivacySyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
pb := &protobuf.SyncSetting{
|
|
Type: protobuf.SyncSetting_PREVIEW_PRIVACY,
|
|
Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
|
|
Clock: clock,
|
|
}
|
|
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
|
return rm, pb, err
|
|
}
|
|
|
|
func previewPrivacyProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
v, err := assertBool(value)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return buildRawPreviewPrivacySyncMessage(v, clock, chatID)
|
|
}
|
|
|
|
func previewPrivacyProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
return buildRawPreviewPrivacySyncMessage(s.PreviewPrivacy, clock, chatID)
|
|
}
|
|
|
|
// ProfilePicturesShowTo
|
|
|
|
func buildRawProfilePicturesShowToSyncMessage(v int64, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
pb := &protobuf.SyncSetting{
|
|
Type: protobuf.SyncSetting_PROFILE_PICTURES_SHOW_TO,
|
|
Value: &protobuf.SyncSetting_ValueInt64{ValueInt64: v},
|
|
Clock: clock,
|
|
}
|
|
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
|
return rm, pb, err
|
|
}
|
|
|
|
func profilePicturesShowToProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
v, err := parseNumberToInt64(value)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return buildRawProfilePicturesShowToSyncMessage(v, clock, chatID)
|
|
}
|
|
|
|
func profilePicturesShowToProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
return buildRawProfilePicturesShowToSyncMessage(int64(s.ProfilePicturesShowTo), clock, chatID)
|
|
}
|
|
|
|
// ProfilePicturesVisibility
|
|
|
|
func buildRawProfilePicturesVisibilitySyncMessage(v int64, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
pb := &protobuf.SyncSetting{
|
|
Type: protobuf.SyncSetting_PROFILE_PICTURES_VISIBILITY,
|
|
Value: &protobuf.SyncSetting_ValueInt64{ValueInt64: v},
|
|
Clock: clock,
|
|
}
|
|
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
|
return rm, pb, err
|
|
}
|
|
|
|
func profilePicturesVisibilityProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
v, err := parseNumberToInt64(value)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return buildRawProfilePicturesVisibilitySyncMessage(v, clock, chatID)
|
|
}
|
|
|
|
func profilePicturesVisibilityProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
return buildRawProfilePicturesVisibilitySyncMessage(int64(s.ProfilePicturesVisibility), clock, chatID)
|
|
}
|
|
|
|
// SendStatusUpdates
|
|
|
|
func buildRawSendStatusUpdatesSyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
pb := &protobuf.SyncSetting{
|
|
Type: protobuf.SyncSetting_SEND_STATUS_UPDATES,
|
|
Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
|
|
Clock: clock,
|
|
}
|
|
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
|
return rm, pb, err
|
|
}
|
|
|
|
func sendStatusUpdatesProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
v, err := assertBool(value)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return buildRawSendStatusUpdatesSyncMessage(v, clock, chatID)
|
|
}
|
|
|
|
func sendStatusUpdatesProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
return buildRawSendStatusUpdatesSyncMessage(s.SendStatusUpdates, clock, chatID)
|
|
}
|
|
|
|
// StickerPacksInstalled
|
|
|
|
func buildRawStickerPacksInstalledSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
pb := &protobuf.SyncSetting{
|
|
Type: protobuf.SyncSetting_STICKERS_PACKS_INSTALLED,
|
|
Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
|
|
Clock: clock,
|
|
}
|
|
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
|
return rm, pb, err
|
|
}
|
|
|
|
func stickersPacksInstalledProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
v, err := parseJSONBlobData(value)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return buildRawStickerPacksInstalledSyncMessage(v, clock, chatID)
|
|
}
|
|
|
|
func stickersPacksInstalledProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
spi := extractJSONRawMessage(s.StickerPacksInstalled)
|
|
return buildRawStickerPacksInstalledSyncMessage(spi, clock, chatID)
|
|
}
|
|
|
|
// StickerPacksPending
|
|
|
|
func buildRawStickerPacksPendingSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
pb := &protobuf.SyncSetting{
|
|
Type: protobuf.SyncSetting_STICKERS_PACKS_PENDING,
|
|
Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
|
|
Clock: clock,
|
|
}
|
|
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
|
return rm, pb, err
|
|
}
|
|
|
|
func stickersPacksPendingProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
v, err := parseJSONBlobData(value)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return buildRawStickerPacksPendingSyncMessage(v, clock, chatID)
|
|
}
|
|
|
|
func stickersPacksPendingProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
spp := extractJSONRawMessage(s.StickerPacksPending)
|
|
return buildRawStickerPacksPendingSyncMessage(spp, clock, chatID)
|
|
}
|
|
|
|
// StickersRecentStickers
|
|
|
|
func buildRawStickersRecentStickersSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
pb := &protobuf.SyncSetting{
|
|
Type: protobuf.SyncSetting_STICKERS_RECENT_STICKERS,
|
|
Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
|
|
Clock: clock,
|
|
}
|
|
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
|
return rm, pb, err
|
|
}
|
|
|
|
func stickersRecentStickersProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
v, err := parseJSONBlobData(value)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return buildRawStickersRecentStickersSyncMessage(v, clock, chatID)
|
|
}
|
|
|
|
func stickersRecentStickersProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
srs := extractJSONRawMessage(s.StickersRecentStickers)
|
|
return buildRawStickersRecentStickersSyncMessage(srs, clock, chatID)
|
|
}
|
|
|
|
func assertBytes(value interface{}) ([]byte, error) {
|
|
v, ok := value.([]byte)
|
|
if !ok {
|
|
return nil, errors.Wrapf(ErrTypeAssertionFailed, "expected '[]byte', received %T", value)
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
func assertBool(value interface{}) (bool, error) {
|
|
v, ok := value.(bool)
|
|
if !ok {
|
|
return false, errors.Wrapf(ErrTypeAssertionFailed, "expected 'bool', received %T", value)
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
func assertString(value interface{}) (string, error) {
|
|
rv := reflect.ValueOf(value)
|
|
if rv.Kind() == reflect.Ptr {
|
|
value = *value.(*string)
|
|
}
|
|
v, ok := value.(string)
|
|
if !ok {
|
|
return "", errors.Wrapf(ErrTypeAssertionFailed, "expected 'string', received %T", value)
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
func parseJSONBlobData(value interface{}) ([]byte, error) {
|
|
switch v := value.(type) {
|
|
case []byte:
|
|
return v, nil
|
|
case *sqlite.JSONBlob:
|
|
return extractJSONBlob(v)
|
|
default:
|
|
return nil, errors.Wrapf(ErrTypeAssertionFailed, "expected []byte or *sqlite.JSONBlob, received %T", value)
|
|
}
|
|
}
|
|
|
|
func parseNumberToInt64(value interface{}) (int64, error) {
|
|
switch v := value.(type) {
|
|
case float32:
|
|
return int64(v), nil
|
|
case float64:
|
|
return int64(v), nil
|
|
case int:
|
|
return int64(v), nil
|
|
case int8:
|
|
return int64(v), nil
|
|
case int16:
|
|
return int64(v), nil
|
|
case int32:
|
|
return int64(v), nil
|
|
case int64:
|
|
return v, nil
|
|
case uint:
|
|
return int64(v), nil
|
|
case uint8:
|
|
return int64(v), nil
|
|
case uint16:
|
|
return int64(v), nil
|
|
case uint32:
|
|
return int64(v), nil
|
|
case uint64:
|
|
return int64(v), nil
|
|
case ProfilePicturesShowToType:
|
|
return int64(v), nil
|
|
case ProfilePicturesVisibilityType:
|
|
return int64(v), nil
|
|
default:
|
|
return 0, errors.Wrapf(ErrTypeAssertionFailed, "expected a numeric type, received %T", value)
|
|
}
|
|
}
|
|
|
|
func extractJSONBlob(jb *sqlite.JSONBlob) ([]byte, error) {
|
|
value, err := jb.Value()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if value == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
return value.([]byte), nil
|
|
}
|
|
|
|
func extractJSONRawMessage(jrm *json.RawMessage) []byte {
|
|
if jrm == nil {
|
|
return nil
|
|
}
|
|
out, _ := jrm.MarshalJSON() // Don't need to parse error because it is always nil
|
|
if len(out) == 0 || bytes.Equal(out, []byte("null")) {
|
|
return nil
|
|
}
|
|
return out
|
|
}
|
|
|
|
// DisplayName
|
|
|
|
func buildRawDisplayNameSyncMessage(v string, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
pb := &protobuf.SyncSetting{
|
|
Type: protobuf.SyncSetting_DISPLAY_NAME,
|
|
Value: &protobuf.SyncSetting_ValueString{ValueString: v},
|
|
Clock: clock,
|
|
}
|
|
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
|
return rm, pb, err
|
|
}
|
|
|
|
func displayNameProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
v, err := assertString(value)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return buildRawDisplayNameSyncMessage(v, clock, chatID)
|
|
}
|
|
|
|
func displayNameProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
|
|
|
return buildRawDisplayNameSyncMessage(s.DisplayName, clock, chatID)
|
|
}
|