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' const CACHE_NAME = 'GramJs'
class CacheApiSession extends StorageSession { class CacheApiSession extends StorageSession {
async delete() { async _delete() {
const request = new Request(this._storageKey) const request = new Request(this._storageKey)
const cache = await self.caches.open(CACHE_NAME) const cache = await self.caches.open(CACHE_NAME)
await cache.delete(request) return cache.delete(request)
} }
async _fetchFromCache() { async _fetchFromCache() {

View File

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

View File

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

View File

@ -32,7 +32,8 @@ class StorageSession extends MemorySession {
} }
}) })
} catch (err) { } 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 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() { 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') throw new Error('Not Implemented')
} }
// @abstract
async _fetchFromCache() { async _fetchFromCache() {
throw new Error('Not Implemented') throw new Error('Not Implemented')
} }
// @abstract
async _saveToCache(data) { async _saveToCache(data) {
throw new Error('Not Implemented') throw new Error('Not Implemented')
} }

View File

@ -12,38 +12,44 @@ export async function fetch(cacheName: string, key: string, type: Type) {
return undefined; return undefined;
} }
const request = new Request(key); try {
const cache = await cacheApi.open(cacheName); const request = new Request(key);
const response = await cache.match(request); const cache = await cacheApi.open(cacheName);
if (!response) { const response = await cache.match(request);
return undefined; if (!response) {
}
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:
return undefined; 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; return undefined;
} }
const cacheData = typeof data === 'string' || data instanceof Blob ? data : JSON.stringify(data); try {
const request = new Request(key); const cacheData = typeof data === 'string' || data instanceof Blob ? data : JSON.stringify(data);
const response = new Response(cacheData); const request = new Request(key);
const cache = await cacheApi.open(cacheName); const response = new Response(cacheData);
return cache.put(request, response); const cache = await cacheApi.open(cacheName);
} return await cache.put(request, response);
} catch (err) {
export function clear(cacheName: string) { // eslint-disable-next-line no-console
if (!cacheApi) { 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 undefined;
} }
return cacheApi.delete(cacheName);
} }