session-desktop/ts/session/profile_manager/ProfileManager.ts

97 lines
3.8 KiB
TypeScript

import { isEmpty } from 'lodash';
import { getConversationController } from '../conversations';
import { UserUtils } from '../utils';
import { toHex } from '../utils/String';
import { AvatarDownload } from '../utils/job_runners/jobs/AvatarDownloadJob';
/**
* 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
) {
const us = UserUtils.getOurPubKeyStrFromCache();
const ourConvo = getConversationController().get(us);
if (!ourConvo?.id) {
window?.log?.warn('[profileupdate] Cannot update our profile without convo associated');
return;
}
await updateProfileOfContact(us, displayName, profileUrl, profileKey);
if (priority !== null && ourConvo.get('priority') !== priority) {
ourConvo.set('priority', priority);
await ourConvo.commit();
}
}
/**
* This can be used to update the display name of the given pubkey right away, and plan an AvatarDownloadJob to retrieve the new avatar if needed to download it.
*/
async function updateProfileOfContact(
pubkey: string,
displayName: string | null | undefined,
profileUrl: string | null | undefined,
profileKey: Uint8Array | null | undefined
) {
const conversation = getConversationController().get(pubkey);
if (!conversation || !conversation.isPrivate()) {
window.log.warn('updateProfileOfContact can only be used for existing and private convos');
return;
}
let changes = false;
const existingDisplayName = conversation.get('displayNameInProfile');
// avoid setting the display name to an invalid value
if (existingDisplayName !== displayName && !isEmpty(displayName)) {
conversation.set('displayNameInProfile', displayName || undefined);
changes = true;
}
const profileKeyHex = !profileKey || isEmpty(profileKey) ? null : toHex(profileKey);
let avatarChanged = false;
// trust whatever we get as an update. It either comes from a shared config wrapper or one of that user's message. But in any case we should trust it, even if it gets resetted.
const prevPointer = conversation.get('avatarPointer');
const prevProfileKey = conversation.get('profileKey');
// we have to set it right away and not in the async download job, as the next .commit will save it to the
// database and wrapper (and we do not want to override anything in the wrapper's content
// with what we have locally, so we need the commit to have already the right values in pointer and profileKey)
if (prevPointer !== profileUrl || prevProfileKey !== profileKeyHex) {
conversation.set({
avatarPointer: profileUrl || undefined,
profileKey: profileKeyHex || undefined,
});
// if the avatar data we had before is not the same of what we received, we need to schedule a new avatar download job.
avatarChanged = true; // allow changes from strings to null/undefined to trigger a AvatarDownloadJob. If that happens, we want to remove the local attachment file.
}
// if we have a local path to an downloaded avatar, but no corresponding url/key for it, it means that
// the avatar was most likely removed so let's remove our link to that file.
if ((!profileUrl || !profileKeyHex) && conversation.get('avatarInProfile')) {
conversation.set({ avatarInProfile: undefined });
changes = true;
}
if (changes) {
await conversation.commit();
}
if (avatarChanged) {
// this call will download the new avatar or reset the local filepath if needed
await AvatarDownload.addAvatarDownloadJob({
conversationId: pubkey,
});
}
}
export const ProfileManager = {
updateOurProfileSync,
updateProfileOfContact,
};