status-go/multiaccounts/settings/sync_protobuf_factories.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

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)
}