Import/export sticker packs

Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
This commit is contained in:
automated-signal 2024-06-12 17:57:27 -05:00 committed by GitHub
parent d426109734
commit a0fb131294
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 62 additions and 15 deletions

View file

@ -1043,17 +1043,8 @@ message GroupExpirationTimerUpdate {
message StickerPack { message StickerPack {
bytes packId = 1; bytes packId = 1;
bytes packKey = 2; bytes packKey = 2;
string title = 3;
string author = 4;
repeated StickerPackSticker stickers = 5; // First one should be cover sticker.
} }
message StickerPackSticker {
string emoji = 1;
uint32 id = 2;
}
message ChatStyle { message ChatStyle {
message Gradient { message Gradient {
uint32 angle = 1; // degrees uint32 angle = 1; // degrees

View file

@ -212,6 +212,7 @@ export class BackupExportStream extends Readable {
distributionLists: 0, distributionLists: 0,
messages: 0, messages: 0,
skippedMessages: 0, skippedMessages: 0,
stickerPacks: 0,
}; };
for (const { attributes } of window.ConversationController.getAll()) { for (const { attributes } of window.ConversationController.getAll()) {
@ -284,6 +285,21 @@ export class BackupExportStream extends Readable {
stats.distributionLists += 1; stats.distributionLists += 1;
} }
const stickerPacks = await Data.getInstalledStickerPacks();
for (const { id, key } of stickerPacks) {
this.pushFrame({
stickerPack: {
packId: Bytes.fromHex(id),
packKey: Bytes.fromBase64(key),
},
});
// eslint-disable-next-line no-await-in-loop
await this.flush();
stats.stickerPacks += 1;
}
const pinnedConversationIds = const pinnedConversationIds =
window.storage.get('pinnedConversationIds') || []; window.storage.get('pinnedConversationIds') || [];

View file

@ -26,6 +26,7 @@ import {
import { import {
STICKERPACK_ID_BYTE_LEN, STICKERPACK_ID_BYTE_LEN,
STICKERPACK_KEY_BYTE_LEN, STICKERPACK_KEY_BYTE_LEN,
downloadStickerPack,
} from '../../types/Stickers'; } from '../../types/Stickers';
import type { import type {
ConversationAttributesType, ConversationAttributesType,
@ -386,6 +387,8 @@ export class BackupImportStream extends Writable {
} }
await this.fromChatItem(frame.chatItem, { aboutMe }); await this.fromChatItem(frame.chatItem, { aboutMe });
} else if (frame.stickerPack) {
await this.fromStickerPack(frame.stickerPack);
} else { } else {
log.warn(`${this.logId}: unsupported frame item ${frame.item}`); log.warn(`${this.logId}: unsupported frame item ${frame.item}`);
} }
@ -2311,4 +2314,26 @@ export class BackupImportStream extends Writable {
throw new Error('Not implemented'); throw new Error('Not implemented');
} }
} }
private async fromStickerPack({
packId: id,
packKey: key,
}: Backups.IStickerPack): Promise<void> {
strictAssert(
id?.length === STICKERPACK_ID_BYTE_LEN,
'Sticker pack must have a valid pack id'
);
const logId = `fromStickerPack(${Bytes.toHex(id).slice(-2)})`;
strictAssert(
key?.length === STICKERPACK_KEY_BYTE_LEN,
`${logId}: must have a valid pack key`
);
drop(
downloadStickerPack(Bytes.toHex(id), Bytes.toBase64(key), {
fromBackup: true,
})
);
}
} }

View file

@ -214,7 +214,11 @@ function downloadStickerPack(
function installStickerPack( function installStickerPack(
packId: string, packId: string,
packKey: string, packKey: string,
options: { fromSync?: boolean; fromStorageService?: boolean } = {} options: {
fromSync?: boolean;
fromStorageService?: boolean;
fromBackup?: boolean;
} = {}
): InstallStickerPackAction { ): InstallStickerPackAction {
return { return {
type: 'stickers/INSTALL_STICKER_PACK', type: 'stickers/INSTALL_STICKER_PACK',
@ -224,19 +228,27 @@ function installStickerPack(
async function doInstallStickerPack( async function doInstallStickerPack(
packId: string, packId: string,
packKey: string, packKey: string,
options: { fromSync?: boolean; fromStorageService?: boolean } = {} options: {
fromSync?: boolean;
fromStorageService?: boolean;
fromBackup?: boolean;
} = {}
): Promise<InstallStickerPackPayloadType> { ): Promise<InstallStickerPackPayloadType> {
const { fromSync = false, fromStorageService = false } = options; const {
fromSync = false,
fromStorageService = false,
fromBackup = false,
} = options;
const timestamp = Date.now(); const timestamp = Date.now();
await dataInterface.installStickerPack(packId, timestamp); await dataInterface.installStickerPack(packId, timestamp);
if (!fromSync && !fromStorageService) { if (!fromSync && !fromStorageService && !fromBackup) {
// Kick this off, but don't wait for it // Kick this off, but don't wait for it
void sendStickerPackSync(packId, packKey, true); void sendStickerPackSync(packId, packKey, true);
} }
if (!fromStorageService) { if (!fromStorageService && !fromBackup) {
storageServiceUploadJob(); storageServiceUploadJob();
} }

View file

@ -552,6 +552,7 @@ export type DownloadStickerPackOptions = Readonly<{
messageId?: string; messageId?: string;
fromSync?: boolean; fromSync?: boolean;
fromStorageService?: boolean; fromStorageService?: boolean;
fromBackup?: boolean;
finalStatus?: StickerPackStatusType; finalStatus?: StickerPackStatusType;
suppressError?: boolean; suppressError?: boolean;
}>; }>;
@ -582,6 +583,7 @@ async function doDownloadStickerPack(
messageId, messageId,
fromSync = false, fromSync = false,
fromStorageService = false, fromStorageService = false,
fromBackup = false,
suppressError = false, suppressError = false,
}: DownloadStickerPackOptions }: DownloadStickerPackOptions
): Promise<void> { ): Promise<void> {
@ -703,7 +705,7 @@ async function doDownloadStickerPack(
status: 'pending', status: 'pending',
createdAt: Date.now(), createdAt: Date.now(),
stickers: {}, stickers: {},
storageNeedsSync: !fromStorageService, storageNeedsSync: !fromStorageService && !fromBackup,
title: proto.title ?? '', title: proto.title ?? '',
author: proto.author ?? '', author: proto.author ?? '',
}; };
@ -788,6 +790,7 @@ async function doDownloadStickerPack(
await installStickerPack(packId, packKey, { await installStickerPack(packId, packKey, {
fromSync, fromSync,
fromStorageService, fromStorageService,
fromBackup,
}); });
} else { } else {
// Mark the pack as complete // Mark the pack as complete