[Streaming] Fix hanged chunk load promise
Hide 'Sensitive content' section if it's unavailable
This commit is contained in:
parent
1b88742d3e
commit
eff96de924
@ -31,6 +31,7 @@ import CheckboxField from "../../checkboxField";
|
|||||||
import PopupPeer from "../../popups/peer";
|
import PopupPeer from "../../popups/peer";
|
||||||
import appDraftsManager from "../../../lib/appManagers/appDraftsManager";
|
import appDraftsManager from "../../../lib/appManagers/appDraftsManager";
|
||||||
import Button from "../../button";
|
import Button from "../../button";
|
||||||
|
import toggleDisability from "../../../helpers/dom/toggleDisability";
|
||||||
|
|
||||||
export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||||
private activeSessionsRow: Row;
|
private activeSessionsRow: Row;
|
||||||
@ -232,6 +233,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||||||
const promises: Promise<any>[] = [];
|
const promises: Promise<any>[] = [];
|
||||||
{
|
{
|
||||||
const section = new SettingSection({name: 'Privacy.SensitiveContent'});
|
const section = new SettingSection({name: 'Privacy.SensitiveContent'});
|
||||||
|
section.container.classList.add('hide');
|
||||||
|
|
||||||
promises.push(apiManager.invokeApi('account.getContentSettings').then(settings => {
|
promises.push(apiManager.invokeApi('account.getContentSettings').then(settings => {
|
||||||
if(!settings.pFlags.sensitive_can_change) {
|
if(!settings.pFlags.sensitive_can_change) {
|
||||||
@ -247,7 +249,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||||||
});
|
});
|
||||||
|
|
||||||
section.content.append(sensitiveRow.container);
|
section.content.append(sensitiveRow.container);
|
||||||
|
section.container.classList.remove('hide');
|
||||||
|
|
||||||
this.eventListener.addEventListener('destroy', () => {
|
this.eventListener.addEventListener('destroy', () => {
|
||||||
const _enabled = sensitiveRow.checkboxField.checked;
|
const _enabled = sensitiveRow.checkboxField.checked;
|
||||||
@ -273,7 +275,10 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||||||
buttons: [{
|
buttons: [{
|
||||||
langKey: 'Delete',
|
langKey: 'Delete',
|
||||||
callback: () => {
|
callback: () => {
|
||||||
appDraftsManager.clearAllDrafts();
|
const toggle = toggleDisability([deleteButton], true);
|
||||||
|
appDraftsManager.clearAllDrafts().then(() => {
|
||||||
|
toggle();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
isDanger: true,
|
isDanger: true,
|
||||||
}],
|
}],
|
||||||
|
@ -10,6 +10,12 @@ export const isWorker = isWebWorker || isServiceWorker;
|
|||||||
|
|
||||||
// в SW может быть сразу две переменных TRUE, поэтому проверяю по последней
|
// в SW может быть сразу две переменных TRUE, поэтому проверяю по последней
|
||||||
|
|
||||||
|
export const getWindowClients = () => {
|
||||||
|
return (self as any as ServiceWorkerGlobalScope)
|
||||||
|
.clients
|
||||||
|
.matchAll({ includeUncontrolled: false, type: 'window' });
|
||||||
|
};
|
||||||
|
|
||||||
const notifyServiceWorker = (all: boolean, ...args: any[]) => {
|
const notifyServiceWorker = (all: boolean, ...args: any[]) => {
|
||||||
(self as any as ServiceWorkerGlobalScope)
|
(self as any as ServiceWorkerGlobalScope)
|
||||||
.clients
|
.clients
|
||||||
|
@ -54,7 +54,7 @@ export interface ToggleStorageTask extends WorkerTaskVoidTemplate {
|
|||||||
export class ApiManagerProxy extends CryptoWorkerMethods {
|
export class ApiManagerProxy extends CryptoWorkerMethods {
|
||||||
public worker: /* Window */Worker;
|
public worker: /* Window */Worker;
|
||||||
public postMessage: (...args: any[]) => void;
|
public postMessage: (...args: any[]) => void;
|
||||||
public postSWMessage: (...args: any[]) => void = () => {};
|
//public postSWMessage: (...args: any[]) => void = () => {};
|
||||||
private afterMessageIdTemp = 0;
|
private afterMessageIdTemp = 0;
|
||||||
|
|
||||||
private taskId = 0;
|
private taskId = 0;
|
||||||
@ -229,7 +229,7 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
|
|||||||
this.log('SW statechange', e);
|
this.log('SW statechange', e);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.postSWMessage = worker.controller.postMessage.bind(worker.controller);
|
//this.postSWMessage = worker.controller.postMessage.bind(worker.controller);
|
||||||
|
|
||||||
/// #if MTPROTO_SW
|
/// #if MTPROTO_SW
|
||||||
const controller = worker.controller || registration.installing || registration.waiting || registration.active;
|
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) {
|
private onWorkerFirstMessage(worker: any) {
|
||||||
if(!this.worker) {
|
if(!this.worker) {
|
||||||
this.worker = worker;
|
this.worker = worker;
|
||||||
|
@ -181,9 +181,7 @@ export class WebPushApiManager {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if(navigator.serviceWorker.controller) {
|
apiManager.postSWMessage(task);
|
||||||
navigator.serviceWorker.controller.postMessage(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isAliveTO = setTimeout(this.isAliveNotify, 10000);
|
this.isAliveTO = setTimeout(this.isAliveNotify, 10000);
|
||||||
}
|
}
|
||||||
@ -199,10 +197,8 @@ export class WebPushApiManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(navigator.serviceWorker.controller) {
|
const task: ServiceWorkerNotificationsClearTask = {type: 'notifications_clear'};
|
||||||
const task: ServiceWorkerNotificationsClearTask = {type: 'notifications_clear'};
|
apiManager.postSWMessage(task);
|
||||||
navigator.serviceWorker.controller.postMessage(task);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public setUpServiceWorkerChannel() {
|
public setUpServiceWorkerChannel() {
|
||||||
|
@ -22,7 +22,7 @@ import CacheStorageController from '../cacheStorage';
|
|||||||
|
|
||||||
export const log = logger('SW', LogTypes.Error | LogTypes.Debug | LogTypes.Log | LogTypes.Warn);
|
export const log = logger('SW', LogTypes.Error | LogTypes.Debug | LogTypes.Log | LogTypes.Warn);
|
||||||
const ctx = self as any as ServiceWorkerGlobalScope;
|
const ctx = self as any as ServiceWorkerGlobalScope;
|
||||||
export const deferredPromises: {[taskId: string]: CancellablePromise<any>} = {};
|
export const deferredPromises: Map<WindowClient['id'], {[taskId: string]: CancellablePromise<any>}> = new Map();
|
||||||
|
|
||||||
export interface RequestFilePartTask extends Modify<WorkerTaskTemplate, {id: string}> {
|
export interface RequestFilePartTask extends Modify<WorkerTaskTemplate, {id: string}> {
|
||||||
type: 'requestFilePart',
|
type: 'requestFilePart',
|
||||||
@ -69,16 +69,23 @@ const taskListeners: {
|
|||||||
ping: (task: ServiceWorkerPingTask, event) => {
|
ping: (task: ServiceWorkerPingTask, event) => {
|
||||||
onPing(task, event);
|
onPing(task, event);
|
||||||
},
|
},
|
||||||
requestFilePart: (task: RequestFilePartTaskResponse) => {
|
requestFilePart: (task: RequestFilePartTaskResponse, e: ExtendableMessageEvent) => {
|
||||||
const promise = deferredPromises[task.id];
|
const windowClient = e.source as WindowClient;
|
||||||
|
const promises = deferredPromises.get(windowClient.id);
|
||||||
if(task.error) {
|
if(!promises) {
|
||||||
promise.reject(task.error);
|
return;
|
||||||
} else {
|
|
||||||
promise.resolve(task.payload);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) => {
|
toggleStorage: (task: ToggleStorageTask) => {
|
||||||
CacheStorageController.toggleStorage(task.payload);
|
CacheStorageController.toggleStorage(task.payload);
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import { readBlobAsUint8Array } from "../../helpers/blob";
|
import { readBlobAsUint8Array } from "../../helpers/blob";
|
||||||
import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise";
|
import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise";
|
||||||
import { notifySomeone } from "../../helpers/context";
|
import { getWindowClients, notifySomeone } from "../../helpers/context";
|
||||||
import debounce from "../../helpers/schedulers/debounce";
|
import debounce from "../../helpers/schedulers/debounce";
|
||||||
import { isSafari } from "../../helpers/userAgent";
|
import { isSafari } from "../../helpers/userAgent";
|
||||||
import { InputFileLocation, UploadFile } from "../../layer";
|
import { InputFileLocation, UploadFile } from "../../layer";
|
||||||
@ -49,6 +49,20 @@ const clearOldChunks = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
setInterval(clearOldChunks, 1800e3);
|
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 StreamRange = [number, number];
|
||||||
type StreamId = string;
|
type StreamId = string;
|
||||||
@ -72,7 +86,7 @@ class Stream {
|
|||||||
streams.delete(this.id);
|
streams.delete(this.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
private requestFilePartFromWorker(alignedOffset: number, limit: number, fromPreload = false) {
|
private async requestFilePartFromWorker(alignedOffset: number, limit: number, fromPreload = false) {
|
||||||
const task: Omit<RequestFilePartTask, 'id'> = {
|
const task: Omit<RequestFilePartTask, 'id'> = {
|
||||||
type: 'requestFilePart',
|
type: 'requestFilePart',
|
||||||
payload: [this.info.dcId, this.info.location, alignedOffset, limit]
|
payload: [this.info.dcId, this.info.location, alignedOffset, limit]
|
||||||
@ -81,16 +95,32 @@ class Stream {
|
|||||||
const taskId = JSON.stringify(task);
|
const taskId = JSON.stringify(task);
|
||||||
(task as RequestFilePartTask).id = taskId;
|
(task as RequestFilePartTask).id = taskId;
|
||||||
|
|
||||||
let deferred = deferredPromises[taskId] as CancellablePromise<UploadFile.uploadFile>;
|
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<UploadFile.uploadFile>;
|
||||||
if(deferred) {
|
if(deferred) {
|
||||||
return deferred.then(uploadFile => uploadFile.bytes);
|
return deferred.then(uploadFile => uploadFile.bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
notifySomeone(task);
|
windowClient.postMessage(task);
|
||||||
|
|
||||||
this.loadedOffsets.add(alignedOffset);
|
this.loadedOffsets.add(alignedOffset);
|
||||||
|
|
||||||
deferred = deferredPromises[taskId] = deferredPromise<UploadFile.uploadFile>();
|
deferred = promises[taskId] = deferredPromise<UploadFile.uploadFile>();
|
||||||
const bytesPromise = deferred.then(uploadFile => uploadFile.bytes);
|
const bytesPromise = deferred.then(uploadFile => uploadFile.bytes);
|
||||||
|
|
||||||
this.saveChunkToCache(bytesPromise, alignedOffset, limit);
|
this.saveChunkToCache(bytesPromise, alignedOffset, limit);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user