Support missing session storage (Fix Firefox Private Mode)

This commit is contained in:
Alexander Zinchuk 2021-04-29 18:24:10 +03:00
parent bedd3d2119
commit 426ca7549b
5 changed files with 84 additions and 48 deletions

View File

@ -3,10 +3,10 @@ const StorageSession = require('./StorageSession')
const CACHE_NAME = 'GramJs'
class CacheApiSession extends StorageSession {
async delete() {
async _delete() {
const request = new Request(this._storageKey)
const cache = await self.caches.open(CACHE_NAME)
await cache.delete(request)
return cache.delete(request)
}
async _fetchFromCache() {

View File

@ -4,7 +4,7 @@ const idb = require('idb-keyval')
const CACHE_NAME = 'GramJs'
class IdbSession extends StorageSession {
async delete() {
async _delete() {
return idb.del(`${CACHE_NAME}:${this._storageKey}`)
}

View File

@ -1,7 +1,7 @@
const StorageSession = require('./StorageSession')
class LocalStorageSession extends StorageSession {
async delete() {
async _delete() {
return localStorage.removeItem(this._storageKey)
}

View File

@ -32,7 +32,8 @@ class StorageSession extends MemorySession {
}
})
} catch (err) {
throw new Error(`Failed to retrieve or parse JSON from Cache for key ${this._storageKey}`)
console.warn('Failed to retrieve or parse session from storage')
console.warn(err)
}
}
@ -93,17 +94,34 @@ class StorageSession extends MemorySession {
sessionData.hashes[dcId] = authKey._hash
})
await this._saveToCache(JSON.stringify(sessionData))
try {
await this._saveToCache(JSON.stringify(sessionData))
} catch (err) {
console.warn('Failed to update session in storage')
console.warn(err)
}
}
async delete() {
try {
return await this._delete()
} catch (err) {
console.warn('Failed to delete session from storage')
console.warn(err)
}
}
// @abstract
async _delete() {
throw new Error('Not Implemented')
}
// @abstract
async _fetchFromCache() {
throw new Error('Not Implemented')
}
// @abstract
async _saveToCache(data) {
throw new Error('Not Implemented')
}

View File

@ -12,38 +12,44 @@ export async function fetch(cacheName: string, key: string, type: Type) {
return undefined;
}
const request = new Request(key);
const cache = await cacheApi.open(cacheName);
const response = await cache.match(request);
if (!response) {
return undefined;
}
switch (type) {
case Type.Text:
return response.text();
case Type.Blob: {
const blob = await response.blob();
// Safari does not return correct Content-Type header for webp images.
if (key.substr(0, 7) === 'sticker') {
return new Blob([blob], { type: 'image/webp' });
}
// iOS Safari fails to preserve `type` in cache
if (!blob.type) {
const contentType = response.headers.get('Content-Type');
if (contentType) {
return new Blob([blob], { type: contentType });
}
}
return blob;
}
case Type.Json:
return response.json();
default:
try {
const request = new Request(key);
const cache = await cacheApi.open(cacheName);
const response = await cache.match(request);
if (!response) {
return undefined;
}
switch (type) {
case Type.Text:
return await response.text();
case Type.Blob: {
const blob = await response.blob();
// Safari does not return correct Content-Type header for webp images.
if (key.substr(0, 7) === 'sticker') {
return new Blob([blob], { type: 'image/webp' });
}
// iOS Safari fails to preserve `type` in cache
if (!blob.type) {
const contentType = response.headers.get('Content-Type');
if (contentType) {
return new Blob([blob], { type: contentType });
}
}
return blob;
}
case Type.Json:
return await response.json();
default:
return undefined;
}
} catch (err) {
// eslint-disable-next-line no-console
console.warn(err);
return undefined;
}
}
@ -52,17 +58,29 @@ export async function save(cacheName: string, key: string, data: AnyLiteral | Bl
return undefined;
}
const cacheData = typeof data === 'string' || data instanceof Blob ? data : JSON.stringify(data);
const request = new Request(key);
const response = new Response(cacheData);
const cache = await cacheApi.open(cacheName);
return cache.put(request, response);
}
export function clear(cacheName: string) {
if (!cacheApi) {
try {
const cacheData = typeof data === 'string' || data instanceof Blob ? data : JSON.stringify(data);
const request = new Request(key);
const response = new Response(cacheData);
const cache = await cacheApi.open(cacheName);
return await cache.put(request, response);
} catch (err) {
// eslint-disable-next-line no-console
console.warn(err);
return undefined;
}
}
export async function clear(cacheName: string) {
try {
if (!cacheApi) {
return undefined;
}
return await cacheApi.delete(cacheName);
} catch (err) {
// eslint-disable-next-line no-console
console.warn(err);
return undefined;
}
return cacheApi.delete(cacheName);
}