diff --git a/src/components/sidebarLeft/tabs/privacyAndSecurity.ts b/src/components/sidebarLeft/tabs/privacyAndSecurity.ts index a784d65c..1164eec2 100644 --- a/src/components/sidebarLeft/tabs/privacyAndSecurity.ts +++ b/src/components/sidebarLeft/tabs/privacyAndSecurity.ts @@ -31,6 +31,7 @@ import CheckboxField from "../../checkboxField"; import PopupPeer from "../../popups/peer"; import appDraftsManager from "../../../lib/appManagers/appDraftsManager"; import Button from "../../button"; +import toggleDisability from "../../../helpers/dom/toggleDisability"; export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable { private activeSessionsRow: Row; @@ -232,6 +233,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable { const promises: Promise[] = []; { const section = new SettingSection({name: 'Privacy.SensitiveContent'}); + section.container.classList.add('hide'); promises.push(apiManager.invokeApi('account.getContentSettings').then(settings => { if(!settings.pFlags.sensitive_can_change) { @@ -247,7 +249,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable { }); section.content.append(sensitiveRow.container); - + section.container.classList.remove('hide'); this.eventListener.addEventListener('destroy', () => { const _enabled = sensitiveRow.checkboxField.checked; @@ -273,7 +275,10 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable { buttons: [{ langKey: 'Delete', callback: () => { - appDraftsManager.clearAllDrafts(); + const toggle = toggleDisability([deleteButton], true); + appDraftsManager.clearAllDrafts().then(() => { + toggle(); + }); }, isDanger: true, }], diff --git a/src/helpers/context.ts b/src/helpers/context.ts index b41bdbc4..255843f5 100644 --- a/src/helpers/context.ts +++ b/src/helpers/context.ts @@ -10,6 +10,12 @@ export const isWorker = isWebWorker || isServiceWorker; // в SW может быть сразу две переменных TRUE, поэтому проверяю по последней +export const getWindowClients = () => { + return (self as any as ServiceWorkerGlobalScope) + .clients + .matchAll({ includeUncontrolled: false, type: 'window' }); +}; + const notifyServiceWorker = (all: boolean, ...args: any[]) => { (self as any as ServiceWorkerGlobalScope) .clients diff --git a/src/lib/mtproto/mtprotoworker.ts b/src/lib/mtproto/mtprotoworker.ts index 633c86c1..79cf9bb9 100644 --- a/src/lib/mtproto/mtprotoworker.ts +++ b/src/lib/mtproto/mtprotoworker.ts @@ -54,7 +54,7 @@ export interface ToggleStorageTask extends WorkerTaskVoidTemplate { export class ApiManagerProxy extends CryptoWorkerMethods { public worker: /* Window */Worker; public postMessage: (...args: any[]) => void; - public postSWMessage: (...args: any[]) => void = () => {}; + //public postSWMessage: (...args: any[]) => void = () => {}; private afterMessageIdTemp = 0; private taskId = 0; @@ -229,7 +229,7 @@ export class ApiManagerProxy extends CryptoWorkerMethods { this.log('SW statechange', e); }); - this.postSWMessage = worker.controller.postMessage.bind(worker.controller); + //this.postSWMessage = worker.controller.postMessage.bind(worker.controller); /// #if MTPROTO_SW const controller = worker.controller || registration.installing || registration.waiting || registration.active; @@ -292,6 +292,12 @@ export class ApiManagerProxy extends CryptoWorkerMethods { }); } + public postSWMessage(message: any) { + if(navigator.serviceWorker.controller) { + navigator.serviceWorker.controller.postMessage(message); + } + } + private onWorkerFirstMessage(worker: any) { if(!this.worker) { this.worker = worker; diff --git a/src/lib/mtproto/webPushApiManager.ts b/src/lib/mtproto/webPushApiManager.ts index c1feeb62..8ee4dbee 100644 --- a/src/lib/mtproto/webPushApiManager.ts +++ b/src/lib/mtproto/webPushApiManager.ts @@ -181,9 +181,7 @@ export class WebPushApiManager { } }; - if(navigator.serviceWorker.controller) { - navigator.serviceWorker.controller.postMessage(task); - } + apiManager.postSWMessage(task); this.isAliveTO = setTimeout(this.isAliveNotify, 10000); } @@ -199,10 +197,8 @@ export class WebPushApiManager { return; } - if(navigator.serviceWorker.controller) { - const task: ServiceWorkerNotificationsClearTask = {type: 'notifications_clear'}; - navigator.serviceWorker.controller.postMessage(task); - } + const task: ServiceWorkerNotificationsClearTask = {type: 'notifications_clear'}; + apiManager.postSWMessage(task); } public setUpServiceWorkerChannel() { diff --git a/src/lib/serviceWorker/index.service.ts b/src/lib/serviceWorker/index.service.ts index 7bb31f58..dc760fe7 100644 --- a/src/lib/serviceWorker/index.service.ts +++ b/src/lib/serviceWorker/index.service.ts @@ -22,7 +22,7 @@ import CacheStorageController from '../cacheStorage'; export const log = logger('SW', LogTypes.Error | LogTypes.Debug | LogTypes.Log | LogTypes.Warn); const ctx = self as any as ServiceWorkerGlobalScope; -export const deferredPromises: {[taskId: string]: CancellablePromise} = {}; +export const deferredPromises: Map}> = new Map(); export interface RequestFilePartTask extends Modify { type: 'requestFilePart', @@ -69,16 +69,23 @@ const taskListeners: { ping: (task: ServiceWorkerPingTask, event) => { onPing(task, event); }, - requestFilePart: (task: RequestFilePartTaskResponse) => { - const promise = deferredPromises[task.id]; - - if(task.error) { - promise.reject(task.error); - } else { - promise.resolve(task.payload); + requestFilePart: (task: RequestFilePartTaskResponse, e: ExtendableMessageEvent) => { + const windowClient = e.source as WindowClient; + const promises = deferredPromises.get(windowClient.id); + if(!promises) { + return; } - delete deferredPromises[task.id]; + const promise = promises[task.id]; + if(promise) { + if(task.error) { + promise.reject(task.error); + } else { + promise.resolve(task.payload); + } + + delete promises[task.id]; + } }, toggleStorage: (task: ToggleStorageTask) => { CacheStorageController.toggleStorage(task.payload); diff --git a/src/lib/serviceWorker/stream.ts b/src/lib/serviceWorker/stream.ts index 56e5be08..b918f7e2 100644 --- a/src/lib/serviceWorker/stream.ts +++ b/src/lib/serviceWorker/stream.ts @@ -6,7 +6,7 @@ import { readBlobAsUint8Array } from "../../helpers/blob"; import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise"; -import { notifySomeone } from "../../helpers/context"; +import { getWindowClients, notifySomeone } from "../../helpers/context"; import debounce from "../../helpers/schedulers/debounce"; import { isSafari } from "../../helpers/userAgent"; import { InputFileLocation, UploadFile } from "../../layer"; @@ -49,6 +49,20 @@ const clearOldChunks = () => { }; setInterval(clearOldChunks, 1800e3); +setInterval(() => { + getWindowClients().then((clients) => { + for(const [clientId, promises] of deferredPromises) { + if(!clients.find(client => client.id === clientId)) { + for(const taskId in promises) { + const promise = promises[taskId]; + promise.reject(); + } + + deferredPromises.delete(clientId); + } + } + }); +}, 120e3); type StreamRange = [number, number]; type StreamId = string; @@ -72,7 +86,7 @@ class Stream { streams.delete(this.id); }; - private requestFilePartFromWorker(alignedOffset: number, limit: number, fromPreload = false) { + private async requestFilePartFromWorker(alignedOffset: number, limit: number, fromPreload = false) { const task: Omit = { type: 'requestFilePart', payload: [this.info.dcId, this.info.location, alignedOffset, limit] @@ -81,16 +95,32 @@ class Stream { const taskId = JSON.stringify(task); (task as RequestFilePartTask).id = taskId; - let deferred = deferredPromises[taskId] as CancellablePromise; + const windowClient = await getWindowClients().then((clients) => { + if(!clients.length) { + return; + } + + return clients.find(client => deferredPromises.has(client.id)) || clients[0]; + }); + + if(!windowClient) { + throw new Error('no window'); + } + + let promises = deferredPromises.get(windowClient.id); + if(!promises) { + deferredPromises.set(windowClient.id, promises = {}); + } + + let deferred = promises[taskId] as CancellablePromise; if(deferred) { return deferred.then(uploadFile => uploadFile.bytes); } - - notifySomeone(task); - + + windowClient.postMessage(task); this.loadedOffsets.add(alignedOffset); - deferred = deferredPromises[taskId] = deferredPromise(); + deferred = promises[taskId] = deferredPromise(); const bytesPromise = deferred.then(uploadFile => uploadFile.bytes); this.saveChunkToCache(bytesPromise, alignedOffset, limit);