feat: disappearing messages setting now sync correctly in user config

we also load the visible control message, added back a lot of WIP logging while we are testing
pull/2971/head
William Grant 2 years ago
parent 60e5503e6a
commit deceae4119

@ -119,10 +119,10 @@ import {
import {
DisappearingMessageConversationType,
isLegacyDisappearingModeEnabled,
resolveLegacyDisappearingMode,
} from '../util/expiringMessages';
import { markAttributesAsReadIfNeeded } from './messageFactory';
import { ReleasedFeatures } from '../util/releaseFeature';
type InMemoryConvoInfos = {
mentionedUs: boolean;
@ -837,16 +837,18 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
if (
this.get('lastDisappearingMessageChangeTimestamp') > lastDisappearingMessageChangeTimestamp
) {
window.log.info('updateExpireTimer() This is an outdated disappearing message setting');
window.log.info('WIP: updateExpireTimer() This is an outdated disappearing message setting');
return;
}
// NOTE: We don' mind if the message is the same, we still want to update the conversation because we want to show visible control messages we receive an ExpirationTimerUpdate
if (
fromConfigMessage &&
isEqual(expirationType, this.get('expirationType')) &&
isEqual(expireTimer, this.get('expireTimer'))
) {
window.log.info(
'updateExpireTimer() Dropping ExpireTimerUpdate message as we already have the same one set.'
'WIP: updateExpireTimer() Dropping ExpireTimerUpdate message as we already have the same one set.'
);
return;
}
@ -856,7 +858,8 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
// Note the legacy type should only be in the UI, it should change the the conversation type default before we send
if (expirationType === 'legacy') {
expirationType = resolveLegacyDisappearingMode(this);
expirationType = resolveLegacyDisappearingMode(this, expireTimer);
window.log.debug(`WIP: resolving legacy disappearing mode to ${expirationType}`);
}
// When we add a disappearing messages notification to the conversation, we want it
@ -892,10 +895,12 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
fromSync,
},
// TODO legacy messages support will be removed in a future release
expirationType: isLegacyDisappearingModeEnabled(expirationType)
? undefined
: expirationType,
expireTimer: isLegacyDisappearingModeEnabled(expirationType) ? undefined : expireTimer,
expirationType: ReleasedFeatures.isDisappearMessageV2FeatureReleasedCached()
? expirationType
: undefined,
expireTimer: ReleasedFeatures.isDisappearMessageV2FeatureReleasedCached()
? expireTimer
: undefined,
};
if (!message) {
@ -929,6 +934,9 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
// if change was made remotely, don't send it to the contact/group
if (receivedAt || fromSync || fromConfigMessage) {
window.log.debug(
`WIP: updateExpireTimer() Not sending an ExpireTimerUpdate message because the change was made remotely receivedAt:${receivedAt} fromSync:${fromSync} fromConfigMessage:${fromConfigMessage} `
);
return;
}
@ -942,13 +950,17 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
if (this.isMe()) {
// TODO Check that the args are correct
// This might be happening too late in the message pipeline. Maybe should be moved to handleExpirationTimerUpdateNoCommit()
if (expireUpdate.expirationType === 'deleteAfterRead') {
window.log.info('Note to Self messages cannot be delete after read!');
return;
}
const expirationTimerMessage = new ExpirationTimerUpdateMessage(expireUpdate);
window.log.debug(
`WIP: Sending ExpirationTimerUpdate message to Note to Self expirationTimerMessage:${JSON.stringify(
expirationTimerMessage
)}`
);
await message?.sendSyncMessageOnly(expirationTimerMessage);
return;
}

@ -976,7 +976,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
}
public async sendSyncMessageOnly(contentMessage: ContentMessage) {
const now = Date.now();
const now = GetNetworkTime.getNowWithNetworkOffset();
this.set({
sent_to: [UserUtils.getOurPubKeyStrFromCache()],
@ -1015,16 +1015,16 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
dataMessage.flags === SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE)
);
const expirationTimer = isLegacyDisappearingDataMessage
? Number(dataMessage.expireTimer)
: content.expirationTimer;
let expirationType: DisappearingMessageType = DisappearingMessageMode[content.expirationType];
if (isLegacyDisappearingDataMessage) {
expirationType = resolveLegacyDisappearingMode(conversation);
expirationType = resolveLegacyDisappearingMode(conversation, expirationTimer);
}
const expirationTimer = isLegacyDisappearingDataMessage
? Number(dataMessage.expireTimer)
: content.expirationTimer;
const lastDisappearingMessageChangeTimestamp = content.lastDisappearingMessageChangeTimestamp
? Number(content.lastDisappearingMessageChangeTimestamp)
: undefined;

@ -18,7 +18,7 @@ import { getOpenGroupV2ConversationId } from '../session/apis/open_group_api/uti
import { getSwarmPollingInstance } from '../session/apis/snode_api';
import { getConversationController } from '../session/conversations';
import { IncomingMessage } from '../session/messages/incoming/IncomingMessage';
import { ProfileManager } from '../session/profile_manager/ProfileManager';
import { Profile, ProfileManager } from '../session/profile_manager/ProfileManager';
import { PubKey } from '../session/types';
import { StringUtils, UserUtils } from '../session/utils';
import { toHex } from '../session/utils/String';
@ -192,6 +192,10 @@ async function updateLibsessionLatestProcessedUserTimestamp(
}
}
/**
* NOTE When adding new properties to the wrapper, don't update the conversation model here because the merge has not been done yet.
* Instead you will need to updateOurProfileLegacyOrViaLibSession() to support them
*/
async function handleUserProfileUpdate(result: IncomingConfResult): Promise<IncomingConfResult> {
const updateUserInfo = await UserConfigWrapperActions.getUserInfo();
if (!updateUserInfo) {
@ -206,14 +210,52 @@ async function handleUserProfileUpdate(result: IncomingConfResult): Promise<Inco
const picUpdate = !isEmpty(updateUserInfo.key) && !isEmpty(updateUserInfo.url);
// NOTE: if you do any changes to the settings of a user which are synced, it should be done above the `updateOurProfileLegacyOrViaLibSession` call
await updateOurProfileLegacyOrViaLibSession(
result.latestEnvelopeTimestamp,
updateUserInfo.name,
picUpdate ? updateUserInfo.url : null,
picUpdate ? updateUserInfo.key : null,
updateUserInfo.priority
);
// NOTE: if you do any changes to the user's settings which are synced, it should be done above the `updateOurProfileLegacyOrViaLibSession` call
await updateOurProfileLegacyOrViaLibSession({
sentAt: result.latestEnvelopeTimestamp,
displayName: updateUserInfo.name,
profileUrl: picUpdate ? updateUserInfo.url : null,
profileKey: picUpdate ? updateUserInfo.key : null,
priority: updateUserInfo.priority,
});
// NOTE: If we want to update the conversation in memory with changes from the updated user profile we need to wait untl the profile has been updated to prevent multiple merge conflicts
const ourConvo = getConversationController().get(UserUtils.getOurPubKeyStrFromCache());
if (ourConvo) {
window.log.debug(`WIP: [userProfileWrapper] Checking for disappearing messages changes`);
let changes = false;
const expireTimer = ourConvo.get('expireTimer');
const wrapperNoteToSelfExpirySeconds = await UserConfigWrapperActions.getNoteToSelfExpiry();
if (wrapperNoteToSelfExpirySeconds !== expireTimer) {
// we trust the wrapper more than the DB, so let's update the DB but we don't show it in the UI
ourConvo.set('expireTimer', wrapperNoteToSelfExpirySeconds);
// NOTE Can only be 'off' or 'deleteAfterSend' so we don't need to check the expirationType we can just override it
ourConvo.set(
'expirationType',
wrapperNoteToSelfExpirySeconds && wrapperNoteToSelfExpirySeconds > 0
? 'deleteAfterSend'
: 'off'
);
changes = true;
window.log.debug(
`WIP: [userProfileWrapper] updating disappearing messages to`,
wrapperNoteToSelfExpirySeconds && wrapperNoteToSelfExpirySeconds > 0
? 'deleteAfterSend'
: 'off',
' ',
wrapperNoteToSelfExpirySeconds
);
}
// make sure to write the changes to the database now as the `AvatarDownloadJob` triggered by updateOurProfileLegacyOrViaLibSession might take some time before getting run
if (changes) {
await ourConvo.commit();
}
}
const settingsKey = SettingsKey.latestUserProfileEnvelopeTimestamp;
const currentLatestEnvelopeProcessed = Storage.get(settingsKey) || 0;
@ -867,14 +909,19 @@ async function handleConfigMessagesViaLibSession(
await processMergingResults(incomingMergeResult);
}
async function updateOurProfileLegacyOrViaLibSession(
sentAt: number,
displayName: string,
profileUrl: string | null,
profileKey: Uint8Array | null,
priority: number | null // passing null means to not update the priority at all (used for legacy config message for now)
) {
await ProfileManager.updateOurProfileSync(displayName, profileUrl, profileKey, priority);
async function updateOurProfileLegacyOrViaLibSession({
sentAt,
displayName,
profileUrl,
profileKey,
priority,
}: Profile & { sentAt: number }) {
await ProfileManager.updateOurProfileSync({
displayName,
profileUrl,
profileKey,
priority,
});
await setLastProfileUpdateTimestamp(toNumber(sentAt));
// do not trigger a signin by linking if the display name is empty
@ -901,13 +948,13 @@ async function handleOurProfileUpdateLegacy(
);
const { profileKey, profilePicture, displayName } = configMessage;
await updateOurProfileLegacyOrViaLibSession(
toNumber(sentAt),
await updateOurProfileLegacyOrViaLibSession({
sentAt: toNumber(sentAt),
displayName,
profilePicture,
profileUrl: profilePicture,
profileKey,
null // passing null to say do not the prioroti, as we do not get one from the legacy config message
);
priority: null, // passing null to say do not set the priority, as we do not get one from the legacy config message
});
}
}

@ -232,7 +232,11 @@ export async function handleSwarmDataMessage(
}
if (!messageHasVisibleContent(cleanDataMessage)) {
window?.log?.debug(`WIP: Message ${getEnvelopeId(envelope)} ignored; it was empty`);
window?.log?.debug(
`WIP: Message ${getEnvelopeId(envelope)} ignored; it was empty`,
cleanDataMessage
);
await removeFromCache(envelope);
return;
}
@ -257,10 +261,7 @@ export async function handleSwarmDataMessage(
sentAt: sentAtTimestamp,
});
if (isSyncedMessage) {
// TODO handle sync messages expiring separately?
window.log.debug('WIP: Sync Message dropping');
} else {
if (!isEmpty(expireUpdate)) {
msgModel = handleExpireUpdate(convoToAddMessageTo, msgModel, expireUpdate);
}

@ -446,6 +446,7 @@ export async function handleMessageJob(
providedChangeTimestamp: lastDisappearingMessageChangeTimestamp,
providedSource: source,
receivedAt: messageModel.get('received_at'),
// NOTE we don't commit yet because we want to get the message id, see below
shouldCommit: false,
existingMessage: messageModel,
fromConfigMessage: false,

@ -4,15 +4,17 @@ import { UserUtils } from '../utils';
import { toHex } from '../utils/String';
import { AvatarDownload } from '../utils/job_runners/jobs/AvatarDownloadJob';
export type Profile = {
displayName: string | undefined;
profileUrl: string | null;
profileKey: Uint8Array | null;
priority: number | null; // passing null means to not update the priority at all (used for legacy config message for now)
};
/**
* This can be used to update our conversation display name with the given name right away, and plan an AvatarDownloadJob to retrieve the new avatar if needed to download it
*/
async function updateOurProfileSync(
displayName: string | undefined,
profileUrl: string | null,
profileKey: Uint8Array | null,
priority: number | null
) {
async function updateOurProfileSync({ displayName, profileUrl, profileKey, priority }: Profile) {
const us = UserUtils.getOurPubKeyStrFromCache();
const ourConvo = getConversationController().get(us);
if (!ourConvo?.id) {

@ -25,13 +25,14 @@ async function insertUserProfileIntoWrapper(convoId: string) {
const areBlindedMsgRequestEnabled = !!Storage.get(SettingsKey.hasBlindedMsgRequestsEnabled);
const expirySeconds = ourConvo.get('expireTimer') || 0;
window.log.debug(
`inserting into userprofile wrapper: username:"${dbName}", priority:${priority} image:${JSON.stringify(
{ url: dbProfileUrl, key: dbProfileKey }
)}, settings: ${JSON.stringify({ areBlindedMsgRequestEnabled })}`
)}, settings: ${JSON.stringify({ areBlindedMsgRequestEnabled, expirySeconds })}`
);
// const expirySeconds = ourConvo.get('expireTimer') || 0;
// TODO setup getExpiry and setExpiry
if (dbProfileUrl && !isEmpty(dbProfileKey)) {
await UserConfigWrapperActions.setUserInfo(dbName, priority, {
url: dbProfileUrl,
@ -41,6 +42,7 @@ async function insertUserProfileIntoWrapper(convoId: string) {
await UserConfigWrapperActions.setUserInfo(dbName, priority, null);
}
await UserConfigWrapperActions.setEnableBlindedMsgRequest(areBlindedMsgRequestEnabled);
await UserConfigWrapperActions.setNoteToSelfExpiry(expirySeconds);
}
function isUserProfileToStoreInWrapper(convoId: string) {

@ -390,7 +390,7 @@ export const buildSyncMessage = (
if (expireUpdate && !isEmpty(expireUpdate)) {
return buildSyncExpireTimerMessage(identifier, expireUpdate, timestamp, syncTarget);
}
window.log.warn('Building Sync Expire Timer Message failed', dataMessage, expireUpdate);
window.log.warn('WIP: Building Sync Expire Timer Message failed', dataMessage, expireUpdate);
}
return buildSyncVisibleMessage(identifier, dataMessage, timestamp, syncTarget);
};

@ -13,7 +13,9 @@ import { MessageModel } from '../models/message';
import { GetNetworkTime } from '../session/apis/snode_api/getNetworkTime';
import { ReleasedFeatures } from './releaseFeature';
export const DisappearingMessageMode = ['deleteAfterRead', 'deleteAfterSend'];
// NOTE this must match Content.ExpirationType in the protobuf
// TODO double check this
export const DisappearingMessageMode = ['unknown', 'deleteAfterRead', 'deleteAfterSend'];
export type DisappearingMessageType = typeof DisappearingMessageMode[number];
// NOTE these cannot be imported in the nodejs side yet. We need to move the types to the own file with no window imports
// TODO legacy messages support will be removed in a future release
@ -289,10 +291,21 @@ export function isLegacyDisappearingModeEnabled(
// TODO legacy messages support will be removed in a future release
/**
* This function is used to set the mode for legacy disappearing messages depending on the default for the conversation type
*
* NOTE Should only be used when sending or receiving data messages (protobuf)
*
* @param convo Conversation we want to set
* @returns Disappearing mode we should use
*/
export function resolveLegacyDisappearingMode(convo: ConversationModel): DisappearingMessageType {
export function resolveLegacyDisappearingMode(
convo: ConversationModel,
expireTimer?: number
): DisappearingMessageType {
if (expireTimer === 0) {
// NOTE we would want this to be undefined but because of an issue with the protobuf implement we need to have a value
return 'unknown';
}
if (convo.isMe() || convo.isClosedGroup()) {
return 'deleteAfterSend';
}

Loading…
Cancel
Save