Fixed Firefox private mode

This commit is contained in:
WolverinDEV 2020-12-05 16:19:37 +01:00
parent 28ecc39853
commit 4823ed4f76
6 changed files with 95 additions and 64 deletions

View file

@ -1,4 +1,7 @@
# Changelog: # Changelog:
* **05.12.20**
- Fixed the webclient for Firefox in incognito mode
* **04.12.20** * **04.12.20**
- Properly logging channel creations, deletions, shows and hides - Properly logging channel creations, deletions, shows and hides
- Fixed missing collapsed arrow update after channel move - Fixed missing collapsed arrow update after channel move

View file

@ -70,7 +70,6 @@ class RetryTimeCalculator {
this.retryCount++; this.retryCount++;
const time = this.currentTime; const time = this.currentTime;
this.currentTime = Math.min(this.currentTime + this.increment, this.maxTime); this.currentTime = Math.min(this.currentTime + this.increment, this.maxTime);
console.error(time + " - " + this.retryCount);
return time; return time;
} }

View file

@ -1,4 +1,5 @@
import {tr} from "../i18n/localize"; import {tr} from "../i18n/localize";
import {LogCategory, logDebug} from "tc-shared/log";
export enum ImageType { export enum ImageType {
UNKNOWN, UNKNOWN,
@ -56,51 +57,84 @@ export function responseImageType(encoded_data: string | ArrayBuffer, base64_enc
return ImageType.UNKNOWN; return ImageType.UNKNOWN;
} }
export type ImageCacheState = {
state: "loaded",
instance: Cache
} | {
state: "errored",
reason: string
} | {
state: "unloaded"
}
export class ImageCache { export class ImageCache {
readonly cache_name: string; readonly cacheName: string;
private _cache_category: Cache; private state: ImageCacheState;
constructor(name: string) { private constructor(name: string) {
this.cache_name = name; this.cacheName = name;
this.state = { state: "unloaded" };
} }
setupped() : boolean { return !!this._cache_category; } public static async load(cacheName: string) : Promise<ImageCache> {
const cache = new ImageCache(cacheName);
async reset() { return cache;
if(!window.caches) }
private async initialize() {
if(!window.caches) {
this.state = { "state": "errored", reason: tr("Caches are not enabled by the user") };
return; return;
}
try { try {
await caches.delete(this.cache_name); const instance = await window.caches.open(this.cacheName);
this.state = { state: "loaded", instance: instance };
} catch (error) {
logDebug(LogCategory.GENERAL, tr("Failed to open image cache %s: %o"), this.cacheName, error);
this.state = { "state": "errored", reason: tr("Failed to open the cache") };
}
}
private getCacheInstance() : Cache | undefined {
return this.state.state === "loaded" ? this.state.instance : undefined;
}
isPersistent() {
return this.state.state === "loaded";
}
async reset() {
if(!window.caches) {
/* Caches are disabled by the user */
return;
}
try {
await caches.delete(this.cacheName);
} catch(error) { } catch(error) {
throw "Failed to delete cache: " + error; throw "Failed to delete cache: " + error;
} }
try { try {
await this.setup(); await this.initialize();
} catch(error) { } catch(error) {
throw "Failed to reinitialize cache!"; throw "Failed to reinitialize cache!";
} }
} }
async setup() {
if(!window.caches)
throw "Missing caches!";
if(this._cache_category)
return;
this._cache_category = await caches.open(this.cache_name);
}
async cleanup(maxAge: number) { async cleanup(maxAge: number) {
/* FIXME: TODO */ /* FIXME: TODO */
} }
async resolveCached(key: string, maxAge?: number) : Promise<Response | undefined> { async resolveCached(key: string, maxAge?: number) : Promise<Response | undefined> {
maxAge = typeof(maxAge) === "number" ? maxAge : -1; const cacheInstance = this.getCacheInstance();
if(!cacheInstance) { return undefined; }
const cachedResponse = await this._cache_category.match("https://_local_cache/cache_request_" + key); maxAge = typeof(maxAge) === "number" ? maxAge : -1;
const cachedResponse = await cacheInstance.match("https://_local_cache/cache_request_" + key);
if(!cachedResponse) if(!cachedResponse)
return undefined; return undefined;
@ -109,6 +143,9 @@ export class ImageCache {
} }
async putCache(key: string, value: Response, type?: string, headers?: {[key: string]:string}) { async putCache(key: string, value: Response, type?: string, headers?: {[key: string]:string}) {
const cacheInstance = this.getCacheInstance();
if(!cacheInstance) { return; }
const new_headers = new Headers(); const new_headers = new Headers();
for(const key of value.headers.keys()) for(const key of value.headers.keys())
new_headers.set(key, value.headers.get(key)); new_headers.set(key, value.headers.get(key));
@ -117,13 +154,16 @@ export class ImageCache {
for(const key of Object.keys(headers || {})) for(const key of Object.keys(headers || {}))
new_headers.set(key, headers[key]); new_headers.set(key, headers[key]);
await this._cache_category.put("https://_local_cache/cache_request_" + key, new Response(value.body, { await cacheInstance.put("https://_local_cache/cache_request_" + key, new Response(value.body, {
headers: new_headers headers: new_headers
})); }));
} }
async delete(key: string) { async delete(key: string) {
const flag = await this._cache_category.delete("https://_local_cache/cache_request_" + key, { const cacheInstance = this.getCacheInstance();
if(!cacheInstance) { return; }
const flag = await cacheInstance.delete("https://_local_cache/cache_request_" + key, {
ignoreVary: true, ignoreVary: true,
ignoreMethod: true, ignoreMethod: true,
ignoreSearch: true ignoreSearch: true

View file

@ -42,19 +42,14 @@ class LocalClientAvatar extends ClientAvatar {
} }
} }
let localAvatarCache: ImageCache;
export class AvatarManager extends AbstractAvatarManager { export class AvatarManager extends AbstractAvatarManager {
private static cache: ImageCache;
readonly handle: FileManager; readonly handle: FileManager;
private cachedAvatars: {[avatarId: string]: LocalClientAvatar} = {}; private cachedAvatars: {[avatarId: string]: LocalClientAvatar} = {};
constructor(handle: FileManager) { constructor(handle: FileManager) {
super(); super();
this.handle = handle; this.handle = handle;
if(!AvatarManager.cache) {
AvatarManager.cache = new ImageCache("avatars");
}
} }
destroy() { destroy() {
@ -83,11 +78,7 @@ export class AvatarManager extends AbstractAvatarManager {
/* try to lookup our cache for the avatar */ /* try to lookup our cache for the avatar */
cache_lookup: { cache_lookup: {
if(!AvatarManager.cache.setupped()) { const response = await localAvatarCache.resolveCached('avatar_' + avatar.clientAvatarId); //TODO age!
await AvatarManager.cache.setup();
}
const response = await AvatarManager.cache.resolveCached('avatar_' + avatar.clientAvatarId); //TODO age!
if(!response) { if(!response) {
break cache_lookup; break cache_lookup;
} }
@ -96,11 +87,11 @@ export class AvatarManager extends AbstractAvatarManager {
if(avatar.getAvatarHash() !== "unknown") { if(avatar.getAvatarHash() !== "unknown") {
if(cachedAvatarHash === undefined) { if(cachedAvatarHash === undefined) {
log.debug(LogCategory.FILE_TRANSFER, tr("Invalidating cached avatar for %s (Version miss match. Cached: unset, Current: %s)"), avatar.clientAvatarId, avatar.getAvatarHash()); log.debug(LogCategory.FILE_TRANSFER, tr("Invalidating cached avatar for %s (Version miss match. Cached: unset, Current: %s)"), avatar.clientAvatarId, avatar.getAvatarHash());
await AvatarManager.cache.delete('avatar_' + avatar.clientAvatarId); await localAvatarCache.delete('avatar_' + avatar.clientAvatarId);
break cache_lookup; break cache_lookup;
} else if(cachedAvatarHash !== avatar.getAvatarHash()) { } else if(cachedAvatarHash !== avatar.getAvatarHash()) {
log.debug(LogCategory.FILE_TRANSFER, tr("Invalidating cached avatar for %s (Version miss match. Cached: %s, Current: %s)"), avatar.clientAvatarId, cachedAvatarHash, avatar.getAvatarHash()); log.debug(LogCategory.FILE_TRANSFER, tr("Invalidating cached avatar for %s (Version miss match. Cached: %s, Current: %s)"), avatar.clientAvatarId, cachedAvatarHash, avatar.getAvatarHash());
await AvatarManager.cache.delete('avatar_' + avatar.clientAvatarId); await localAvatarCache.delete('avatar_' + avatar.clientAvatarId);
break cache_lookup; break cache_lookup;
} }
} else if(cachedAvatarHash) { } else if(cachedAvatarHash) {
@ -174,7 +165,7 @@ export class AvatarManager extends AbstractAvatarManager {
return; return;
} }
await AvatarManager.cache.putCache('avatar_' + avatar.clientAvatarId, transferResponse.getResponse().clone(), "image/" + media, { await localAvatarCache.putCache('avatar_' + avatar.clientAvatarId, transferResponse.getResponse().clone(), "image/" + media, {
"X-avatar-version": avatar.getAvatarHash() "X-avatar-version": avatar.getAvatarHash()
}); });
@ -231,31 +222,29 @@ export class AvatarManager extends AbstractAvatarManager {
}); });
} }
updateCache(clientAvatarId: string, clientAvatarHash: string) { async updateCache(clientAvatarId: string, clientAvatarHash: string) {
AvatarManager.cache.setup().then(async () => { const cached = this.cachedAvatars[clientAvatarId];
const cached = this.cachedAvatars[clientAvatarId]; if(cached) {
if(cached) { if(cached.getAvatarHash() === clientAvatarHash)
if(cached.getAvatarHash() === clientAvatarHash) return;
return;
log.info(LogCategory.GENERAL, tr("Deleting cached avatar for client %s. Cached version: %s; New version: %s"), cached.getAvatarHash(), clientAvatarHash); log.info(LogCategory.GENERAL, tr("Deleting cached avatar for client %s. Cached version: %s; New version: %s"), cached.getAvatarHash(), clientAvatarHash);
} }
const response = await AvatarManager.cache.resolveCached('avatar_' + clientAvatarId); const response = await localAvatarCache.resolveCached('avatar_' + clientAvatarId);
if(response) { if(response) {
let cachedAvatarHash = response.headers.has("X-avatar-version") ? response.headers.get("X-avatar-version") : undefined; let cachedAvatarHash = response.headers.has("X-avatar-version") ? response.headers.get("X-avatar-version") : undefined;
if(cachedAvatarHash !== clientAvatarHash) { if(cachedAvatarHash !== clientAvatarHash) {
await AvatarManager.cache.delete("avatar_" + clientAvatarId).catch(error => { await localAvatarCache.delete("avatar_" + clientAvatarId).catch(error => {
log.warn(LogCategory.FILE_TRANSFER, tr("Failed to delete avatar %s: %o"), clientAvatarId, error); log.warn(LogCategory.FILE_TRANSFER, tr("Failed to delete avatar %s: %o"), clientAvatarId, error);
}); });
}
} }
}
if(cached) { if(cached) {
cached.events.fire("avatar_changed", { newAvatarHash: clientAvatarHash }); cached.events.fire("avatar_changed", { newAvatarHash: clientAvatarHash });
this.executeAvatarLoad(cached); this.executeAvatarLoad(cached);
} }
});
} }
resolveAvatar(clientAvatarId: string, avatarHash?: string, cacheOnly?: boolean) : ClientAvatar { resolveAvatar(clientAvatarId: string, avatarHash?: string, cacheOnly?: boolean) : ClientAvatar {
@ -449,6 +438,7 @@ class LocalAvatarManagerFactory extends AbstractAvatarManagerFactory {
loader.register_task(Stage.LOADED, { loader.register_task(Stage.LOADED, {
name: "Avatar init", name: "Avatar init",
function: async () => { function: async () => {
localAvatarCache = await ImageCache.load("avatars");
setGlobalAvatarManagerFactory(new LocalAvatarManagerFactory()); setGlobalAvatarManagerFactory(new LocalAvatarManagerFactory());
}, },
priority: 5 priority: 5

View file

@ -346,9 +346,7 @@ loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
name: "icon init", name: "icon init",
priority: 60, priority: 60,
function: async () => { function: async () => {
localIconCache = new ImageCache("icons"); localIconCache = await ImageCache.load("icons");
await localIconCache.setup();
setIconManager(new IconManager()); setIconManager(new IconManager());
} }
}); });

View file

@ -65,8 +65,9 @@ export const ServerLogRenderer = (props: { events: Registry<ServerLogUIEvents>,
}); });
const fixScroll = () => { const fixScroll = () => {
if(!refContainer.current) if(!refContainer.current) {
return; return;
}
refContainer.current.scrollTop = scrollOffset.current === "bottom" ? refContainer.current.scrollHeight : scrollOffset.current; refContainer.current.scrollTop = scrollOffset.current === "bottom" ? refContainer.current.scrollHeight : scrollOffset.current;
}; };
@ -86,7 +87,7 @@ export const ServerLogRenderer = (props: { events: Registry<ServerLogUIEvents>,
const top = target.scrollTop; const top = target.scrollTop;
const total = target.scrollHeight - target.clientHeight; const total = target.scrollHeight - target.clientHeight;
const shouldFollow = top + 50 > total; const shouldFollow = top + 100 > total;
scrollOffset.current = shouldFollow ? "bottom" : top; scrollOffset.current = shouldFollow ? "bottom" : top;
}}> }}>