Refactor sticker sync logic
This commit is contained in:
parent
ce6ae78230
commit
9ac46b8e8a
11 changed files with 264 additions and 187 deletions
|
@ -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',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -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',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
165
ts/sql/Server.ts
165
ts/sql/Server.ts
|
@ -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> {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -704,6 +704,7 @@ export function createIPCEvents(
|
|||
installStickerPack: async (packId, key) => {
|
||||
void Stickers.downloadStickerPack(packId, key, {
|
||||
finalStatus: 'installed',
|
||||
actionSource: 'ui',
|
||||
});
|
||||
},
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue