Browse Source

ESG GIFs try

Websocket fix instant connect retry
Possible fix to stream FILE_REFERENCE_EXPIRED
master
morethanwords 4 years ago
parent
commit
097a55850c
  1. 22
      src/components/emoticonsDropdown/index.ts
  2. 8
      src/components/emoticonsDropdown/tabs/gifs.ts
  3. 18
      src/components/emoticonsDropdown/tabs/stickers.ts
  4. 10
      src/components/gifsMasonry.ts
  5. 2
      src/components/sidebarRight/forward.ts
  6. 9
      src/components/sidebarRight/sharedMedia.ts
  7. 10
      src/components/wrappers.ts
  8. 21
      src/lib/appManagers/appDownloadManager.ts
  9. 2
      src/lib/appManagers/appStickersManager.ts
  10. 2
      src/lib/crypto/crypto_utils.ts
  11. 9
      src/lib/mtproto/mtproto.service.ts
  12. 6
      src/lib/mtproto/mtproto.worker.ts
  13. 28
      src/lib/mtproto/mtprotoworker.ts
  14. 29
      src/lib/mtproto/referenceDatabase.ts
  15. 12
      src/lib/mtproto/transports/websocket.ts
  16. 10
      src/scss/partials/_rightSidebar.scss
  17. 2
      src/scss/style.scss
  18. 5
      src/types.d.ts

22
src/components/emoticonsDropdown/index.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import LazyLoadQueue from "../lazyLoadQueue";
import LazyLoadQueue, { LazyLoadQueueIntersector } from "../lazyLoadQueue";
import GifsTab from "./tabs/gifs";
import { findUpClassName, findUpTag, whichChild } from "../../lib/utils";
import { horizontalMenu } from "../horizontalMenu";
@ -324,6 +324,26 @@ export class EmoticonsDropdown { @@ -324,6 +324,26 @@ export class EmoticonsDropdown {
console.warn('got no doc by id:', fileID);
}
};
public addLazyLoadQueueRepeat(lazyLoadQueue: LazyLoadQueueIntersector, processInvisibleDiv: (div: HTMLElement) => void) {
this.events.onClose.push(() => {
lazyLoadQueue.lock();
});
this.events.onCloseAfter.push(() => {
const divs = lazyLoadQueue.intersector.getVisible();
for(const div of divs) {
processInvisibleDiv(div);
}
lazyLoadQueue.intersector.clearVisible();
});
this.events.onOpenAfter.push(() => {
lazyLoadQueue.unlockAndRefresh();
});
}
}
const emoticonsDropdown = new EmoticonsDropdown();

8
src/components/emoticonsDropdown/tabs/gifs.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import { EmoticonsDropdown, EmoticonsTab, EMOTICONSSTICKERGROUP } from "..";
import emoticonsDropdown, { EmoticonsDropdown, EmoticonsTab, EMOTICONSSTICKERGROUP } from "..";
import GifsMasonry from "../../gifsMasonry";
import Scrollable from "../../scrollable_new";
import { putPreloader } from "../../misc";
@ -24,15 +24,15 @@ export default class GifsTab implements EmoticonsTab { @@ -24,15 +24,15 @@ export default class GifsTab implements EmoticonsTab {
res.gifs.forEach((doc, idx) => {
res.gifs[idx] = doc = appDocsManager.saveDoc(doc);
//if(doc._ == 'documentEmpty') return;
//masonry.add(doc as MyDocument);
masonry.add(doc as MyDocument);
});
}
//let line: MTDocument[] = [];
preloader.remove();
});
emoticonsDropdown.addLazyLoadQueueRepeat(masonry.lazyLoadQueue, masonry.processInvisibleDiv);
this.init = null;
}

18
src/components/emoticonsDropdown/tabs/stickers.ts

@ -321,23 +321,7 @@ export default class StickersTab implements EmoticonsTab { @@ -321,23 +321,7 @@ export default class StickersTab implements EmoticonsTab {
}
});
emoticonsDropdown.events.onClose.push(() => {
this.lazyLoadQueue.lock();
});
emoticonsDropdown.events.onCloseAfter.push(() => {
const divs = this.lazyLoadQueue.intersector.getVisible();
for(const div of divs) {
this.processInvisibleDiv(div);
}
this.lazyLoadQueue.intersector.clearVisible();
});
emoticonsDropdown.events.onOpenAfter.push(() => {
this.lazyLoadQueue.unlockAndRefresh();
});
emoticonsDropdown.addLazyLoadQueueRepeat(this.lazyLoadQueue, this.processInvisibleDiv);
/* setInterval(() => {
// @ts-ignore

10
src/components/gifsMasonry.ts

@ -24,14 +24,14 @@ export default class GifsMasonry { @@ -24,14 +24,14 @@ export default class GifsMasonry {
}
});
setInterval(() => {
/* setInterval(() => {
// @ts-ignore
const players = animationIntersector.byGroups[group];
if(players) {
console.log(`GIFS RENDERED IN ${group}:`, players.length, players.filter(p => !p.animation.paused).length, this.lazyLoadQueue.intersector.getVisible().length);
}
}, .25e3);
}, .25e3); */
let timeout = 0;
// memory leak
@ -51,12 +51,14 @@ export default class GifsMasonry { @@ -51,12 +51,14 @@ export default class GifsMasonry {
});
}
private processVisibleDiv = (div: HTMLElement) => {
processVisibleDiv = (div: HTMLElement) => {
const video = div.querySelector('video');
if(video) {
return;
}
//console.log('processVisibleDiv');
const load = () => {
const docID = div.dataset.docID;
const doc = appDocsManager.getDoc(docID);
@ -110,7 +112,7 @@ export default class GifsMasonry { @@ -110,7 +112,7 @@ export default class GifsMasonry {
this.lazyLoadQueue.push({div, load});
};
private processInvisibleDiv = async(div: HTMLElement) => {
processInvisibleDiv = async(div: HTMLElement) => {
return this.scrollPromise.then(async() => {
//return;

2
src/components/sidebarRight/forward.ts

@ -13,6 +13,7 @@ export default class AppForwardTab implements SliderTab { @@ -13,6 +13,7 @@ export default class AppForwardTab implements SliderTab {
private msgIDs: number[] = [];
onCloseAfterTimeout() {
document.body.classList.remove('is-forward-active');
this.cleanup();
}
@ -79,6 +80,7 @@ export default class AppForwardTab implements SliderTab { @@ -79,6 +80,7 @@ export default class AppForwardTab implements SliderTab {
//console.log('forward rendered:', this.container.querySelector('.selector ul').childElementCount);
appSidebarRight.selectTab(AppSidebarRight.SLIDERITEMSIDS.forward);
appSidebarRight.toggleSidebar(true);
document.body.classList.add('is-forward-active');
});
}
}

9
src/components/sidebarRight/sharedMedia.ts

@ -263,17 +263,10 @@ export default class AppSharedMediaTab implements SliderTab { @@ -263,17 +263,10 @@ export default class AppSharedMediaTab implements SliderTab {
case 'inputMessagesFilterDocument': {
for(let message of messages) {
if(!message.media.document || ['voice', 'audio', 'gif'].includes(message.media.document.type)) {
if(!message.media.document || ['voice', 'audio', 'gif', 'sticker'].includes(message.media.document.type)) {
continue;
}
let doc = message.media.document;
if(doc.attributes) {
if(doc.attributes.find((a: any) => a._ == "documentAttributeSticker")) {
continue;
}
}
filtered.push(message);
}
break;

10
src/components/wrappers.ts

@ -234,7 +234,15 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai @@ -234,7 +234,15 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
}, {once: true});
//}
video.addEventListener('error', deferred.reject);
video.addEventListener('error', (e) => {
deferred.resolve();
/* console.error('video error', e, video.src);
if(video.src) { // if wasn't cleaned
deferred.reject(e);
} else {
deferred.resolve();
} */
});
//if(doc.type != 'round') {
renderImageFromUrl(video, doc.url);

21
src/lib/appManagers/appDownloadManager.ts

@ -5,7 +5,7 @@ import type { DownloadOptions } from "../mtproto/apiFileManager"; @@ -5,7 +5,7 @@ import type { DownloadOptions } from "../mtproto/apiFileManager";
import { getFileNameByLocation } from "../bin_utils";
import { InputFile } from "../../layer";
import referenceDatabase, {ReferenceBytes} from "../mtproto/referenceDatabase";
import appMessagesManager from "./appMessagesManager";
import type { ApiError } from "../mtproto/apiManager";
export type ResponseMethodBlob = 'blob';
export type ResponseMethodJson = 'json';
@ -77,30 +77,17 @@ export class AppDownloadManager { @@ -77,30 +77,17 @@ export class AppDownloadManager {
const deferred = this.getNewDeferred(fileName);
const onError = (err: any) => {
const onError = (err: ApiError) => {
switch(err.type) {
case 'FILE_REFERENCE_EXPIRED': {
// @ts-ignore
const bytes: ReferenceBytes = options?.location?.file_reference;
if(bytes) {
const context = referenceDatabase.getContext(bytes);
switch(context?.type) {
case 'message': {
return appMessagesManager.wrapSingleMessage(context.messageID, true).then(() => {
//console.log('FILE_REFERENCE_EXPIRED: got message', context, options, appMessagesManager.getMessage(context.messageID).media);
return tryDownload();
});
}
default: {
console.warn('FILE_REFERENCE_EXPIRED: not implemented context', context);
}
}
referenceDatabase.refreshReference(bytes).then(tryDownload);
break;
} else {
console.warn('FILE_REFERENCE_EXPIRED: no context for bytes:', bytes);
}
break;
}
default:

2
src/lib/appManagers/appStickersManager.ts

@ -6,6 +6,8 @@ import { Modify } from '../../types'; @@ -6,6 +6,8 @@ import { Modify } from '../../types';
import appStateManager from './appStateManager';
import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
// TODO: если пак будет сохранён и потом обновлён, то недостающие стикеры не подгрузит
export class AppStickersManager {
private stickerSets: {
[stickerSetID: string]: MessagesStickerSet

2
src/lib/crypto/crypto_utils.ts

@ -29,7 +29,7 @@ export function longToBytes(sLong: string) { @@ -29,7 +29,7 @@ export function longToBytes(sLong: string) {
}
console.log('longToBytes LEEMON', sLong, performance.now() - perf); */
const bytes = bigInt2bytes(str2bigInt(sLong, 10), false);
const bytes = addPadding(bigInt2bytes(str2bigInt(sLong, 10), false), 8, true, false, false);
//console.log('longToBytes', bytes, b);
return bytes;

9
src/lib/mtproto/mtproto.service.ts

@ -15,10 +15,10 @@ ctx.addEventListener('message', (e) => { @@ -15,10 +15,10 @@ ctx.addEventListener('message', (e) => {
const task = e.data as ServiceWorkerTaskResponse;
const promise = deferredPromises[task.id];
if(task.payload) {
promise.resolve(task.payload);
if(task.error) {
promise.reject(task.error);
} else {
promise.reject();
promise.resolve(task.payload);
}
delete deferredPromises[task.id];
@ -33,7 +33,8 @@ export interface ServiceWorkerTask extends WorkerTaskTemplate { @@ -33,7 +33,8 @@ export interface ServiceWorkerTask extends WorkerTaskTemplate {
export interface ServiceWorkerTaskResponse extends WorkerTaskTemplate {
type: 'requestFilePart',
payload: UploadFile.uploadFile
payload?: UploadFile.uploadFile,
originalPayload?: ServiceWorkerTask['payload']
};
const onFetch = (event: FetchEvent): void => {

6
src/lib/mtproto/mtproto.worker.ts

@ -82,15 +82,15 @@ ctx.addEventListener('message', async(e) => { @@ -82,15 +82,15 @@ ctx.addEventListener('message', async(e) => {
const task = e.data as ServiceWorkerTask;
const responseTask: ServiceWorkerTaskResponse = {
type: task.type,
id: task.id,
payload: null
id: task.id
};
try {
const res = await apiFileManager.requestFilePart(...task.payload);
responseTask.payload = res;
} catch(err) {
responseTask.originalPayload = task.payload;
responseTask.error = err;
}
respond(responseTask);

28
src/lib/mtproto/mtprotoworker.ts

@ -9,6 +9,8 @@ import type { ServiceWorkerTask, ServiceWorkerTaskResponse } from './mtproto.ser @@ -9,6 +9,8 @@ import type { ServiceWorkerTask, ServiceWorkerTaskResponse } from './mtproto.ser
import { MethodDeclMap } from '../../layer';
import { MOUNT_CLASS_TO } from './mtproto_config';
import $rootScope from '../rootScope';
import referenceDatabase from './referenceDatabase';
import { ApiError } from './apiManager';
type Task = {
taskID: number,
@ -126,7 +128,31 @@ class ApiManagerProxy extends CryptoWorkerMethods { @@ -126,7 +128,31 @@ class ApiManagerProxy extends CryptoWorkerMethods {
} else if(task.type == 'convertWebp') {
webpWorkerController.postMessage(task);
} else if((task as ServiceWorkerTaskResponse).type == 'requestFilePart') {
const _task = task as ServiceWorkerTaskResponse;
if(_task.error) {
const onError = (error: ApiError) => {
if(error?.type == 'FILE_REFERENCE_EXPIRED') {
// @ts-ignore
const bytes = _task.originalPayload[1].file_reference;
referenceDatabase.refreshReference(bytes).then(() => {
const newTask: ServiceWorkerTask = {
type: _task.type,
id: _task.id,
payload: _task.originalPayload
};
this.postMessage(newTask);
}).catch(onError);
} else {
navigator.serviceWorker.controller.postMessage(task);
}
};
onError(_task.error);
} else {
navigator.serviceWorker.controller.postMessage(task);
}
} else {
this.finalizeTask(task.taskID, task.result, task.error);
}
@ -137,7 +163,7 @@ class ApiManagerProxy extends CryptoWorkerMethods { @@ -137,7 +163,7 @@ class ApiManagerProxy extends CryptoWorkerMethods {
const deferred = this.awaiting[taskID];
if(deferred !== undefined) {
this.log.debug('done', deferred.taskName, result, error);
result === undefined ? deferred.reject(error) : deferred.resolve(result);
error ? deferred.reject(error) : deferred.resolve(result);
delete this.awaiting[taskID];
}
}

29
src/lib/mtproto/referenceDatabase.ts

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
import appMessagesManager from "../appManagers/appMessagesManager";
import { Photo } from "../../layer";
import { deepEqual } from "../utils";
import { MOUNT_CLASS_TO } from "./mtproto_config";
@ -57,6 +58,34 @@ class ReferenceDatabase { @@ -57,6 +58,34 @@ class ReferenceDatabase {
return false;
}
public refreshReference(reference: ReferenceBytes): Promise<void> {
const context = this.getContext(reference);
switch(context?.type) {
case 'message': {
return appMessagesManager.wrapSingleMessage(context.messageID, true);
// .then(() => {
// console.log('FILE_REFERENCE_EXPIRED: got message', context, options, appMessagesManager.getMessage(context.messageID).media);
// });
}
default: {
console.warn('FILE_REFERENCE_EXPIRED: not implemented context', context);
return Promise.reject();
}
}
}
/* handleReferenceError = (reference: ReferenceBytes, error: ApiError) => {
switch(error.type) {
case 'FILE_REFERENCE_EXPIRED': {
return this.refreshReference(reference);
}
default:
return Promise.reject(error);
}
}; */
/* public replaceReference(oldReference: ReferenceBytes, newReference: ReferenceBytes) {
const contexts = this.contexts.get(oldReference);
if(contexts) {

12
src/lib/mtproto/transports/websocket.ts

@ -107,6 +107,8 @@ export class Obfuscation { @@ -107,6 +107,8 @@ export class Obfuscation {
}
}
const CONNECTION_RETRY_TIMEOUT = 30000;
export default class Socket extends MTTransport {
ws: WebSocket;
@ -129,6 +131,8 @@ export default class Socket extends MTTransport { @@ -129,6 +131,8 @@ export default class Socket extends MTTransport {
codec = intermediatePacketCodec;
lastCloseTime: number;
constructor(dcID: number, url: string) {
super(dcID, url);
@ -169,13 +173,20 @@ export default class Socket extends MTTransport { @@ -169,13 +173,20 @@ export default class Socket extends MTTransport {
this.log('closed', event, this.pending);
this.connected = false;
const time = Date.now();
const diff = time - this.lastCloseTime;
let needTimeout = !isNaN(diff) && diff < CONNECTION_RETRY_TIMEOUT ? CONNECTION_RETRY_TIMEOUT - diff : 0;
//this.pending.length = 0;
/* if(this.networker) {
this.networker.resend();
this.networker.cleanupSent();
} */
this.log('will try to reconnect after timeout:', needTimeout / 1000);
setTimeout(() => {
this.log('trying to reconnect...');
this.lastCloseTime = Date.now();
this.connect();
for(let pending of this.pending) {
@ -190,6 +201,7 @@ export default class Socket extends MTTransport { @@ -190,6 +201,7 @@ export default class Socket extends MTTransport {
this.networker.cleanupSent();
}, {once: true});
}
}, needTimeout);
};
handleMessage = (event: MessageEvent) => {

10
src/scss/partials/_rightSidebar.scss

@ -34,6 +34,10 @@ @@ -34,6 +34,10 @@
border-left: 1px solid #DADCE0;
}
body.is-forward-active & {
z-index: 4;
}
.sidebar-header {
flex: 0 0 auto;
@ -315,7 +319,10 @@ @@ -315,7 +319,10 @@
color: white;
}
.grid-item-media {
.grid-item {
overflow: hidden;
&-media {
opacity: 1;
transition: opacity .2s ease;
@ -323,6 +330,7 @@ @@ -323,6 +330,7 @@
filter: blur(7px);
}
}
}
/* span.video-play {
background-color: var(--message-time-background);

2
src/scss/style.scss

@ -1150,7 +1150,7 @@ img.emoji { @@ -1150,7 +1150,7 @@ img.emoji {
.grid-item {
height: 0;
padding-bottom: 100%;
overflow: hidden;
//overflow: hidden;
position: relative;
cursor: pointer;
user-select: none;

5
src/types.d.ts vendored

@ -1,3 +1,5 @@ @@ -1,3 +1,5 @@
import type { ApiError } from "./lib/mtproto/apiManager";
export type InvokeApiOptions = Partial<{
dcID: number,
timeout: number,
@ -20,7 +22,8 @@ export type InvokeApiOptions = Partial<{ @@ -20,7 +22,8 @@ export type InvokeApiOptions = Partial<{
export type WorkerTaskTemplate = {
type: string,
id: number,
payload: any
payload?: any,
error?: ApiError
};
export type Modify<T, R> = Omit<T, keyof R> & R;

Loading…
Cancel
Save