diff --git a/src/lib/appManagers/appManagersManager.ts b/src/lib/appManagers/appManagersManager.ts index 2ca2f175..2397bdb2 100644 --- a/src/lib/appManagers/appManagersManager.ts +++ b/src/lib/appManagers/appManagersManager.ts @@ -5,6 +5,7 @@ */ import App from '../../config/app'; +import {MOUNT_CLASS_TO} from '../../config/debug'; import callbackify from '../../helpers/callbackify'; import deferredPromise, {CancellablePromise} from '../../helpers/cancellablePromise'; import cryptoMessagePort from '../crypto/cryptoMessagePort'; @@ -53,16 +54,21 @@ export class AppManagersManager { this.cryptoPortPromise?.resolve(); }); - port.addEventListener('createProxyWorkerURLs', (blob) => { - const length = this.cryptoWorkersURLs.length; + port.addEventListener('createProxyWorkerURLs', ({originalUrl, blob}) => { + let length = this.cryptoWorkersURLs.length; + if(!length) { + this.cryptoWorkersURLs.push(originalUrl); + ++length; + } + const maxLength = App.cryptoWorkers; - if(length) { + if(length === maxLength) { return this.cryptoWorkersURLs; } const newURLs = new Array(maxLength - length).fill(undefined).map(() => URL.createObjectURL(blob)); this.cryptoWorkersURLs.push(...newURLs); - return newURLs; + return this.cryptoWorkersURLs; }); } @@ -85,4 +91,5 @@ export class AppManagersManager { } const appManagersManager = new AppManagersManager(); +MOUNT_CLASS_TO && (MOUNT_CLASS_TO.appManagersManager = appManagersManager); export default appManagersManager; diff --git a/src/lib/mtproto/mtprotoMessagePort.ts b/src/lib/mtproto/mtprotoMessagePort.ts index f1e60c7e..3c9a75b7 100644 --- a/src/lib/mtproto/mtprotoMessagePort.ts +++ b/src/lib/mtproto/mtprotoMessagePort.ts @@ -31,7 +31,7 @@ export default class MTProtoMessagePort extends S cryptoPort: (payload: void, source: MessageEventSource, event: MessageEvent) => void, createObjectURL: (blob: Blob) => string, tabState: (payload: TabState, source: MessageEventSource) => void, - createProxyWorkerURLs: (blob: Blob) => string[], + createProxyWorkerURLs: (payload: {originalUrl: string, blob: Blob}) => string[], } & MTProtoBroadcastEvent, { convertWebp: (payload: {fileName: string, bytes: Uint8Array}) => Promise, convertOpus: (payload: {fileName: string, bytes: Uint8Array}) => Promise, diff --git a/src/lib/mtproto/mtprotoworker.ts b/src/lib/mtproto/mtprotoworker.ts index f3ba26af..40c7c659 100644 --- a/src/lib/mtproto/mtprotoworker.ts +++ b/src/lib/mtproto/mtprotoworker.ts @@ -353,11 +353,11 @@ class ApiManagerProxy extends MTProtoMessagePort { originals.forEach((w) => window[w.name as any] = w as any); - const blob = await get((worker as any).url); - const urlsPromise = await this.invoke('createProxyWorkerURLs', blob); - const workers = urlsPromise.map((url) => { - return new (IS_SHARED_WORKER_SUPPORTED ? SharedWorker : Worker)(url, {type: 'module'}); - }); + const originalUrl = (worker as any).url; + + const createWorker = (url: string) => new constructor(url, {type: 'module'}); + const attachWorkerToPort = (worker: SharedWorker | Worker) => this.attachWorkerToPort(worker, cryptoMessagePort, 'crypto'); + const constructor = IS_SHARED_WORKER_SUPPORTED ? SharedWorker : Worker; // let cryptoWorkers = workers.length; cryptoMessagePort.addEventListener('port', (payload, source, event) => { @@ -375,9 +375,13 @@ class ApiManagerProxy extends MTProtoMessagePort { // }); }); - workers.forEach((worker) => { - this.attachWorkerToPort(worker, cryptoMessagePort, 'crypto'); - }); + const firstWorker = createWorker(originalUrl); + attachWorkerToPort(firstWorker); + + const blob = await get(originalUrl); + const urlsPromise = await this.invoke('createProxyWorkerURLs', {originalUrl, blob}); + const workers = urlsPromise.slice(1).map(createWorker); + workers.forEach(attachWorkerToPort); } // #if !MTPROTO_SW diff --git a/src/lib/mtproto/superMessagePort.ts b/src/lib/mtproto/superMessagePort.ts index efefef0b..1c3b0968 100644 --- a/src/lib/mtproto/superMessagePort.ts +++ b/src/lib/mtproto/superMessagePort.ts @@ -5,6 +5,7 @@ */ import DEBUG from '../../config/debug'; +import tabId from '../../config/tabId'; import ctx from '../../environment/ctx'; import indexOfAndSplice from '../../helpers/array/indexOfAndSplice'; import {IS_WORKER} from '../../helpers/context'; @@ -127,7 +128,9 @@ export default class SuperMessagePort< protected onPortDisconnect: (source: MessageEventSource) => void; // protected onPortConnect: (source: MessageEventSource) => void; - constructor(logSuffix?: string) { + protected resolveLocks: Map void>; + + constructor(protected logSuffix?: string) { super(false); this.listenPorts = []; @@ -138,19 +141,7 @@ export default class SuperMessagePort< this.pending = new Map(); this.log = logger('MP' + (logSuffix ? '-' + logSuffix : '')); this.debug = DEBUG; - - if(typeof(window) !== 'undefined') { - if('locks' in navigator) { - const id = 'lock-' + Date.now() + (Math.random() * 0xFFFF | 0); - navigator.locks.request(id, () => new Promise(() => {})); - this.pushTask(this.createTask('lock', id)); - } else { - window.addEventListener('beforeunload', () => { - const task = this.createTask('close', undefined); - this.postMessage(undefined, task); - }); - } - } + this.resolveLocks = new Map(); this.processTaskMap = { result: this.processResultTask, @@ -193,6 +184,22 @@ export default class SuperMessagePort< // const task = this.createTask('open', undefined); // this.postMessage(port, task); + if(typeof(window) !== 'undefined') { + if('locks' in navigator) { + const id = ['lock', tabId, this.logSuffix || '', Math.random() * 0x7FFFFFFF | 0].join('-'); + this.log.warn('created lock', id); + const promise = new Promise((resolve) => this.resolveLocks.set(port, resolve)) + .then(() => this.resolveLocks.delete(port)); + navigator.locks.request(id, () => promise); + this.pushTask(this.createTask('lock', id)); + } else { + window.addEventListener('beforeunload', () => { + const task = this.createTask('close', undefined); + this.postMessage(undefined, task); + }); + } + } + this.releasePending(); } @@ -244,6 +251,9 @@ export default class SuperMessagePort< this.onPortDisconnect?.(port as any); + const resolveLock = this.resolveLocks.get(port as SendPort); + resolveLock?.(); + const error = makeError('PORT_DISCONNECTED'); for(const id in this.awaiting) { const task = this.awaiting[id]; diff --git a/src/lib/serviceWorker/index.service.ts b/src/lib/serviceWorker/index.service.ts index 9d49cfca..0ef52d60 100644 --- a/src/lib/serviceWorker/index.service.ts +++ b/src/lib/serviceWorker/index.service.ts @@ -48,6 +48,7 @@ const onWindowConnected = (source: WindowClient) => { return; } + log('windows', Array.from(connectedWindows)); sendMessagePortIfNeeded(source); connectedWindows.add(source.id); }; @@ -85,8 +86,10 @@ getWindowClients().then((windowClients) => { const connectedWindows: Set = new Set(); (self as any).connectedWindows = connectedWindows; listenMessagePort(serviceMessagePort, undefined, (source) => { + log('something has disconnected', source); const isWindowClient = source instanceof WindowClient; if(!isWindowClient || !connectedWindows.has(source.id)) { + log.warn('it is not a window'); return; }