Service worker changes:
Moved whole apiFileManager TO-DO: Preloader progress File downloads Webp converter in SW
This commit is contained in:
parent
dad42da803
commit
23c91473f6
@ -1,5 +1,4 @@
|
|||||||
import resizeableImage from "../lib/cropper";
|
import resizeableImage from "../lib/cropper";
|
||||||
import apiFileManager from "../lib/mtproto/apiFileManager";
|
|
||||||
|
|
||||||
export class PopupAvatar {
|
export class PopupAvatar {
|
||||||
private container = document.getElementById('popup-avatar');
|
private container = document.getElementById('popup-avatar');
|
||||||
@ -77,7 +76,11 @@ export class PopupAvatar {
|
|||||||
|
|
||||||
private resolve() {
|
private resolve() {
|
||||||
this.onCrop(() => {
|
this.onCrop(() => {
|
||||||
return apiFileManager.uploadFile(this.blob);
|
//return apiFileManager.uploadFile(this.blob);
|
||||||
|
return fetch('/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
body: this.blob
|
||||||
|
}).then(res => res.json());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ import { mediaSizes } from '../lib/config';
|
|||||||
import { MTDocument, MTPhotoSize } from '../types';
|
import { MTDocument, MTPhotoSize } from '../types';
|
||||||
import animationIntersector from './animationIntersector';
|
import animationIntersector from './animationIntersector';
|
||||||
import AudioElement from './audio';
|
import AudioElement from './audio';
|
||||||
import MP4Source from '../lib/MP4Source';
|
|
||||||
|
|
||||||
export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue}: {
|
export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue}: {
|
||||||
doc: MTDocument,
|
doc: MTDocument,
|
||||||
@ -90,26 +89,18 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
|||||||
container.append(video);
|
container.append(video);
|
||||||
}
|
}
|
||||||
|
|
||||||
let loadVideo = async() => {
|
const loadVideo = async() => {
|
||||||
let url: string;
|
|
||||||
if(message.media.preloader) { // means upload
|
if(message.media.preloader) { // means upload
|
||||||
(message.media.preloader as ProgressivePreloader).attach(container, undefined, undefined, false);
|
(message.media.preloader as ProgressivePreloader).attach(container, undefined, undefined, false);
|
||||||
} else if(!doc.downloaded) {
|
} else if(!doc.downloaded) {
|
||||||
const promise = appDocsManager.downloadVideo(doc.id);
|
const promise = appDocsManager.downloadDoc(doc.id);
|
||||||
|
|
||||||
//if(!doc.supportsStreaming) {
|
//if(!doc.supportsStreaming) {
|
||||||
const preloader = new ProgressivePreloader(container, true);
|
const preloader = new ProgressivePreloader(container, true);
|
||||||
preloader.attach(container, true, promise, false);
|
preloader.attach(container, true, promise, false);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
const mp4Source: MP4Source = await (promise as Promise<MP4Source>);
|
await promise;
|
||||||
if(mp4Source instanceof MP4Source) {
|
|
||||||
url = mp4Source.getURL();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!url) {
|
|
||||||
url = doc.url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(middleware && !middleware()) {
|
if(middleware && !middleware()) {
|
||||||
@ -131,7 +122,7 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
|||||||
}, {once: true});
|
}, {once: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderImageFromUrl(source, url);
|
renderImageFromUrl(source, doc.url);
|
||||||
source.type = doc.mime_type;
|
source.type = doc.mime_type;
|
||||||
video.append(source);
|
video.append(source);
|
||||||
video.setAttribute('playsinline', '');
|
video.setAttribute('playsinline', '');
|
||||||
|
@ -1,24 +1,15 @@
|
|||||||
import apiFileManager from '../mtproto/apiFileManager';
|
|
||||||
import FileManager from '../filemanager';
|
import FileManager from '../filemanager';
|
||||||
import {RichTextProcessor} from '../richtextprocessor';
|
import {RichTextProcessor} from '../richtextprocessor';
|
||||||
import { CancellablePromise, deferredPromise } from '../polyfill';
|
import { CancellablePromise, deferredPromise } from '../polyfill';
|
||||||
import { isObject } from '../utils';
|
import { isObject, getFileURL } from '../utils';
|
||||||
import opusDecodeController from '../opusDecodeController';
|
import opusDecodeController from '../opusDecodeController';
|
||||||
import { MTDocument } from '../../types';
|
import { MTDocument, inputDocumentFileLocation } from '../../types';
|
||||||
import MP4Source from '../MP4Source';
|
|
||||||
import { bufferConcat } from '../bin_utils';
|
|
||||||
|
|
||||||
class AppDocsManager {
|
class AppDocsManager {
|
||||||
private docs: {[docID: string]: MTDocument} = {};
|
private docs: {[docID: string]: MTDocument} = {};
|
||||||
private thumbs: {[docIDAndSize: string]: Promise<string>} = {};
|
private thumbs: {[docIDAndSize: string]: Promise<string>} = {};
|
||||||
private downloadPromises: {[docID: string]: CancellablePromise<Blob>} = {};
|
private downloadPromises: {[docID: string]: CancellablePromise<Blob>} = {};
|
||||||
|
|
||||||
private videoChunks: {[docID: string]: CancellablePromise<ArrayBuffer>[]} = {};
|
|
||||||
private videoChunksQueue: {[docID: string]: {offset: number}[]} = {};
|
|
||||||
|
|
||||||
private loadedMP4Box: Promise<void>;
|
|
||||||
private mp4Source: MP4Source;
|
|
||||||
|
|
||||||
public saveDoc(apiDoc: MTDocument, context?: any) {
|
public saveDoc(apiDoc: MTDocument, context?: any) {
|
||||||
//console.log('saveDoc', apiDoc, this.docs[apiDoc.id]);
|
//console.log('saveDoc', apiDoc, this.docs[apiDoc.id]);
|
||||||
if(this.docs[apiDoc.id]) {
|
if(this.docs[apiDoc.id]) {
|
||||||
@ -41,16 +32,6 @@ class AppDocsManager {
|
|||||||
|
|
||||||
this.docs[apiDoc.id] = apiDoc;
|
this.docs[apiDoc.id] = apiDoc;
|
||||||
|
|
||||||
if(apiDoc.thumb && apiDoc.thumb._ == 'photoCachedSize') {
|
|
||||||
console.warn('this will happen!!!');
|
|
||||||
apiFileManager.saveSmallFile(apiDoc.thumb.location, apiDoc.thumb.bytes);
|
|
||||||
|
|
||||||
// Memory
|
|
||||||
apiDoc.thumb.size = apiDoc.thumb.bytes.length;
|
|
||||||
delete apiDoc.thumb.bytes;
|
|
||||||
apiDoc.thumb._ = 'photoSize';
|
|
||||||
}
|
|
||||||
|
|
||||||
if(apiDoc.thumb && apiDoc.thumb._ == 'photoSizeEmpty') {
|
if(apiDoc.thumb && apiDoc.thumb._ == 'photoSizeEmpty') {
|
||||||
delete apiDoc.thumb;
|
delete apiDoc.thumb;
|
||||||
}
|
}
|
||||||
@ -156,8 +137,8 @@ class AppDocsManager {
|
|||||||
return apiDoc;
|
return apiDoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDoc(docID: any): MTDocument {
|
public getDoc(docID: string | MTDocument): MTDocument {
|
||||||
return isObject(docID) ? docID : this.docs[docID];
|
return isObject(docID) && typeof(docID) !== 'string' ? docID : this.docs[docID as string];
|
||||||
}
|
}
|
||||||
|
|
||||||
public getMediaInputByID(docID: any) {
|
public getMediaInputByID(docID: any) {
|
||||||
@ -175,7 +156,7 @@ class AppDocsManager {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public getInputByID(docID: any, thumbSize?: string) {
|
public getInputByID(docID: any, thumbSize?: string): inputDocumentFileLocation {
|
||||||
let doc = this.getDoc(docID);
|
let doc = this.getDoc(docID);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -200,189 +181,40 @@ class AppDocsManager {
|
|||||||
return 't_' + (doc.type || 'file') + doc.id + fileExt;
|
return 't_' + (doc.type || 'file') + doc.id + fileExt;
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadMP4Box() {
|
public getFileURLByDoc(doc: MTDocument) {
|
||||||
if(this.loadedMP4Box) return this.loadedMP4Box;
|
const inputFileLocation = this.getInputByID(doc);
|
||||||
|
return getFileURL('document', {dcID: doc.dc_id, location: inputFileLocation, size: doc.size, mimeType: doc.mime_type || 'application/octet-stream'});
|
||||||
return this.loadedMP4Box = new Promise((resolve, reject) => {
|
|
||||||
(window as any).mp4BoxLoaded = () => {
|
|
||||||
//console.log('webpHero loaded');
|
|
||||||
this.mp4Source = (window as any).MP4Source;
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
|
|
||||||
let sc = document.createElement('script');
|
|
||||||
sc.src = 'mp4box.all.min.js';
|
|
||||||
sc.async = true;
|
|
||||||
sc.onload = (window as any).mp4BoxLoaded;
|
|
||||||
|
|
||||||
document.body.appendChild(sc);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private createMP4Stream(doc: MTDocument) {
|
public downloadDoc(docID: string | MTDocument, toFileEntry?: any): CancellablePromise<Blob> {
|
||||||
const limitPart = 524288;
|
|
||||||
const chunks = this.videoChunks[doc.id];
|
|
||||||
const queue = this.videoChunksQueue[doc.id];
|
|
||||||
|
|
||||||
//let mp4Source = new MP4Source({duration: doc.duration, video: {expected_size: doc.size}}, (offset: number, end: number) => {
|
|
||||||
let mp4Source = new (this.mp4Source as any)({duration: doc.duration, video: {expected_size: doc.size}}, (offset: number, end: number) => {
|
|
||||||
const chunkStart = offset - (offset % limitPart);
|
|
||||||
|
|
||||||
const sorted: typeof queue = [];
|
|
||||||
const lower: typeof queue = [];
|
|
||||||
for(let i = 0; i < queue.length; ++i) {
|
|
||||||
if(queue[i].offset >= chunkStart) {
|
|
||||||
sorted.push(queue[i]);
|
|
||||||
} else {
|
|
||||||
lower.push(queue[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sorted.sort((a, b) => a.offset - b.offset).concat(lower).forEach((q, i) => {
|
|
||||||
queue[i] = q;
|
|
||||||
});
|
|
||||||
|
|
||||||
const index1 = offset / limitPart | 0;
|
|
||||||
const index2 = end / limitPart | 0;
|
|
||||||
|
|
||||||
const p = chunks.slice(index1, index2 + 1);
|
|
||||||
|
|
||||||
//console.log('MP4Source getBuffer:', offset, end, index1, index2, doc.size, JSON.stringify(queue));
|
|
||||||
|
|
||||||
if(offset % limitPart == 0) {
|
|
||||||
return p[0];
|
|
||||||
} else {
|
|
||||||
return Promise.all(p).then(buffers => {
|
|
||||||
const buffer = buffers.length > 1 ? bufferConcat(buffers[0], buffers[1]) : buffers[0];
|
|
||||||
const start = (offset % limitPart);
|
|
||||||
const _end = start + (end - offset);
|
|
||||||
|
|
||||||
const sliced = buffer.slice(start, _end);
|
|
||||||
//console.log('slice buffer:', sliced);
|
|
||||||
return sliced;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return mp4Source;
|
|
||||||
}
|
|
||||||
|
|
||||||
private mp4Stream(doc: MTDocument, deferred: CancellablePromise<Blob>) {
|
|
||||||
const limitPart = 524288;
|
|
||||||
const promises = this.videoChunks[doc.id] ?? (this.videoChunks[doc.id] = []);
|
|
||||||
if(!promises.length) {
|
|
||||||
for(let offset = 0; offset < doc.size; offset += limitPart) {
|
|
||||||
const deferred = deferredPromise<ArrayBuffer>();
|
|
||||||
promises.push(deferred);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let good = false;
|
|
||||||
return async(bytes: Uint8Array, offset: number, queue: {offset: number}[]) => {
|
|
||||||
if(!deferred.isFulfilled && !deferred.isRejected/* && offset == 0 */) {
|
|
||||||
this.videoChunksQueue[doc.id] = queue;
|
|
||||||
console.log('stream:', doc, doc.url, deferred);
|
|
||||||
//doc.url = mp4Source.getURL();
|
|
||||||
//deferred.resolve(mp4Source);
|
|
||||||
deferred.resolve();
|
|
||||||
good = true;
|
|
||||||
} else if(!good) {
|
|
||||||
//mp4Source.stop();
|
|
||||||
//mp4Source = null;
|
|
||||||
promises.length = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const index = offset % limitPart == 0 ? offset / limitPart : promises.length - 1;
|
|
||||||
promises[index].resolve(bytes.slice().buffer);
|
|
||||||
//console.log('i wont believe in you', doc, bytes, offset, promises, bytes.length, bytes.buffer.byteLength, bytes.slice().buffer);
|
|
||||||
//console.log('i wont believe in you', bytes, doc, bytes.length, offset);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public downloadVideo(docID: string): CancellablePromise<MP4Source | Blob> {
|
|
||||||
const doc = this.getDoc(docID);
|
|
||||||
if(!doc.supportsStreaming || doc.url) {
|
|
||||||
return this.downloadDoc(docID);
|
|
||||||
}
|
|
||||||
|
|
||||||
const deferred = deferredPromise<Blob>();
|
|
||||||
let canceled = false;
|
|
||||||
deferred.cancel = () => {
|
|
||||||
canceled = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.loadMP4Box().then(() => {
|
|
||||||
if(canceled) {
|
|
||||||
throw 'canceled';
|
|
||||||
}
|
|
||||||
|
|
||||||
const promise = this.downloadDoc(docID);
|
|
||||||
|
|
||||||
deferred.cancel = () => {
|
|
||||||
promise.cancel();
|
|
||||||
};
|
|
||||||
|
|
||||||
promise.notify = (...args) => {
|
|
||||||
deferred.notify && deferred.notify(...args);
|
|
||||||
};
|
|
||||||
|
|
||||||
promise.then(() => {
|
|
||||||
if(doc.url) { // может быть уже загружен из кэша
|
|
||||||
deferred.resolve();
|
|
||||||
} else {
|
|
||||||
deferred.resolve(this.createMP4Stream(doc));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, deferred.reject);
|
|
||||||
|
|
||||||
return deferred;
|
|
||||||
}
|
|
||||||
|
|
||||||
public downloadDoc(docID: any, toFileEntry?: any): CancellablePromise<Blob> {
|
|
||||||
const doc = this.getDoc(docID);
|
const doc = this.getDoc(docID);
|
||||||
|
|
||||||
if(doc._ == 'documentEmpty') {
|
if(doc._ == 'documentEmpty') {
|
||||||
return Promise.reject();
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputFileLocation = this.getInputByID(doc);
|
|
||||||
if(doc.downloaded && !toFileEntry) {
|
if(doc.downloaded && !toFileEntry) {
|
||||||
if(doc.url) return Promise.resolve(null);
|
if(doc.url) return Promise.resolve(null);
|
||||||
|
|
||||||
const cachedBlob = apiFileManager.getCachedFile(inputFileLocation);
|
/* const cachedBlob = apiFileManager.getCachedFile(inputFileLocation);
|
||||||
if(cachedBlob) {
|
if(cachedBlob) {
|
||||||
return Promise.resolve(cachedBlob);
|
return Promise.resolve(cachedBlob);
|
||||||
}
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.downloadPromises[doc.id]) {
|
if(this.downloadPromises[doc.id]) {
|
||||||
return this.downloadPromises[doc.id];
|
return this.downloadPromises[doc.id];
|
||||||
}
|
}
|
||||||
|
|
||||||
//historyDoc.progress = {enabled: !historyDoc.downloaded, percent: 1, total: doc.size};
|
|
||||||
|
|
||||||
const deferred = deferredPromise<Blob>();
|
const deferred = deferredPromise<Blob>();
|
||||||
deferred.cancel = () => {
|
|
||||||
downloadPromise.cancel();
|
|
||||||
};
|
|
||||||
|
|
||||||
const processPart = doc.supportsStreaming ? this.mp4Stream(doc, deferred) : undefined;
|
/* if(doc.supportsStreaming) {
|
||||||
|
doc.url = '/stream/' + '';
|
||||||
|
} */
|
||||||
|
|
||||||
// нет смысла делать объект с выполняющимися промисами, нижняя строка и так вернёт загружающийся
|
const url = this.getFileURLByDoc(doc);
|
||||||
const downloadPromise = apiFileManager.downloadFile(doc.dc_id, inputFileLocation, doc.size, {
|
fetch(url).then(res => res.blob())
|
||||||
mimeType: doc.mime_type || 'application/octet-stream',
|
/* downloadPromise */.then((blob) => {
|
||||||
toFileEntry: toFileEntry,
|
|
||||||
stickerType: doc.sticker,
|
|
||||||
processPart
|
|
||||||
});
|
|
||||||
|
|
||||||
downloadPromise.notify = (...args) => {
|
|
||||||
deferred.notify && deferred.notify(...args);
|
|
||||||
};
|
|
||||||
|
|
||||||
//deferred.notify = downloadPromise.notify;
|
|
||||||
|
|
||||||
downloadPromise.then((blob) => {
|
|
||||||
if(blob) {
|
if(blob) {
|
||||||
doc.downloaded = true;
|
doc.downloaded = true;
|
||||||
|
|
||||||
@ -405,11 +237,7 @@ class AppDocsManager {
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
} else if(doc.type && doc.sticker != 2) {
|
} else if(doc.type && doc.sticker != 2) {
|
||||||
/* if(processPart) {
|
doc.url = url;
|
||||||
console.log('stream after:', doc, doc.url, deferred);
|
|
||||||
} */
|
|
||||||
|
|
||||||
doc.url = URL.createObjectURL(blob);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,23 +245,10 @@ class AppDocsManager {
|
|||||||
}, (e) => {
|
}, (e) => {
|
||||||
console.log('document download failed', e);
|
console.log('document download failed', e);
|
||||||
deferred.reject(e);
|
deferred.reject(e);
|
||||||
//historyDoc.progress.enabled = false;
|
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
deferred.notify = downloadPromise.notify = deferred.cancel = downloadPromise.cancel = null;
|
//deferred.notify = downloadPromise.notify = deferred.cancel = downloadPromise.cancel = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
/* downloadPromise.notify = (progress) => {
|
|
||||||
console.log('dl progress', progress);
|
|
||||||
historyDoc.progress.enabled = true;
|
|
||||||
historyDoc.progress.done = progress.done;
|
|
||||||
historyDoc.progress.percent = Math.max(1, Math.floor(100 * progress.done / progress.total));
|
|
||||||
$rootScope.$broadcast('history_update');
|
|
||||||
}; */
|
|
||||||
|
|
||||||
//historyDoc.progress.cancel = downloadPromise.cancel;
|
|
||||||
|
|
||||||
//console.log('return downloadPromise:', downloadPromise);
|
|
||||||
|
|
||||||
return this.downloadPromises[doc.id] = deferred;
|
return this.downloadPromises[doc.id] = deferred;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,16 +266,8 @@ class AppDocsManager {
|
|||||||
return Promise.reject();
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mimeType = doc.sticker ? 'image/webp' : doc.mime_type;
|
const url = getFileURL('thumb', {dcID: doc.dc_id, location: input, mimeType: doc.sticker ? 'image/webp' : doc.mime_type});
|
||||||
let promise = apiFileManager.downloadSmallFile(input, {
|
return this.thumbs[key] = Promise.resolve(url);
|
||||||
dcID: doc.dc_id,
|
|
||||||
stickerType: doc.sticker ? 1 : undefined,
|
|
||||||
mimeType: mimeType
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.thumbs[key] = promise.then((blob) => {
|
|
||||||
return URL.createObjectURL(blob);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasDownloadedThumb(docID: string, thumbSize: string) {
|
public hasDownloadedThumb(docID: string, thumbSize: string) {
|
||||||
|
@ -549,7 +549,7 @@ export class AppImManager {
|
|||||||
private closeBtn = this.topbar.querySelector('.sidebar-close-button') as HTMLButtonElement;
|
private closeBtn = this.topbar.querySelector('.sidebar-close-button') as HTMLButtonElement;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.log = logger('IM', LogLevels.log | LogLevels.error | LogLevels.warn | LogLevels.debug);
|
this.log = logger('IM', /* LogLevels.log | LogLevels.warn | LogLevels.debug | */ LogLevels.error);
|
||||||
this.chatInputC = new ChatInput();
|
this.chatInputC = new ChatInput();
|
||||||
this.preloader = new ProgressivePreloader(null, false);
|
this.preloader = new ProgressivePreloader(null, false);
|
||||||
this.selectTab(0);
|
this.selectTab(0);
|
||||||
@ -2641,7 +2641,7 @@ export class AppImManager {
|
|||||||
|
|
||||||
avatarElem.setAttribute('peer', '' + ((message.fwd_from && this.peerID == this.myID ? message.fwdFromID : message.fromID) || 0));
|
avatarElem.setAttribute('peer', '' + ((message.fwd_from && this.peerID == this.myID ? message.fwdFromID : message.fromID) || 0));
|
||||||
|
|
||||||
this.log('exec loadDialogPhoto', message);
|
//this.log('exec loadDialogPhoto', message);
|
||||||
|
|
||||||
bubbleContainer.append(avatarElem);
|
bubbleContainer.append(avatarElem);
|
||||||
}
|
}
|
||||||
|
@ -826,7 +826,7 @@ export class AppMediaViewer {
|
|||||||
|
|
||||||
if(!source.src || (media.url && media.url != source.src)) {
|
if(!source.src || (media.url && media.url != source.src)) {
|
||||||
const load = () => {
|
const load = () => {
|
||||||
const promise = appDocsManager.downloadVideo(media.id);
|
const promise = appDocsManager.downloadDoc(media.id);
|
||||||
|
|
||||||
const streamable = media.supportsStreaming && !media.url;
|
const streamable = media.supportsStreaming && !media.url;
|
||||||
//if(!streamable) {
|
//if(!streamable) {
|
||||||
|
@ -11,7 +11,6 @@ import appPhotosManager from "./appPhotosManager";
|
|||||||
import AppStorage from '../storage';
|
import AppStorage from '../storage';
|
||||||
import appPeersManager from "./appPeersManager";
|
import appPeersManager from "./appPeersManager";
|
||||||
import ServerTimeManager from "../mtproto/serverTimeManager";
|
import ServerTimeManager from "../mtproto/serverTimeManager";
|
||||||
import apiFileManager from "../mtproto/apiFileManager";
|
|
||||||
import appDocsManager from "./appDocsManager";
|
import appDocsManager from "./appDocsManager";
|
||||||
import ProgressivePreloader from "../../components/preloader";
|
import ProgressivePreloader from "../../components/preloader";
|
||||||
import serverTimeManager from "../mtproto/serverTimeManager";
|
import serverTimeManager from "../mtproto/serverTimeManager";
|
||||||
@ -22,7 +21,8 @@ import { CancellablePromise, deferredPromise } from "../polyfill";
|
|||||||
import appPollsManager from "./appPollsManager";
|
import appPollsManager from "./appPollsManager";
|
||||||
import searchIndexManager from '../searchIndexManager';
|
import searchIndexManager from '../searchIndexManager';
|
||||||
import { MTDocument, MTPhotoSize } from "../../types";
|
import { MTDocument, MTPhotoSize } from "../../types";
|
||||||
import { logger } from "../logger";
|
import { logger, LogLevels } from "../logger";
|
||||||
|
import type {ApiFileManager} from '../mtproto/apiFileManager';
|
||||||
|
|
||||||
//console.trace('include');
|
//console.trace('include');
|
||||||
|
|
||||||
@ -595,7 +595,7 @@ export class AppMessagesManager {
|
|||||||
dialogs: []
|
dialogs: []
|
||||||
};
|
};
|
||||||
|
|
||||||
private log = logger('MESSAGES'/* , LogLevels.error */);
|
private log = logger('MESSAGES', LogLevels.error);
|
||||||
|
|
||||||
public dialogsStorage = new DialogsStorage();
|
public dialogsStorage = new DialogsStorage();
|
||||||
public filtersStorage = new FiltersStorage();
|
public filtersStorage = new FiltersStorage();
|
||||||
@ -1179,7 +1179,7 @@ export class AppMessagesManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var uploaded = false,
|
var uploaded = false,
|
||||||
uploadPromise: ReturnType<typeof apiFileManager.uploadFile> = null;
|
uploadPromise: ReturnType<ApiFileManager['uploadFile']> = null;
|
||||||
|
|
||||||
let invoke = (flags: number, inputMedia: any) => {
|
let invoke = (flags: number, inputMedia: any) => {
|
||||||
this.setTyping('sendMessageCancelAction');
|
this.setTyping('sendMessageCancelAction');
|
||||||
@ -1241,7 +1241,11 @@ export class AppMessagesManager {
|
|||||||
this.sendFilePromise.then(() => {
|
this.sendFilePromise.then(() => {
|
||||||
if(!uploaded || message.error) {
|
if(!uploaded || message.error) {
|
||||||
uploaded = false;
|
uploaded = false;
|
||||||
uploadPromise = apiFileManager.uploadFile(file);
|
//uploadPromise = apiFileManager.uploadFile(file);
|
||||||
|
uploadPromise = fetch('/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
body: file
|
||||||
|
}).then(res => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadPromise && uploadPromise.then((inputFile) => {
|
uploadPromise && uploadPromise.then((inputFile) => {
|
||||||
@ -1485,7 +1489,7 @@ export class AppMessagesManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let uploaded = false,
|
let uploaded = false,
|
||||||
uploadPromise: ReturnType<typeof apiFileManager.uploadFile> = null;
|
uploadPromise: ReturnType<ApiFileManager['uploadFile']> = null;
|
||||||
|
|
||||||
let inputPeer = appPeersManager.getInputPeerByID(peerID);
|
let inputPeer = appPeersManager.getInputPeerByID(peerID);
|
||||||
let invoke = (multiMedia: any[]) => {
|
let invoke = (multiMedia: any[]) => {
|
||||||
@ -1517,7 +1521,11 @@ export class AppMessagesManager {
|
|||||||
|
|
||||||
if(!uploaded || message.error) {
|
if(!uploaded || message.error) {
|
||||||
uploaded = false;
|
uploaded = false;
|
||||||
uploadPromise = apiFileManager.uploadFile(file);
|
//uploadPromise = apiFileManager.uploadFile(file);
|
||||||
|
uploadPromise = fetch('/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
body: file
|
||||||
|
}).then(res => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadPromise.notify = (progress: {done: number, total: number}) => {
|
uploadPromise.notify = (progress: {done: number, total: number}) => {
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import appUsersManager from "./appUsersManager";
|
import appUsersManager from "./appUsersManager";
|
||||||
import { calcImageInBox, isObject } from "../utils";
|
import { calcImageInBox, isObject, getFileURL } from "../utils";
|
||||||
import fileManager from '../filemanager';
|
import fileManager from '../filemanager';
|
||||||
import { bytesFromHex } from "../bin_utils";
|
import { bytesFromHex } from "../bin_utils";
|
||||||
import apiFileManager from "../mtproto/apiFileManager";
|
|
||||||
//import apiManager from '../mtproto/apiManager';
|
//import apiManager from '../mtproto/apiManager';
|
||||||
import apiManager from '../mtproto/mtprotoworker';
|
import apiManager from '../mtproto/mtprotoworker';
|
||||||
import { MTPhotoSize } from "../../types";
|
import { MTPhotoSize, inputPhotoFileLocation, inputDocumentFileLocation, InputFileLocation, FileLocation } from "../../types";
|
||||||
|
|
||||||
export type MTPhoto = {
|
export type MTPhoto = {
|
||||||
_: 'photo' | 'photoEmpty' | string,
|
_: 'photo' | 'photoEmpty' | string,
|
||||||
@ -250,17 +249,17 @@ export class AppPhotosManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public preloadPhoto(photoID: any, photoSize?: MTPhotoSize): Promise<Blob | void> {
|
public preloadPhoto(photoID: any, photoSize?: MTPhotoSize): Promise<Blob | void> {
|
||||||
let photo = this.getPhoto(photoID);
|
const photo = this.getPhoto(photoID);
|
||||||
|
|
||||||
if(!photoSize) {
|
if(!photoSize) {
|
||||||
let fullWidth = this.windowW;
|
const fullWidth = this.windowW;
|
||||||
let fullHeight = this.windowH;
|
const fullHeight = this.windowH;
|
||||||
|
|
||||||
photoSize = this.choosePhotoSize(photo, fullWidth, fullHeight);
|
photoSize = this.choosePhotoSize(photo, fullWidth, fullHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
let isDocument = photo._ == 'document';
|
const isDocument = photo._ == 'document';
|
||||||
let cacheContext = isDocument ? (this.documentThumbsCache[photo.id] ?? (this.documentThumbsCache[photo.id] = {downloaded: -1, url: ''})) : photo;
|
const cacheContext = isDocument ? (this.documentThumbsCache[photo.id] ?? (this.documentThumbsCache[photo.id] = {downloaded: -1, url: ''})) : photo;
|
||||||
|
|
||||||
if(cacheContext.downloaded >= photoSize.size && cacheContext.url) {
|
if(cacheContext.downloaded >= photoSize.size && cacheContext.url) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@ -273,7 +272,7 @@ export class AppPhotosManager {
|
|||||||
|
|
||||||
// maybe it's a thumb
|
// maybe it's a thumb
|
||||||
let isPhoto = photoSize.size && photo.access_hash && photo.file_reference;
|
let isPhoto = photoSize.size && photo.access_hash && photo.file_reference;
|
||||||
let location = isPhoto ? {
|
let location: inputPhotoFileLocation | inputDocumentFileLocation | FileLocation = isPhoto ? {
|
||||||
_: isDocument ? 'inputDocumentFileLocation' : 'inputPhotoFileLocation',
|
_: isDocument ? 'inputDocumentFileLocation' : 'inputPhotoFileLocation',
|
||||||
id: photo.id,
|
id: photo.id,
|
||||||
access_hash: photo.access_hash,
|
access_hash: photo.access_hash,
|
||||||
@ -281,19 +280,20 @@ export class AppPhotosManager {
|
|||||||
thumb_size: photoSize.type
|
thumb_size: photoSize.type
|
||||||
} : photoSize.location;
|
} : photoSize.location;
|
||||||
|
|
||||||
|
const url = getFileURL('photo', {dcID: photo.dc_id, location, size: isPhoto ? photoSize.size : undefined});
|
||||||
let promise: Promise<Blob>;
|
let promise: Promise<Blob>;
|
||||||
if(isPhoto/* && photoSize.size >= 1e6 */) {
|
if(isPhoto/* && photoSize.size >= 1e6 */) {
|
||||||
//console.log('Photos downloadFile exec', photo);
|
promise = fetch(url).then(res => res.blob());
|
||||||
promise = apiFileManager.downloadFile(photo.dc_id, location, photoSize.size);
|
|
||||||
} else {
|
} else {
|
||||||
//console.log('Photos downloadSmallFile exec', photo, location);
|
//console.log('Photos downloadSmallFile exec', photo, location);
|
||||||
promise = apiFileManager.downloadSmallFile(location);
|
promise = fetch(url).then(res => res.blob());
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.then(blob => {
|
promise.then(blob => {
|
||||||
if(!cacheContext.downloaded || cacheContext.downloaded < blob.size) {
|
if(!cacheContext.downloaded || cacheContext.downloaded < blob.size) {
|
||||||
cacheContext.downloaded = blob.size;
|
cacheContext.downloaded = blob.size;
|
||||||
cacheContext.url = URL.createObjectURL(blob);
|
//cacheContext.url = URL.createObjectURL(blob);
|
||||||
|
cacheContext.url = url;
|
||||||
|
|
||||||
//console.log('wrote photo:', photo, photoSize, cacheContext, blob);
|
//console.log('wrote photo:', photo, photoSize, cacheContext, blob);
|
||||||
}
|
}
|
||||||
@ -333,7 +333,7 @@ export class AppPhotosManager {
|
|||||||
var fullWidth = this.windowW;
|
var fullWidth = this.windowW;
|
||||||
var fullHeight = this.windowH;
|
var fullHeight = this.windowH;
|
||||||
var fullPhotoSize = this.choosePhotoSize(photo, fullWidth, fullHeight);
|
var fullPhotoSize = this.choosePhotoSize(photo, fullWidth, fullHeight);
|
||||||
var inputFileLocation = {
|
var inputFileLocation: inputDocumentFileLocation | inputPhotoFileLocation = {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
_: photo._ == 'document' ? 'inputDocumentFileLocation' : 'inputPhotoFileLocation',
|
_: photo._ == 'document' ? 'inputDocumentFileLocation' : 'inputPhotoFileLocation',
|
||||||
id: photo.id,
|
id: photo.id,
|
||||||
@ -346,7 +346,7 @@ export class AppPhotosManager {
|
|||||||
let writer = fileManager.chooseSaveFile(fileName, ext, mimeType, fullPhotoSize.size);
|
let writer = fileManager.chooseSaveFile(fileName, ext, mimeType, fullPhotoSize.size);
|
||||||
writer.ready.then(() => {
|
writer.ready.then(() => {
|
||||||
console.log('ready');
|
console.log('ready');
|
||||||
apiFileManager.downloadFile(photo.dc_id, inputFileLocation, fullPhotoSize.size, {
|
apiManager.downloadFile(photo.dc_id, inputFileLocation, fullPhotoSize.size, {
|
||||||
mimeType: mimeType,
|
mimeType: mimeType,
|
||||||
toFileEntry: writer
|
toFileEntry: writer
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
@ -360,12 +360,12 @@ export class AppPhotosManager {
|
|||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.error('err', err);
|
console.error('err', err);
|
||||||
|
|
||||||
var cachedBlob = apiFileManager.getCachedFile(inputFileLocation)
|
/* var cachedBlob = apiFileManager.getCachedFile(inputFileLocation)
|
||||||
if (cachedBlob) {
|
if (cachedBlob) {
|
||||||
return fileManager.download(cachedBlob, mimeType, fileName);
|
return fileManager.download(cachedBlob, mimeType, fileName);
|
||||||
}
|
} */
|
||||||
|
|
||||||
apiFileManager.downloadFile(photo.dc_id, inputFileLocation, fullPhotoSize.size, {mimeType: mimeType})
|
apiManager.downloadFile(photo.dc_id, inputFileLocation, fullPhotoSize.size, {mimeType: mimeType})
|
||||||
.then((blob: Blob) => {
|
.then((blob: Blob) => {
|
||||||
fileManager.download(blob, mimeType, fileName);
|
fileManager.download(blob, mimeType, fileName);
|
||||||
}, (e: any) => {
|
}, (e: any) => {
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import AppStorage from '../storage';
|
import AppStorage from '../storage';
|
||||||
//import apiManager from '../mtproto/apiManager';
|
//import apiManager from '../mtproto/apiManager';
|
||||||
import apiManager from '../mtproto/mtprotoworker';
|
import apiManager from '../mtproto/mtprotoworker';
|
||||||
import apiFileManager from '../mtproto/apiFileManager';
|
|
||||||
import appDocsManager from './appDocsManager';
|
import appDocsManager from './appDocsManager';
|
||||||
import { MTDocument } from '../../types';
|
import { MTDocument, inputStickerSetThumb } from '../../types';
|
||||||
import { $rootScope } from '../utils';
|
import { $rootScope, getFileURL } from '../utils';
|
||||||
|
|
||||||
export type MTStickerSet = {
|
export type MTStickerSet = {
|
||||||
_: 'stickerSet',
|
_: 'stickerSet',
|
||||||
@ -224,17 +223,17 @@ class AppStickersManager {
|
|||||||
|
|
||||||
const isAnimated = stickerSet.pFlags?.animated;
|
const isAnimated = stickerSet.pFlags?.animated;
|
||||||
|
|
||||||
const promise = apiFileManager.downloadFile(dcID, {
|
const input: inputStickerSetThumb = {
|
||||||
_: 'inputStickerSetThumb',
|
_: 'inputStickerSetThumb',
|
||||||
stickerset: this.getStickerSetInput(stickerSet),
|
stickerset: this.getStickerSetInput(stickerSet),
|
||||||
volume_id: thumb.location.volume_id,
|
volume_id: thumb.location.volume_id,
|
||||||
local_id: thumb.location.local_id
|
local_id: thumb.location.local_id
|
||||||
}, thumb.size, {
|
};
|
||||||
stickerType: isAnimated ? 2 : 1,
|
|
||||||
mimeType: isAnimated ? "application/x-tgsticker" : 'image/webp'
|
|
||||||
});
|
|
||||||
|
|
||||||
return promise;
|
const url = getFileURL('document', {dcID, location: input, size: thumb.size, mimeType: isAnimated ? "application/x-tgsticker" : 'image/webp'});
|
||||||
|
return fetch(url).then(res => res.blob());
|
||||||
|
|
||||||
|
//return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getStickerSetInput(set: {id: string, access_hash: string}) {
|
public getStickerSetInput(set: {id: string, access_hash: string}) {
|
||||||
|
@ -71,6 +71,7 @@ class AppWebpManager {
|
|||||||
if(this.testPromise) return this.testPromise;
|
if(this.testPromise) return this.testPromise;
|
||||||
|
|
||||||
return this.testPromise = new Promise((resolve, reject) => {
|
return this.testPromise = new Promise((resolve, reject) => {
|
||||||
|
return resolve(this.webpSupport = true);
|
||||||
let webP = new Image();
|
let webP = new Image();
|
||||||
webP.src = 'data:image/webp;base64,UklGRi4AAABXRUJQVlA4TCEAAAAvAUAAEB8wAiMw' +
|
webP.src = 'data:image/webp;base64,UklGRi4AAABXRUJQVlA4TCEAAAAvAUAAEB8wAiMw' +
|
||||||
'AgSSNtse/cXjxyCCmrYNWPwmHRH9jwMA';
|
'AgSSNtse/cXjxyCCmrYNWPwmHRH9jwMA';
|
||||||
@ -95,8 +96,8 @@ class AppWebpManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const appWebpManager = new AppWebpManager();
|
const appWebpManager = new AppWebpManager();
|
||||||
// @ts-ignore
|
/* // @ts-ignore
|
||||||
if(process.env.NODE_ENV != 'production') {
|
if(process.env.NODE_ENV != 'production') {
|
||||||
(window as any).appWebpManager = appWebpManager;
|
(window as any).appWebpManager = appWebpManager;
|
||||||
}
|
} */
|
||||||
export default appWebpManager;
|
export default appWebpManager;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import {BigInteger, SecureRandom} from 'jsbn';
|
import {BigInteger, SecureRandom} from 'jsbn';
|
||||||
|
import { InputFileLocation, FileLocation } from '../types';
|
||||||
|
|
||||||
/// #if !MTPROTO_WORKER
|
/// #if !MTPROTO_WORKER
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -380,3 +381,30 @@ export function addPadding(bytes: any, blockSize: number = 16, zeroes?: boolean,
|
|||||||
export function nextRandomInt(maxValue: number) {
|
export function nextRandomInt(maxValue: number) {
|
||||||
return Math.floor(Math.random() * maxValue);
|
return Math.floor(Math.random() * maxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getFileNameByLocation(location: InputFileLocation | FileLocation, options?: Partial<{
|
||||||
|
fileName: string
|
||||||
|
}>) {
|
||||||
|
const fileName = (options?.fileName || '').split('.');
|
||||||
|
const ext = fileName[fileName.length - 1] || '';
|
||||||
|
|
||||||
|
switch(location._) {
|
||||||
|
case 'inputPhotoFileLocation':
|
||||||
|
case 'inputDocumentFileLocation': {
|
||||||
|
const thumbPart = location.thumb_size ? '_' + location.thumb_size : '';
|
||||||
|
return (fileName[0] ? fileName[0] + '_' : '') + location.id + thumbPart + (ext ? '.' + ext : ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'fileLocationToBeDeprecated':
|
||||||
|
case 'inputPeerPhotoFileLocation':
|
||||||
|
case 'inputStickerSetThumb':
|
||||||
|
case 'inputFileLocation': {
|
||||||
|
return location.volume_id + '_' + location.local_id + (ext ? '.' + ext : ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
console.error('Unrecognized location:', location);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -95,8 +95,8 @@ class CacheStorageController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cacheStorage = new CacheStorageController();
|
const cacheStorage = new CacheStorageController();
|
||||||
// @ts-ignore
|
/* // @ts-ignore
|
||||||
if(process.env.NODE_ENV != 'production') {
|
if(process.env.NODE_ENV != 'production') {
|
||||||
(window as any).cacheStorage = cacheStorage;
|
(window as any).cacheStorage = cacheStorage;
|
||||||
}
|
} */
|
||||||
export default cacheStorage;
|
export default cacheStorage;
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import { nextRandomInt } from "../bin_utils";
|
import { nextRandomInt, getFileNameByLocation } from "../bin_utils";
|
||||||
|
|
||||||
//import IdbFileStorage from "../idb";
|
|
||||||
import cacheStorage from "../cacheStorage";
|
import cacheStorage from "../cacheStorage";
|
||||||
import FileManager from "../filemanager";
|
import FileManager from "../filemanager";
|
||||||
//import apiManager from "./apiManager";
|
import apiManager from "./apiManager";
|
||||||
import apiManager from "./mtprotoworker";
|
|
||||||
import { deferredPromise, CancellablePromise } from "../polyfill";
|
import { deferredPromise, CancellablePromise } from "../polyfill";
|
||||||
import appWebpManager from "../appManagers/appWebpManager";
|
import appWebpManager from "../appManagers/appWebpManager";
|
||||||
import { logger } from "../logger";
|
import { logger } from "../logger";
|
||||||
|
import { InputFileLocation, FileLocation } from "../../types";
|
||||||
|
|
||||||
type Delayed = {
|
type Delayed = {
|
||||||
offset: number,
|
offset: number,
|
||||||
@ -15,19 +14,14 @@ type Delayed = {
|
|||||||
writeFileDeferred: CancellablePromise<unknown>
|
writeFileDeferred: CancellablePromise<unknown>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type DownloadOptions = Partial<{
|
||||||
|
|
||||||
|
}>;
|
||||||
|
|
||||||
export class ApiFileManager {
|
export class ApiFileManager {
|
||||||
public cachedSavePromises: {
|
public cachedDownloadPromises: {
|
||||||
[fileName: string]: Promise<Blob>
|
[fileName: string]: Promise<Blob>
|
||||||
} = {};
|
} = {};
|
||||||
public cachedDownloadPromises: {
|
|
||||||
[fileName: string]: any
|
|
||||||
} = {};
|
|
||||||
public cachedDownloads: {
|
|
||||||
[fileName: string]: Blob
|
|
||||||
} = {};
|
|
||||||
|
|
||||||
/* public indexedKeys: Set<string> = new Set();
|
|
||||||
private keysLoaded = false; */
|
|
||||||
|
|
||||||
public downloadPulls: {
|
public downloadPulls: {
|
||||||
[x: string]: Array<{
|
[x: string]: Array<{
|
||||||
@ -95,194 +89,26 @@ export class ApiFileManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFileName(location: any, options?: Partial<{
|
|
||||||
stickerType: number
|
|
||||||
}>) {
|
|
||||||
switch(location._) {
|
|
||||||
case 'inputDocumentFileLocation': {
|
|
||||||
let fileName = (location.file_name as string || '').split('.');
|
|
||||||
let ext = fileName[fileName.length - 1] || '';
|
|
||||||
|
|
||||||
if(options?.stickerType == 1 && !appWebpManager.isSupported()) {
|
|
||||||
ext += '.png'
|
|
||||||
}
|
|
||||||
|
|
||||||
let thumbPart = location.thumb_size ? '_' + location.thumb_size : '';
|
|
||||||
return (fileName[0] ? fileName[0] + '_' : '') + location.id + thumbPart + (ext ? '.' + ext : ext);
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
if(!location.volume_id && !location.file_reference) {
|
|
||||||
this.log.trace('Empty location', location);
|
|
||||||
}
|
|
||||||
|
|
||||||
let ext = 'jpg';
|
|
||||||
if(options?.stickerType == 1 && !appWebpManager.isSupported()) {
|
|
||||||
ext += '.png'
|
|
||||||
}
|
|
||||||
|
|
||||||
if(location.volume_id) {
|
|
||||||
return location.volume_id + '_' + location.local_id + '.' + ext;
|
|
||||||
} else {
|
|
||||||
return location.id + '_' + location.access_hash + '.' + ext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public getTempFileName(file: any) {
|
|
||||||
const size = file.size || -1;
|
|
||||||
const random = nextRandomInt(0xFFFFFFFF);
|
|
||||||
return '_temp' + random + '_' + size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getCachedFile(location: any) {
|
|
||||||
if(!location) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const fileName = this.getFileName(location);
|
|
||||||
|
|
||||||
return this.cachedDownloads[fileName] || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getFileStorage() {
|
public getFileStorage() {
|
||||||
return cacheStorage;
|
return cacheStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* public isFileExists(location: any) {
|
public downloadFile(options: {
|
||||||
var fileName = this.getFileName(location);
|
|
||||||
|
|
||||||
return this.cachedDownloads[fileName] || this.indexedKeys.has(fileName);
|
|
||||||
//return this.cachedDownloads[fileName] || this.indexedKeys.has(fileName) ? Promise.resolve(true) : this.getFileStorage().isFileExists(fileName);
|
|
||||||
} */
|
|
||||||
|
|
||||||
public saveSmallFile(location: any, bytes: Uint8Array) {
|
|
||||||
var fileName = this.getFileName(location);
|
|
||||||
|
|
||||||
if(!this.cachedSavePromises[fileName]) {
|
|
||||||
this.cachedSavePromises[fileName] = this.getFileStorage().saveFile(fileName, bytes).then((blob: any) => {
|
|
||||||
return this.cachedDownloads[fileName] = blob;
|
|
||||||
}, (error: any) => {
|
|
||||||
delete this.cachedSavePromises[fileName];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return this.cachedSavePromises[fileName];
|
|
||||||
}
|
|
||||||
|
|
||||||
public downloadSmallFile(location: any, options: Partial<{
|
|
||||||
mimeType: string,
|
|
||||||
dcID: number,
|
dcID: number,
|
||||||
stickerType: number
|
location: InputFileLocation | FileLocation,
|
||||||
}> = {}): Promise<Blob> {
|
size: number,
|
||||||
|
mimeType?: string,
|
||||||
|
toFileEntry?: any,
|
||||||
|
limitPart?: number,
|
||||||
|
stickerType?: number,
|
||||||
|
processPart?: (bytes: Uint8Array, offset: number, queue: Delayed[]) => Promise<any>
|
||||||
|
}): CancellablePromise<Blob> {
|
||||||
if(!FileManager.isAvailable()) {
|
if(!FileManager.isAvailable()) {
|
||||||
return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'});
|
return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if(!this.keysLoaded) {
|
let size = options.size ?? 0;
|
||||||
this.getIndexedKeys();
|
let {dcID, location} = options;
|
||||||
} */
|
|
||||||
|
|
||||||
//this.log('downloadSmallFile', location, options);
|
|
||||||
|
|
||||||
let processSticker = false;
|
|
||||||
if(options.stickerType == 1 && !appWebpManager.isSupported()) {
|
|
||||||
processSticker = true;
|
|
||||||
options.mimeType = 'image/png';
|
|
||||||
}
|
|
||||||
|
|
||||||
let dcID = options.dcID || location.dc_id;
|
|
||||||
let mimeType = options.mimeType || 'image/jpeg';
|
|
||||||
let fileName = this.getFileName(location, options);
|
|
||||||
let cachedPromise = this.cachedSavePromises[fileName] || this.cachedDownloadPromises[fileName];
|
|
||||||
|
|
||||||
//this.log('downloadSmallFile!', location, options, fileName, cachedPromise);
|
|
||||||
|
|
||||||
if(cachedPromise) {
|
|
||||||
return cachedPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fileStorage = this.getFileStorage();
|
|
||||||
|
|
||||||
return this.cachedDownloadPromises[fileName] = fileStorage.getFile(fileName).then((blob) => {
|
|
||||||
//throw '';
|
|
||||||
//this.log('downloadSmallFile found photo by fileName:', fileName);
|
|
||||||
return this.cachedDownloads[fileName] = blob;
|
|
||||||
}).catch(() => {
|
|
||||||
//this.log.warn('downloadSmallFile found no photo by fileName:', fileName);
|
|
||||||
let downloadPromise = this.downloadRequest(dcID, () => {
|
|
||||||
let inputLocation = location;
|
|
||||||
if(!inputLocation._ || inputLocation._ == 'fileLocation') {
|
|
||||||
inputLocation = Object.assign({}, location, {_: 'inputFileLocation'});
|
|
||||||
}
|
|
||||||
|
|
||||||
let params = {
|
|
||||||
flags: 0,
|
|
||||||
location: inputLocation,
|
|
||||||
offset: 0,
|
|
||||||
limit: 1024 * 1024
|
|
||||||
};
|
|
||||||
|
|
||||||
//this.log('next small promise', params);
|
|
||||||
return apiManager.invokeApi('upload.getFile', params, {
|
|
||||||
dcID: dcID,
|
|
||||||
fileDownload: true,
|
|
||||||
noErrorBox: true
|
|
||||||
});
|
|
||||||
}, dcID);
|
|
||||||
|
|
||||||
let processDownloaded = (bytes: Uint8Array) => {
|
|
||||||
//this.log('processDownloaded', location, bytes);
|
|
||||||
|
|
||||||
if(processSticker) {
|
|
||||||
return appWebpManager.convertToPng(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve(bytes);
|
|
||||||
};
|
|
||||||
|
|
||||||
return fileStorage.getFileWriter(fileName, mimeType).then(fileWriter => {
|
|
||||||
return downloadPromise.then((result: any) => {
|
|
||||||
return processDownloaded(result.bytes).then((proccessedResult) => {
|
|
||||||
return FileManager.write(fileWriter, proccessedResult).then(() => {
|
|
||||||
return this.cachedDownloads[fileName] = fileWriter.finalize();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public getDownloadedFile(location: any) {
|
|
||||||
var fileStorage = this.getFileStorage();
|
|
||||||
var fileName = typeof(location) !== 'string' ? this.getFileName(location) : location;
|
|
||||||
|
|
||||||
//console.log('getDownloadedFile', location, fileName);
|
|
||||||
|
|
||||||
return fileStorage.getFile(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* public getIndexedKeys() {
|
|
||||||
this.keysLoaded = true;
|
|
||||||
this.getFileStorage().getAllKeys().then(keys => {
|
|
||||||
this.indexedKeys.clear();
|
|
||||||
this.indexedKeys = new Set(keys);
|
|
||||||
});
|
|
||||||
} */
|
|
||||||
|
|
||||||
public downloadFile(dcID: number, location: any, size: number, options: Partial<{
|
|
||||||
mimeType: string,
|
|
||||||
toFileEntry: any,
|
|
||||||
limitPart: number,
|
|
||||||
stickerType: number,
|
|
||||||
processPart: (bytes: Uint8Array, offset: number, queue: Delayed[]) => Promise<any>
|
|
||||||
}> = {}): CancellablePromise<Blob> {
|
|
||||||
if(!FileManager.isAvailable()) {
|
|
||||||
return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if(!this.keysLoaded) {
|
|
||||||
this.getIndexedKeys();
|
|
||||||
} */
|
|
||||||
|
|
||||||
let processSticker = false;
|
let processSticker = false;
|
||||||
if(options.stickerType == 1 && !appWebpManager.isSupported()) {
|
if(options.stickerType == 1 && !appWebpManager.isSupported()) {
|
||||||
@ -295,12 +121,12 @@ export class ApiFileManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this.log('Dload file', dcID, location, size)
|
// this.log('Dload file', dcID, location, size)
|
||||||
const fileName = this.getFileName(location, options);
|
const fileName = getFileNameByLocation(location);
|
||||||
const toFileEntry = options.toFileEntry || null;
|
const toFileEntry = options.toFileEntry || null;
|
||||||
const cachedPromise = this.cachedSavePromises[fileName] || this.cachedDownloadPromises[fileName];
|
const cachedPromise = this.cachedDownloadPromises[fileName];
|
||||||
const fileStorage = this.getFileStorage();
|
const fileStorage = this.getFileStorage();
|
||||||
|
|
||||||
//this.log('downloadFile', fileStorage.name, fileName, fileName.length, location, arguments);
|
//this.log('downloadFile', fileName, fileName.length, location, arguments);
|
||||||
|
|
||||||
if(cachedPromise) {
|
if(cachedPromise) {
|
||||||
if(toFileEntry) {
|
if(toFileEntry) {
|
||||||
@ -317,9 +143,9 @@ export class ApiFileManager {
|
|||||||
this.log('downloadFile need to deleteFile, wrong size:', blob.size, size);
|
this.log('downloadFile need to deleteFile, wrong size:', blob.size, size);
|
||||||
|
|
||||||
return this.deleteFile(fileName).then(() => {
|
return this.deleteFile(fileName).then(() => {
|
||||||
return this.downloadFile(dcID, location, size, options);
|
return this.downloadFile(options);
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
return this.downloadFile(dcID, location, size, options);
|
return this.downloadFile(options);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return blob;
|
return blob;
|
||||||
@ -346,7 +172,7 @@ export class ApiFileManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fileStorage.getFile(fileName).then(async(blob: Blob) => {
|
fileStorage.getFile(fileName).then(async(blob: Blob) => {
|
||||||
//this.log('is that i wanted');
|
//this.log('maybe cached', fileName);
|
||||||
//throw '';
|
//throw '';
|
||||||
|
|
||||||
if(blob.size < size) {
|
if(blob.size < size) {
|
||||||
@ -358,10 +184,10 @@ export class ApiFileManager {
|
|||||||
if(toFileEntry) {
|
if(toFileEntry) {
|
||||||
FileManager.copy(blob, toFileEntry).then(deferred.resolve, errorHandler);
|
FileManager.copy(blob, toFileEntry).then(deferred.resolve, errorHandler);
|
||||||
} else {
|
} else {
|
||||||
deferred.resolve(this.cachedDownloads[fileName] = blob);
|
deferred.resolve(blob);
|
||||||
}
|
}
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
//this.log('not i wanted');
|
//this.log('not cached', fileName);
|
||||||
//var fileWriterPromise = toFileEntry ? FileManager.getFileWriter(toFileEntry) : fileStorage.getFileWriter(fileName, mimeType);
|
//var fileWriterPromise = toFileEntry ? FileManager.getFileWriter(toFileEntry) : fileStorage.getFileWriter(fileName, mimeType);
|
||||||
const fileWriterPromise = toFileEntry ? Promise.resolve(toFileEntry) : fileStorage.getFileWriter(fileName, mimeType);
|
const fileWriterPromise = toFileEntry ? Promise.resolve(toFileEntry) : fileStorage.getFileWriter(fileName, mimeType);
|
||||||
|
|
||||||
@ -374,6 +200,10 @@ export class ApiFileManager {
|
|||||||
writeFileDeferred: CancellablePromise<unknown>;
|
writeFileDeferred: CancellablePromise<unknown>;
|
||||||
const maxRequests = options.processPart ? 5 : 5;
|
const maxRequests = options.processPart ? 5 : 5;
|
||||||
|
|
||||||
|
if(!size) {
|
||||||
|
size = limit;
|
||||||
|
}
|
||||||
|
|
||||||
if(fileWriter.length) {
|
if(fileWriter.length) {
|
||||||
startOffset = fileWriter.length;
|
startOffset = fileWriter.length;
|
||||||
|
|
||||||
@ -381,7 +211,7 @@ export class ApiFileManager {
|
|||||||
if(toFileEntry) {
|
if(toFileEntry) {
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
} else {
|
} else {
|
||||||
deferred.resolve(this.cachedDownloads[fileName] = fileWriter.finalize());
|
deferred.resolve(fileWriter.finalize());
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -475,7 +305,7 @@ export class ApiFileManager {
|
|||||||
if(toFileEntry) {
|
if(toFileEntry) {
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
} else {
|
} else {
|
||||||
deferred.resolve(this.cachedDownloads[fileName] = fileWriter.finalize());
|
deferred.resolve(fileWriter.finalize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
@ -511,11 +341,7 @@ export class ApiFileManager {
|
|||||||
|
|
||||||
public deleteFile(fileName: string) {
|
public deleteFile(fileName: string) {
|
||||||
//this.log('will delete file:', fileName);
|
//this.log('will delete file:', fileName);
|
||||||
|
|
||||||
delete this.cachedDownloadPromises[fileName];
|
delete this.cachedDownloadPromises[fileName];
|
||||||
delete this.cachedDownloads[fileName];
|
|
||||||
delete this.cachedSavePromises[fileName];
|
|
||||||
|
|
||||||
return this.getFileStorage().deleteFile(fileName);
|
return this.getFileStorage().deleteFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,4 +464,9 @@ export class ApiFileManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new ApiFileManager();
|
const apiFileManager = new ApiFileManager();
|
||||||
|
// @ts-ignore
|
||||||
|
if(process.env.NODE_ENV != 'production') {
|
||||||
|
(self as any).apiFileManager = apiFileManager;
|
||||||
|
}
|
||||||
|
export default apiFileManager;
|
||||||
|
@ -6,6 +6,7 @@ import apiManager from "./apiManager";
|
|||||||
import AppStorage from '../storage';
|
import AppStorage from '../storage';
|
||||||
import cryptoWorker from "../crypto/cryptoworker";
|
import cryptoWorker from "../crypto/cryptoworker";
|
||||||
import networkerFactory from "./networkerFactory";
|
import networkerFactory from "./networkerFactory";
|
||||||
|
import apiFileManager from './apiFileManager';
|
||||||
|
|
||||||
const ctx = self as any as ServiceWorkerGlobalScope;
|
const ctx = self as any as ServiceWorkerGlobalScope;
|
||||||
|
|
||||||
@ -85,14 +86,16 @@ networkerFactory.setUpdatesProcessor((obj, bool) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
listeners[0].postMessage({update: {obj, bool}});
|
listeners.forEach(listener => {
|
||||||
|
listener.postMessage({update: {obj, bool}});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.addEventListener('message', async(e) => {
|
ctx.addEventListener('message', async(e) => {
|
||||||
const taskID = e.data.taskID;
|
const taskID = e.data.taskID;
|
||||||
|
|
||||||
console.log('[SW] Got message:', taskID, e, e.data);
|
//console.log('[SW] Got message:', taskID, e, e.data);
|
||||||
|
|
||||||
if(e.data.useLs) {
|
if(e.data.useLs) {
|
||||||
AppStorage.finishTask(e.data.taskID, e.data.args);
|
AppStorage.finishTask(e.data.taskID, e.data.args);
|
||||||
@ -107,6 +110,24 @@ ctx.addEventListener('message', async(e) => {
|
|||||||
respond(e.source, {taskID: taskID, result: result});
|
respond(e.source, {taskID: taskID, result: result});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
case 'downloadFile': {
|
||||||
|
/* // @ts-ignore
|
||||||
|
return apiFileManager.downloadFile(...e.data.args); */
|
||||||
|
|
||||||
|
try {
|
||||||
|
// @ts-ignore
|
||||||
|
let result = apiFileManager[e.data.task].apply(apiFileManager, e.data.args);
|
||||||
|
|
||||||
|
if(result instanceof Promise) {
|
||||||
|
result = await result;
|
||||||
|
}
|
||||||
|
|
||||||
|
respond(e.source, {taskID: taskID, result: result});
|
||||||
|
} catch(err) {
|
||||||
|
respond(e.source, {taskID: taskID, error: err});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
try {
|
try {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -151,3 +172,104 @@ ctx.addEventListener('activate', (event) => {
|
|||||||
|
|
||||||
event.waitUntil(ctx.clients.claim());
|
event.waitUntil(ctx.clients.claim());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function timeout(delay: number): Promise<Response> {
|
||||||
|
return new Promise(((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve(new Response('', {
|
||||||
|
status: 408,
|
||||||
|
statusText: 'Request timed out.',
|
||||||
|
}));
|
||||||
|
}, delay);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch requests
|
||||||
|
*/
|
||||||
|
ctx.addEventListener('fetch', (event: FetchEvent): void => {
|
||||||
|
const [, url, scope, fileName] = /http[:s]+\/\/.*?(\/(.*?)(?:$|\/(.*)$))/.exec(event.request.url) || [];
|
||||||
|
|
||||||
|
//console.log('[SW] fetch:', event, event.request, url, scope, fileName);
|
||||||
|
|
||||||
|
switch(scope) {
|
||||||
|
case 'thumb':
|
||||||
|
case 'document':
|
||||||
|
case 'photo': {
|
||||||
|
const info = JSON.parse(decodeURIComponent(fileName));
|
||||||
|
|
||||||
|
//console.log('[SW] fetch cachedDownloadPromises:', info/* apiFileManager.cachedDownloadPromises, apiFileManager.cachedDownloadPromises.hasOwnProperty(fileName) */);
|
||||||
|
|
||||||
|
const promise = apiFileManager.downloadFile(info).then(b => new Response(b));
|
||||||
|
event.respondWith(promise);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'upload': {
|
||||||
|
if(event.request.method == 'POST') {
|
||||||
|
event.respondWith(event.request.blob().then(blob => {
|
||||||
|
return apiFileManager.uploadFile(blob).then(v => new Response(JSON.stringify(v), {headers: {'Content-Type': 'application/json'}}));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* default: {
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'documents':
|
||||||
|
case 'photos':
|
||||||
|
case 'profiles':
|
||||||
|
// direct download
|
||||||
|
if (event.request.method === 'POST') {
|
||||||
|
event.respondWith(// download(url, 'unknown file.txt', getFilePartRequest));
|
||||||
|
event.request.text()
|
||||||
|
.then((text) => {
|
||||||
|
const [, filename] = text.split('=');
|
||||||
|
return download(url, filename ? filename.toString() : 'unknown file', getFilePartRequest);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// inline
|
||||||
|
} else {
|
||||||
|
event.respondWith(
|
||||||
|
ctx.cache.match(url).then((cached) => {
|
||||||
|
if (cached) return cached;
|
||||||
|
|
||||||
|
return Promise.race([
|
||||||
|
timeout(45 * 1000), // safari fix
|
||||||
|
new Promise<Response>((resolve) => {
|
||||||
|
fetchRequest(url, resolve, getFilePartRequest, ctx.cache, fileProgress);
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'stream': {
|
||||||
|
const [offset, end] = parseRange(event.request.headers.get('Range') || '');
|
||||||
|
|
||||||
|
log('stream', url, offset, end);
|
||||||
|
|
||||||
|
event.respondWith(new Promise((resolve) => {
|
||||||
|
fetchStreamRequest(url, offset, end, resolve, getFilePartRequest);
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'stripped':
|
||||||
|
case 'cached': {
|
||||||
|
const bytes = getThumb(url) || null;
|
||||||
|
event.respondWith(new Response(bytes, { headers: { 'Content-Type': 'image/jpg' } }));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (url && url.endsWith('.tgs')) event.respondWith(fetchTGS(url));
|
||||||
|
else event.respondWith(fetch(event.request.url)); */
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -2,6 +2,7 @@ import {dT, isObject, $rootScope} from '../utils';
|
|||||||
import AppStorage from '../storage';
|
import AppStorage from '../storage';
|
||||||
import CryptoWorkerMethods from '../crypto/crypto_methods';
|
import CryptoWorkerMethods from '../crypto/crypto_methods';
|
||||||
import runtime from 'serviceworker-webpack-plugin/lib/runtime';
|
import runtime from 'serviceworker-webpack-plugin/lib/runtime';
|
||||||
|
import { InputFileLocation, FileLocation } from '../../types';
|
||||||
|
|
||||||
type Task = {
|
type Task = {
|
||||||
taskID: number,
|
taskID: number,
|
||||||
@ -45,14 +46,14 @@ class ApiManagerProxy extends CryptoWorkerMethods {
|
|||||||
this.releasePending();
|
this.releasePending();
|
||||||
});
|
});
|
||||||
|
|
||||||
navigator.serviceWorker.oncontrollerchange = () => {
|
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
||||||
console.error('oncontrollerchange');
|
console.warn(dT(), 'ApiManagerProxy controllerchange');
|
||||||
this.releasePending();
|
this.releasePending();
|
||||||
|
|
||||||
navigator.serviceWorker.controller.addEventListener('error', (e) => {
|
navigator.serviceWorker.controller.addEventListener('error', (e) => {
|
||||||
console.error('controller error:', e);
|
console.error('controller error:', e);
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message resolver
|
* Message resolver
|
||||||
@ -75,41 +76,6 @@ class ApiManagerProxy extends CryptoWorkerMethods {
|
|||||||
this.finalizeTask(e.data.taskID, e.data.result, e.data.error);
|
this.finalizeTask(e.data.taskID, e.data.result, e.data.error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* if(window.Worker) {
|
|
||||||
import('./mtproto_service.js').then((worker: any) => {
|
|
||||||
var tmpWorker = new worker.default();
|
|
||||||
tmpWorker.onmessage = (e: any) => {
|
|
||||||
if(!this.webWorker) {
|
|
||||||
this.webWorker = tmpWorker;
|
|
||||||
console.info(dT(), 'ApiManagerProxy set webWorker');
|
|
||||||
this.releasePending();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!isObject(e.data)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(e.data.useLs) {
|
|
||||||
// @ts-ignore
|
|
||||||
AppStorage[e.data.task](...e.data.args).then(res => {
|
|
||||||
(this.webWorker as Worker).postMessage({useLs: true, taskID: e.data.taskID, args: res});
|
|
||||||
});
|
|
||||||
} else if(e.data.update) {
|
|
||||||
if(this.updatesProcessor) {
|
|
||||||
this.updatesProcessor(e.data.update.obj, e.data.update.bool);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.finalizeTask(e.data.taskID, e.data.result, e.data.error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
tmpWorker.onerror = (error: any) => {
|
|
||||||
console.error('ApiManagerProxy error', error);
|
|
||||||
this.webWorker = false;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private finalizeTask(taskID: number, result: any, error: any) {
|
private finalizeTask(taskID: number, result: any, error: any) {
|
||||||
@ -127,13 +93,12 @@ class ApiManagerProxy extends CryptoWorkerMethods {
|
|||||||
return new Promise<T>((resolve, reject) => {
|
return new Promise<T>((resolve, reject) => {
|
||||||
this.awaiting[this.taskID] = {resolve, reject, taskName: task};
|
this.awaiting[this.taskID] = {resolve, reject, taskName: task};
|
||||||
|
|
||||||
let params = {
|
const params = {
|
||||||
task,
|
task,
|
||||||
taskID: this.taskID,
|
taskID: this.taskID,
|
||||||
args
|
args
|
||||||
};
|
};
|
||||||
|
|
||||||
//(this.webWorker as Worker).postMessage(params);
|
|
||||||
this.pending.push(params);
|
this.pending.push(params);
|
||||||
this.releasePending();
|
this.releasePending();
|
||||||
|
|
||||||
@ -194,6 +159,15 @@ class ApiManagerProxy extends CryptoWorkerMethods {
|
|||||||
public logOut(): Promise<void> {
|
public logOut(): Promise<void> {
|
||||||
return this.performTaskWorker('logOut');
|
return this.performTaskWorker('logOut');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public downloadFile(dcID: number, location: InputFileLocation | FileLocation, size: number = 0, options: Partial<{
|
||||||
|
mimeType: string,
|
||||||
|
toFileEntry: any,
|
||||||
|
limitPart: number,
|
||||||
|
stickerType: number
|
||||||
|
}> = {}): Promise<Blob> {
|
||||||
|
return this.performTaskWorker('downloadFile', dcID, location, size, options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiManagerProxy = new ApiManagerProxy();
|
const apiManagerProxy = new ApiManagerProxy();
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
|
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
|
||||||
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { InputFileLocation, FileLocation } from "../types";
|
||||||
|
|
||||||
var _logTimer = Date.now();
|
var _logTimer = Date.now();
|
||||||
export function dT () {
|
export function dT () {
|
||||||
return '[' + ((Date.now() - _logTimer) / 1000).toFixed(3) + ']';
|
return '[' + ((Date.now() - _logTimer) / 1000).toFixed(3) + ']';
|
||||||
@ -519,3 +522,17 @@ export function getEmojiToneIndex(input: string) {
|
|||||||
let match = input.match(/[\uDFFB-\uDFFF]/);
|
let match = input.match(/[\uDFFB-\uDFFF]/);
|
||||||
return match ? 5 - (57343 - match[0].charCodeAt(0)) : 0;
|
return match ? 5 - (57343 - match[0].charCodeAt(0)) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getFileURL(type: 'photo' | 'thumb' | 'document', options: {
|
||||||
|
dcID: number,
|
||||||
|
location: InputFileLocation | FileLocation,
|
||||||
|
size?: number,
|
||||||
|
mimeType?: string
|
||||||
|
}) {
|
||||||
|
//console.log('getFileURL', location);
|
||||||
|
//const perf = performance.now();
|
||||||
|
const encoded = encodeURIComponent(JSON.stringify(options));
|
||||||
|
//console.log('getFileURL encode:', performance.now() - perf, encoded);
|
||||||
|
|
||||||
|
return '/' + type + '/' + encoded;
|
||||||
|
}
|
||||||
|
44
src/types.d.ts
vendored
44
src/types.d.ts
vendored
@ -41,7 +41,7 @@ export type MTPhotoSize = {
|
|||||||
h?: number,
|
h?: number,
|
||||||
size?: number,
|
size?: number,
|
||||||
type?: string, // i, m, x, y, w by asc
|
type?: string, // i, m, x, y, w by asc
|
||||||
location?: any,
|
location?: FileLocation,
|
||||||
bytes?: Uint8Array // if type == 'i'
|
bytes?: Uint8Array // if type == 'i'
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -88,3 +88,45 @@ export type AccountPassword = {
|
|||||||
srp_id?: string,
|
srp_id?: string,
|
||||||
secure_random: Uint8Array,
|
secure_random: Uint8Array,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type FileLocation = {
|
||||||
|
_: 'fileLocationToBeDeprecated',
|
||||||
|
volume_id: string,
|
||||||
|
local_id: number
|
||||||
|
};
|
||||||
|
|
||||||
|
export type inputFileLocation = {
|
||||||
|
_: 'inputFileLocation',
|
||||||
|
volume_id: string,
|
||||||
|
local_id: number,
|
||||||
|
secret: string,
|
||||||
|
file_reference: Uint8Array | number[]
|
||||||
|
};
|
||||||
|
|
||||||
|
export type inputDocumentFileLocation = {
|
||||||
|
_: 'inputDocumentFileLocation',
|
||||||
|
id: string,
|
||||||
|
access_hash: string,
|
||||||
|
file_reference: Uint8Array | number[],
|
||||||
|
thumb_size: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export type inputPhotoFileLocation = Omit<inputDocumentFileLocation, '_'> & {_: 'inputPhotoFileLocation'};
|
||||||
|
|
||||||
|
export type inputPeerPhotoFileLocation = {
|
||||||
|
_: 'inputPeerPhotoFileLocation',
|
||||||
|
flags: number,
|
||||||
|
big?: true,
|
||||||
|
peer: any,
|
||||||
|
volume_id: string,
|
||||||
|
local_id: number
|
||||||
|
};
|
||||||
|
|
||||||
|
export type inputStickerSetThumb = {
|
||||||
|
_: 'inputStickerSetThumb',
|
||||||
|
stickerset: any,
|
||||||
|
volume_id: string,
|
||||||
|
local_id: number
|
||||||
|
};
|
||||||
|
|
||||||
|
export type InputFileLocation = inputFileLocation | inputDocumentFileLocation | inputPhotoFileLocation | inputPeerPhotoFileLocation | inputStickerSetThumb;
|
Loading…
Reference in New Issue
Block a user