Refactor sticker sync logic

This commit is contained in:
Fedor Indutny 2025-02-06 11:00:55 -08:00 committed by GitHub
parent ce6ae78230
commit 9ac46b8e8a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 264 additions and 187 deletions

View file

@ -2343,17 +2343,17 @@ export async function startApp(): Promise<void> {
if (status === 'installed' && isRemove) {
window.reduxActions.stickers.uninstallStickerPack(id, key, {
fromSync: true,
actionSource: 'syncMessage',
});
} else if (isInstall) {
if (status === 'downloaded') {
window.reduxActions.stickers.installStickerPack(id, key, {
fromSync: true,
actionSource: 'syncMessage',
});
} else {
void Stickers.downloadStickerPack(id, key, {
finalStatus: 'installed',
fromSync: true,
actionSource: 'syncMessage',
});
}
}

View file

@ -11,13 +11,25 @@ import { Tabs } from '../Tabs';
export type OwnProps = {
readonly blessedPacks: ReadonlyArray<StickerPackType>;
readonly closeStickerPackPreview: () => unknown;
readonly downloadStickerPack: (packId: string, packKey: string) => unknown;
readonly downloadStickerPack: (
packId: string,
packKey: string,
options: { actionSource: 'ui' }
) => unknown;
readonly i18n: LocalizerType;
readonly installStickerPack: (packId: string, packKey: string) => unknown;
readonly installStickerPack: (
packId: string,
packKey: string,
options: { actionSource: 'ui' }
) => unknown;
readonly installedPacks: ReadonlyArray<StickerPackType>;
readonly knownPacks?: ReadonlyArray<StickerPackType>;
readonly receivedPacks: ReadonlyArray<StickerPackType>;
readonly uninstallStickerPack: (packId: string, packKey: string) => unknown;
readonly uninstallStickerPack: (
packId: string,
packKey: string,
options: { actionSource: 'ui' }
) => unknown;
};
export type Props = OwnProps;
@ -47,7 +59,7 @@ export const StickerManager = React.memo(function StickerManagerInner({
return;
}
knownPacks.forEach(pack => {
downloadStickerPack(pack.id, pack.key);
downloadStickerPack(pack.id, pack.key, { actionSource: 'ui' });
});
// When this component is created, it's initially not part of the DOM, and then it's

View file

@ -12,8 +12,16 @@ export type OwnProps = {
readonly i18n: LocalizerType;
readonly pack: StickerPackType;
readonly onClickPreview?: (sticker: StickerPackType) => unknown;
readonly installStickerPack?: (packId: string, packKey: string) => unknown;
readonly uninstallStickerPack?: (packId: string, packKey: string) => unknown;
readonly installStickerPack?: (
packId: string,
packKey: string,
options: { actionSource: 'ui' }
) => unknown;
readonly uninstallStickerPack?: (
packId: string,
packKey: string,
options: { actionSource: 'ui' }
) => unknown;
};
export type Props = OwnProps;
@ -37,7 +45,7 @@ export const StickerManagerPackRow = React.memo(
(e: React.MouseEvent) => {
e.stopPropagation();
if (installStickerPack) {
installStickerPack(id, key);
installStickerPack(id, key, { actionSource: 'ui' });
}
},
[id, installStickerPack, key]
@ -47,7 +55,7 @@ export const StickerManagerPackRow = React.memo(
(e: React.MouseEvent) => {
e.stopPropagation();
if (isBlessed && uninstallStickerPack) {
uninstallStickerPack(id, key);
uninstallStickerPack(id, key, { actionSource: 'ui' });
} else {
setUninstalling(true);
}
@ -58,7 +66,7 @@ export const StickerManagerPackRow = React.memo(
const handleConfirmUninstall = React.useCallback(() => {
clearUninstalling();
if (uninstallStickerPack) {
uninstallStickerPack(id, key);
uninstallStickerPack(id, key, { actionSource: 'ui' });
}
}, [id, key, clearUninstalling, uninstallStickerPack]);

View file

@ -19,10 +19,18 @@ export type OwnProps = {
readonly downloadStickerPack: (
packId: string,
packKey: string,
options?: { finalStatus?: 'installed' | 'downloaded' }
options: { finalStatus?: 'installed' | 'downloaded'; actionSource: 'ui' }
) => unknown;
readonly installStickerPack: (
packId: string,
packKey: string,
options: { actionSource: 'ui' }
) => unknown;
readonly uninstallStickerPack: (
packId: string,
packKey: string,
options: { actionSource: 'ui' }
) => unknown;
readonly installStickerPack: (packId: string, packKey: string) => unknown;
readonly uninstallStickerPack: (packId: string, packKey: string) => unknown;
readonly pack?: StickerPackType;
readonly i18n: LocalizerType;
};
@ -90,7 +98,7 @@ export const StickerPreviewModal = React.memo(
React.useEffect(() => {
if (pack && pack.status === 'known') {
downloadStickerPack(pack.id, pack.key);
downloadStickerPack(pack.id, pack.key, { actionSource: 'ui' });
}
if (
pack &&
@ -99,6 +107,7 @@ export const StickerPreviewModal = React.memo(
pack.attemptedStatus === 'installed')
) {
downloadStickerPack(pack.id, pack.key, {
actionSource: 'ui',
finalStatus: pack.attemptedStatus,
});
}
@ -130,10 +139,13 @@ export const StickerPreviewModal = React.memo(
if (isInstalled) {
setConfirmingUninstall(true);
} else if (pack.status === 'ephemeral') {
downloadStickerPack(pack.id, pack.key, { finalStatus: 'installed' });
downloadStickerPack(pack.id, pack.key, {
finalStatus: 'installed',
actionSource: 'ui',
});
handleClose();
} else {
installStickerPack(pack.id, pack.key);
installStickerPack(pack.id, pack.key, { actionSource: 'ui' });
handleClose();
}
}, [
@ -149,7 +161,7 @@ export const StickerPreviewModal = React.memo(
if (!pack) {
return;
}
uninstallStickerPack(pack.id, pack.key);
uninstallStickerPack(pack.id, pack.key, { actionSource: 'ui' });
setConfirmingUninstall(false);
// closeStickerPackPreview is called by <ConfirmationDialog />'s onClose
}, [uninstallStickerPack, setConfirmingUninstall, pack]);

View file

@ -409,13 +409,9 @@ async function generateManifest(
}
}
log.info(
`storageService.upload(${version}): ` +
`adding uninstalled stickerPacks=${uninstalledStickerPacks.length}`
);
const uninstalledStickerPackIds = new Set<string>();
let newlyUninstalledPacks = 0;
uninstalledStickerPacks.forEach(stickerPack => {
const storageRecord = new Proto.StorageRecord();
storageRecord.stickerPack = toStickerPackRecord(stickerPack);
@ -431,22 +427,19 @@ async function generateManifest(
});
if (isNewItem) {
postUploadUpdateFunctions.push(() => {
void DataWriter.addUninstalledStickerPack({
newlyUninstalledPacks += 1;
postUploadUpdateFunctions.push(() =>
DataWriter.addUninstalledStickerPack({
...stickerPack,
storageID,
storageVersion: version,
storageNeedsSync: false,
});
});
})
);
}
});
log.info(
`storageService.upload(${version}): ` +
`adding installed stickerPacks=${installedStickerPacks.length}`
);
let newlyInstalledPacks = 0;
installedStickerPacks.forEach(stickerPack => {
if (uninstalledStickerPackIds.has(stickerPack.id)) {
log.error(
@ -456,7 +449,7 @@ async function generateManifest(
window.reduxActions.stickers.uninstallStickerPack(
stickerPack.id,
stickerPack.key,
{ fromSync: true }
{ actionSource: 'storageService' }
);
return;
}
@ -473,17 +466,27 @@ async function generateManifest(
});
if (isNewItem) {
postUploadUpdateFunctions.push(() => {
void DataWriter.createOrUpdateStickerPack({
...stickerPack,
newlyInstalledPacks += 1;
postUploadUpdateFunctions.push(() =>
DataWriter.updateStickerPackInfo({
id: stickerPack.id,
key: stickerPack.key,
storageID,
storageVersion: version,
storageNeedsSync: false,
});
});
position: stickerPack.position,
})
);
}
});
log.info(
`storageService.upload(${version}): stickerPacks ` +
`installed=${newlyInstalledPacks}/${installedStickerPacks.length} ` +
`uninstalled=${newlyUninstalledPacks}/${uninstalledStickerPacks.length}`
);
log.info(
`storageService.upload(${version}): ` +
`adding callLinks=${callLinkDbRecords.length}`
@ -1498,10 +1501,15 @@ async function processManifest(
`storageService.process(${version}): localKey=${missingKey} was not ` +
'in remote manifest'
);
void DataWriter.createOrUpdateStickerPack({
...stickerPack,
void DataWriter.updateStickerPackInfo({
id: stickerPack.id,
key: stickerPack.key,
storageID: undefined,
storageVersion: undefined,
storageUnknownFields: undefined,
storageNeedsSync: false,
uninstalledAt: stickerPack.uninstalledAt,
});
});

View file

@ -1937,13 +1937,24 @@ export async function mergeStickerPackRecord(
`newPosition=${stickerPack.position ?? '?'}`
);
if (localStickerPack && !wasUninstalled && isUninstalled) {
assertDev(localStickerPack.key, 'Installed sticker pack has no key');
window.reduxActions.stickers.uninstallStickerPack(
localStickerPack.id,
localStickerPack.key,
{ fromStorageService: true }
);
if (!wasUninstalled && isUninstalled) {
if (localStickerPack != null) {
assertDev(localStickerPack.key, 'Installed sticker pack has no key');
window.reduxActions.stickers.uninstallStickerPack(
localStickerPack.id,
localStickerPack.key,
{
actionSource: 'storageService',
uninstalledAt: stickerPack.uninstalledAt,
}
);
} else {
strictAssert(
stickerPack.key == null && stickerPack.uninstalledAt != null,
'Created sticker pack must be already uninstalled'
);
await DataWriter.addUninstalledStickerPack(stickerPack);
}
} else if ((!localStickerPack || wasUninstalled) && !isUninstalled) {
assertDev(stickerPack.key, 'Sticker pack does not have key');
@ -1953,13 +1964,13 @@ export async function mergeStickerPackRecord(
stickerPack.id,
stickerPack.key,
{
fromStorageService: true,
actionSource: 'storageService',
}
);
} else {
void Stickers.downloadStickerPack(stickerPack.id, stickerPack.key, {
finalStatus: 'installed',
fromStorageService: true,
actionSource: 'storageService',
});
}
}

View file

@ -934,11 +934,12 @@ type WritableInterface = {
createOrUpdateStickerPack: (pack: StickerPackType) => void;
createOrUpdateStickerPacks: (packs: ReadonlyArray<StickerPackType>) => void;
// Returns previous sticker pack status
updateStickerPackStatus: (
id: string,
status: StickerPackStatusType,
options?: { timestamp: number }
) => void;
) => StickerPackStatusType | null;
updateStickerPackInfo: (info: StickerPackInfoType) => void;
createOrUpdateSticker: (sticker: StickerType) => void;
createOrUpdateStickers: (sticker: ReadonlyArray<StickerType>) => void;
@ -959,9 +960,10 @@ type WritableInterface = {
addUninstalledStickerPacks: (
pack: ReadonlyArray<UninstalledStickerPackType>
) => void;
removeUninstalledStickerPack: (packId: string) => void;
installStickerPack: (packId: string, timestamp: number) => void;
uninstallStickerPack: (packId: string, timestamp: number) => void;
// Returns `true` if sticker pack was previously uninstalled
installStickerPack: (packId: string, timestamp: number) => boolean;
// Returns `true` if sticker pack was not previously uninstalled
uninstallStickerPack: (packId: string, timestamp: number) => boolean;
clearAllErrorStickerPackAttempts: () => void;
updateEmojiUsage: (shortName: string, timeUsed?: number) => void;

View file

@ -507,7 +507,6 @@ export const DataWriter: ServerWritableInterface = {
getUnresolvedStickerPackReferences,
addUninstalledStickerPack,
addUninstalledStickerPacks,
removeUninstalledStickerPack,
installStickerPack,
uninstallStickerPack,
clearAllErrorStickerPackAttempts,
@ -5251,10 +5250,6 @@ function createOrUpdateStickerPack(
status,
stickerCount,
title,
storageID,
storageVersion,
storageUnknownFields,
storageNeedsSync,
} = pack;
if (!id) {
throw new Error(
@ -5262,21 +5257,6 @@ function createOrUpdateStickerPack(
);
}
let { position } = pack;
// Assign default position
if (!isNumber(position)) {
position = db
.prepare<EmptyQuery>(
`
SELECT IFNULL(MAX(position) + 1, 0)
FROM sticker_packs
`
)
.pluck()
.get();
}
const row = db
.prepare<Query>(
`
@ -5299,11 +5279,6 @@ function createOrUpdateStickerPack(
status,
stickerCount,
title,
position: position ?? 0,
storageID: storageID ?? null,
storageVersion: storageVersion ?? null,
storageUnknownFields: storageUnknownFields ?? null,
storageNeedsSync: storageNeedsSync ? 1 : 0,
};
if (row) {
@ -5320,12 +5295,7 @@ function createOrUpdateStickerPack(
lastUsed = $lastUsed,
status = $status,
stickerCount = $stickerCount,
title = $title,
position = $position,
storageID = $storageID,
storageVersion = $storageVersion,
storageUnknownFields = $storageUnknownFields,
storageNeedsSync = $storageNeedsSync
title = $title
WHERE id = $id;
`
).run(payload);
@ -5333,6 +5303,21 @@ function createOrUpdateStickerPack(
return;
}
let { position } = pack;
// Assign default position when inserting a row
if (!isNumber(position)) {
position = db
.prepare<EmptyQuery>(
`
SELECT IFNULL(MAX(position) + 1, 0)
FROM sticker_packs
`
)
.pluck()
.get();
}
db.prepare<Query>(
`
INSERT INTO sticker_packs (
@ -5348,11 +5333,7 @@ function createOrUpdateStickerPack(
status,
stickerCount,
title,
position,
storageID,
storageVersion,
storageUnknownFields,
storageNeedsSync
position
) values (
$attemptedStatus,
$author,
@ -5366,14 +5347,10 @@ function createOrUpdateStickerPack(
$status,
$stickerCount,
$title,
$position,
$storageID,
$storageVersion,
$storageUnknownFields,
$storageNeedsSync
$position
)
`
).run(payload);
).run({ ...payload, position: position ?? 0 });
}
function createOrUpdateStickerPacks(
db: WritableDB,
@ -5390,21 +5367,27 @@ function updateStickerPackStatus(
id: string,
status: StickerPackStatusType,
options?: { timestamp: number }
): void {
): StickerPackStatusType | null {
const timestamp = options ? options.timestamp || Date.now() : Date.now();
const installedAt = status === 'installed' ? timestamp : null;
db.prepare<Query>(
`
UPDATE sticker_packs
SET status = $status, installedAt = $installedAt
WHERE id = $id;
`
).run({
id,
status,
installedAt,
});
return db.transaction(() => {
const [select, selectParams] = sql`
SELECT status FROM sticker_packs WHERE id IS ${id};
`;
const oldStatus = db.prepare(select).pluck().get(selectParams);
const [update, updateParams] = sql`
UPDATE sticker_packs
SET status = ${status}, installedAt = ${installedAt}
WHERE id IS ${id}
`;
db.prepare(update).run(updateParams);
return oldStatus;
})();
}
function updateStickerPackInfo(
db: WritableDB,
@ -5415,6 +5398,7 @@ function updateStickerPackInfo(
storageUnknownFields,
storageNeedsSync,
uninstalledAt,
position,
}: StickerPackInfoType
): void {
if (uninstalledAt) {
@ -5443,7 +5427,8 @@ function updateStickerPackInfo(
storageID = $storageID,
storageVersion = $storageVersion,
storageUnknownFields = $storageUnknownFields,
storageNeedsSync = $storageNeedsSync
storageNeedsSync = $storageNeedsSync,
position = $position
WHERE id = $id;
`
).run({
@ -5452,6 +5437,7 @@ function updateStickerPackInfo(
storageVersion: storageVersion ?? null,
storageUnknownFields: storageUnknownFields ?? null,
storageNeedsSync: storageNeedsSync ? 1 : 0,
position: position || 0,
});
}
}
@ -5774,17 +5760,17 @@ function addUninstalledStickerPack(
): void {
db.prepare<Query>(
`
INSERT OR REPLACE INTO uninstalled_sticker_packs
(
id, uninstalledAt, storageID, storageVersion, storageUnknownFields,
storageNeedsSync
)
VALUES
(
$id, $uninstalledAt, $storageID, $storageVersion, $unknownFields,
$storageNeedsSync
)
`
INSERT OR REPLACE INTO uninstalled_sticker_packs
(
id, uninstalledAt, storageID, storageVersion, storageUnknownFields,
storageNeedsSync
)
VALUES
(
$id, $uninstalledAt, $storageID, $storageVersion, $unknownFields,
$storageNeedsSync
)
`
).run({
id: pack.id,
uninstalledAt: pack.uninstalledAt,
@ -5805,9 +5791,10 @@ function addUninstalledStickerPacks(
})();
}
function removeUninstalledStickerPack(db: WritableDB, packId: string): void {
db.prepare<Query>(
'DELETE FROM uninstalled_sticker_packs WHERE id IS $id'
).run({ id: packId });
const [query, params] = sql`
DELETE FROM uninstalled_sticker_packs WHERE id IS ${packId}
`;
db.prepare(query).run(params);
}
function getUninstalledStickerPacks(
db: ReadableDB
@ -5876,39 +5863,57 @@ function installStickerPack(
db: WritableDB,
packId: string,
timestamp: number
): void {
): boolean {
return db.transaction(() => {
const status = 'installed';
updateStickerPackStatus(db, packId, status, { timestamp });
removeUninstalledStickerPack(db, packId);
const oldStatus = updateStickerPackStatus(db, packId, status, {
timestamp,
});
const wasPreviouslyUninstalled = oldStatus !== 'installed';
if (wasPreviouslyUninstalled) {
const [query, params] = sql`
UPDATE sticker_packs SET
storageNeedsSync = 1
WHERE id IS ${packId};
`;
db.prepare(query).run(params);
}
return wasPreviouslyUninstalled;
})();
}
function uninstallStickerPack(
db: WritableDB,
packId: string,
timestamp: number
): void {
): boolean {
return db.transaction(() => {
const status = 'downloaded';
updateStickerPackStatus(db, packId, status);
const oldStatus = updateStickerPackStatus(db, packId, status);
db.prepare<Query>(
`
const wasPreviouslyInstalled = oldStatus === 'installed';
const [query, params] = sql`
UPDATE sticker_packs SET
storageID = NULL,
storageVersion = NULL,
storageUnknownFields = NULL,
storageNeedsSync = 0
WHERE id = $packId;
`
).run({ packId });
WHERE id = ${packId}
`;
db.prepare(query).run(params);
addUninstalledStickerPack(db, {
id: packId,
uninstalledAt: timestamp,
storageNeedsSync: true,
storageNeedsSync: wasPreviouslyInstalled,
});
return wasPreviouslyInstalled;
})();
}
function getAllStickers(db: ReadableDB): Array<StickerType> {

View file

@ -10,11 +10,12 @@ import type {
StickerPackType as StickerPackDBType,
} from '../../sql/Interface';
import { DataReader, DataWriter } from '../../sql/Client';
import type { RecentStickerType } from '../../types/Stickers';
import type { ActionSourceType, RecentStickerType } from '../../types/Stickers';
import {
downloadStickerPack as externalDownloadStickerPack,
maybeDeletePack,
} from '../../types/Stickers';
import { drop } from '../../util/drop';
import { storageServiceUploadJob } from '../../services/storage';
import { sendStickerPackSync } from '../../shims/textsecure';
import { trigger } from '../../shims/events';
@ -74,7 +75,7 @@ type StickerAddedAction = ReadonlyDeep<{
type InstallStickerPackPayloadType = ReadonlyDeep<{
packId: string;
fromSync: boolean;
actionSource: ActionSourceType;
status: 'installed';
installedAt: number;
recentStickers: Array<RecentStickerType>;
@ -93,7 +94,7 @@ type ClearInstalledStickerPackAction = ReadonlyDeep<{
type UninstallStickerPackPayloadType = ReadonlyDeep<{
packId: string;
fromSync: boolean;
actionSource: ActionSourceType;
status: 'downloaded';
installedAt?: undefined;
recentStickers: Array<RecentStickerType>;
@ -199,12 +200,21 @@ function stickerPackAdded(
function downloadStickerPack(
packId: string,
packKey: string,
options?: { finalStatus?: 'installed' | 'downloaded' }
{
finalStatus,
actionSource,
}: {
finalStatus?: 'installed' | 'downloaded';
actionSource: ActionSourceType;
}
): NoopActionType {
const { finalStatus } = options || { finalStatus: undefined };
// We're just kicking this off, since it will generate more redux events
void externalDownloadStickerPack(packId, packKey, { finalStatus });
drop(
externalDownloadStickerPack(packId, packKey, {
finalStatus,
actionSource,
})
);
return {
type: 'NOOP',
@ -215,41 +225,33 @@ function downloadStickerPack(
function installStickerPack(
packId: string,
packKey: string,
options: {
fromSync?: boolean;
fromStorageService?: boolean;
fromBackup?: boolean;
} = {}
{ actionSource }: { actionSource: ActionSourceType }
): InstallStickerPackAction {
return {
type: 'stickers/INSTALL_STICKER_PACK',
payload: doInstallStickerPack(packId, packKey, options),
payload: doInstallStickerPack(packId, packKey, { actionSource }),
};
}
async function doInstallStickerPack(
packId: string,
packKey: string,
options: {
fromSync?: boolean;
fromStorageService?: boolean;
fromBackup?: boolean;
} = {}
{ actionSource }: { actionSource: ActionSourceType }
): Promise<InstallStickerPackPayloadType> {
const {
fromSync = false,
fromStorageService = false,
fromBackup = false,
} = options;
const timestamp = Date.now();
await DataWriter.installStickerPack(packId, timestamp);
const changed = await DataWriter.installStickerPack(packId, timestamp);
if (!fromSync && !fromStorageService && !fromBackup) {
if (actionSource === 'ui') {
// Kick this off, but don't wait for it
void sendStickerPackSync(packId, packKey, true);
drop(sendStickerPackSync(packId, packKey, true));
}
if (!fromStorageService && !fromBackup) {
if (
// Don't cause storageService loop
actionSource !== 'storageService' &&
// Stickers downloaded on startup should already be synced
actionSource !== 'startup' &&
changed
) {
storageServiceUploadJob({ reason: 'doInstallServicePack' });
}
@ -257,7 +259,7 @@ async function doInstallStickerPack(
return {
packId,
fromSync,
actionSource,
status: 'installed',
installedAt: timestamp,
recentStickers: recentStickers.map(item => ({
@ -269,32 +271,44 @@ async function doInstallStickerPack(
function uninstallStickerPack(
packId: string,
packKey: string,
options: { fromSync?: boolean; fromStorageService?: boolean } = {}
{
actionSource,
uninstalledAt,
}: { actionSource: ActionSourceType; uninstalledAt?: number }
): UninstallStickerPackAction {
return {
type: 'stickers/UNINSTALL_STICKER_PACK',
payload: doUninstallStickerPack(packId, packKey, options),
payload: doUninstallStickerPack(packId, packKey, {
actionSource,
uninstalledAt,
}),
};
}
async function doUninstallStickerPack(
packId: string,
packKey: string,
options: { fromSync?: boolean; fromStorageService?: boolean } = {}
{
actionSource,
uninstalledAt = Date.now(),
}: { actionSource: ActionSourceType; uninstalledAt?: number }
): Promise<UninstallStickerPackPayloadType> {
const { fromSync = false, fromStorageService = false } = options;
const timestamp = Date.now();
await DataWriter.uninstallStickerPack(packId, timestamp);
const changed = await DataWriter.uninstallStickerPack(packId, uninstalledAt);
// If there are no more references, it should be removed
await maybeDeletePack(packId);
if (!fromSync && !fromStorageService) {
if (actionSource === 'ui') {
// Kick this off, but don't wait for it
void sendStickerPackSync(packId, packKey, false);
drop(sendStickerPackSync(packId, packKey, false));
}
if (!fromStorageService) {
if (
// Don't cause storageService loop
actionSource !== 'storageService' &&
// Stickers downloaded on startup should already be synced
actionSource !== 'startup' &&
changed
) {
storageServiceUploadJob({ reason: 'doUninstallStickerPack' });
}
@ -302,7 +316,7 @@ async function doUninstallStickerPack(
return {
packId,
fromSync,
actionSource,
status: 'downloaded',
installedAt: undefined,
recentStickers: recentStickers.map(item => ({
@ -438,7 +452,8 @@ export function reducer(
action.type === 'stickers/UNINSTALL_STICKER_PACK_FULFILLED'
) {
const { payload } = action;
const { fromSync, installedAt, packId, status, recentStickers } = payload;
const { actionSource, installedAt, packId, status, recentStickers } =
payload;
const { packs } = state;
const existingPack = packs[packId];
@ -453,7 +468,7 @@ export function reducer(
}
const isBlessed = state.blessedPacks[packId];
const installedPack = !fromSync && !isBlessed ? packId : null;
const installedPack = actionSource === 'ui' && !isBlessed ? packId : null;
return {
...state,

View file

@ -32,6 +32,12 @@ import { isNotNil } from '../util/isNotNil';
import { encryptLegacyAttachment } from '../util/encryptLegacyAttachment';
import { AttachmentDisposition } from '../util/getLocalAttachmentUrl';
export type ActionSourceType =
| 'startup'
| 'syncMessage'
| 'storageService'
| 'ui';
export type StickerType = {
packId: string;
stickerId: number;
@ -265,6 +271,7 @@ export function downloadQueuedPacks(): void {
downloadStickerPack(id, key, {
finalStatus: status,
suppressError: true,
actionSource: 'startup',
})
);
}
@ -634,9 +641,7 @@ export async function downloadEphemeralPack(
}
export type DownloadStickerPackOptions = Readonly<{
fromSync?: boolean;
fromStorageService?: boolean;
fromBackup?: boolean;
actionSource: ActionSourceType;
finalStatus?: StickerPackStatusType;
suppressError?: boolean;
}>;
@ -644,7 +649,7 @@ export type DownloadStickerPackOptions = Readonly<{
export async function downloadStickerPack(
packId: string,
packKey: string,
options: DownloadStickerPackOptions = {}
options: DownloadStickerPackOptions
): Promise<void> {
// This will ensure that only one download process is in progress at any given time
return downloadQueue.add(async () => {
@ -664,9 +669,7 @@ async function doDownloadStickerPack(
packKey: string,
{
finalStatus = 'downloaded',
fromSync = false,
fromStorageService = false,
fromBackup = false,
actionSource,
suppressError = false,
}: DownloadStickerPackOptions
): Promise<void> {
@ -788,9 +791,11 @@ async function doDownloadStickerPack(
status: 'pending',
createdAt: Date.now(),
stickers: {},
storageNeedsSync: !fromStorageService && !fromBackup,
title: proto.title ?? '',
author: proto.author ?? '',
// Redux handles these
storageNeedsSync: false,
};
await DataWriter.createOrUpdateStickerPack(pack);
stickerPackAdded(pack);
@ -865,9 +870,7 @@ async function doDownloadStickerPack(
// No-op
} else if (finalStatus === 'installed') {
await installStickerPack(packId, packKey, {
fromSync,
fromStorageService,
fromBackup,
actionSource,
});
} else {
// Mark the pack as complete

View file

@ -704,6 +704,7 @@ export function createIPCEvents(
installStickerPack: async (packId, key) => {
void Stickers.downloadStickerPack(packId, key, {
finalStatus: 'installed',
actionSource: 'ui',
});
},