Rollback Safari connection
Done local forward
This commit is contained in:
parent
6de93c6fd9
commit
04442dcffa
@ -308,7 +308,7 @@ export default class ChatBubbles {
|
||||
});
|
||||
|
||||
this.listenerSetter.add(rootScope, 'album_edit', (e) => {
|
||||
fastRaf(() => {
|
||||
//fastRaf(() => { // ! can't use delayed smth here, need original bubble to be edited
|
||||
const {peerId, groupId, deletedMids} = e;
|
||||
|
||||
if(peerId !== this.peerId) return;
|
||||
@ -319,7 +319,7 @@ export default class ChatBubbles {
|
||||
const renderMaxId = getObjectKeysAndSort(this.appMessagesManager.groupedMessagesStorage[groupId], 'asc').pop();
|
||||
|
||||
this.renderMessage(this.chat.getMessage(renderMaxId), true, false, this.bubbles[renderedId], false);
|
||||
});
|
||||
//});
|
||||
});
|
||||
|
||||
this.listenerSetter.add(rootScope, 'messages_downloaded', (e) => {
|
||||
|
@ -26,7 +26,7 @@ const notifyWorker = (...args: any[]) => {
|
||||
(self as any as DedicatedWorkerGlobalScope).postMessage(...args);
|
||||
};
|
||||
|
||||
const empty = () => {};
|
||||
const noop = () => {};
|
||||
|
||||
export const notifySomeone = isServiceWorker ? notifyServiceWorker.bind(null, false) : (isWebWorker ? notifyWorker : empty);
|
||||
export const notifyAll = isServiceWorker ? notifyServiceWorker.bind(null, true) : (isWebWorker ? notifyWorker : empty);
|
||||
export const notifySomeone = isServiceWorker ? notifyServiceWorker.bind(null, false) : (isWebWorker ? notifyWorker : noop);
|
||||
export const notifyAll = isServiceWorker ? notifyServiceWorker.bind(null, true) : (isWebWorker ? notifyWorker : noop);
|
@ -11,7 +11,7 @@ export const isChromium = /Chrome/.test(navigator.userAgent) && /Google Inc/.tes
|
||||
*
|
||||
* This should be removed once the underlying Safari issue is fixed.
|
||||
*/
|
||||
const ctx = typeof(window) !== 'undefined' ? window : self;
|
||||
export const ctx = typeof(window) !== 'undefined' ? window : self;
|
||||
|
||||
// https://stackoverflow.com/a/58065241
|
||||
export const isAppleMobile = (/iPad|iPhone|iPod/.test(navigator.platform) ||
|
||||
|
@ -164,7 +164,8 @@ class ConnectionStatusComponent {
|
||||
DEBUG && this.log('setState: isShown:', this.connecting || this.updating);
|
||||
};
|
||||
|
||||
this.setStateTimeout = window.setTimeout(cb, timeout);
|
||||
//this.setStateTimeout = window.setTimeout(cb, timeout);
|
||||
cb();
|
||||
/* if(timeout) this.setStateTimeout = window.setTimeout(cb, timeout);
|
||||
else cb(); */
|
||||
});
|
||||
|
@ -176,6 +176,8 @@ export class AppMessagesManager {
|
||||
public dialogsStorage: DialogsStorage;
|
||||
public filtersStorage: FiltersStorage;
|
||||
|
||||
private groupedTempId = 0;
|
||||
|
||||
constructor() {
|
||||
this.dialogsStorage = new DialogsStorage(this, appChatsManager, appPeersManager, serverTimeManager);
|
||||
this.filtersStorage = new FiltersStorage(appPeersManager, appUsersManager, /* apiManager, */ rootScope);
|
||||
@ -578,6 +580,7 @@ export class AppMessagesManager {
|
||||
|
||||
replyToMsgId: number,
|
||||
threadId: number,
|
||||
groupId: string,
|
||||
caption: string,
|
||||
entities: MessageEntity[],
|
||||
width: number,
|
||||
@ -591,7 +594,7 @@ export class AppMessagesManager {
|
||||
clearDraft: true,
|
||||
scheduleDate: number,
|
||||
|
||||
waveform: Uint8Array
|
||||
waveform: Uint8Array,
|
||||
}> = {}) {
|
||||
peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;
|
||||
|
||||
@ -771,6 +774,29 @@ export class AppMessagesManager {
|
||||
|
||||
const sentDeferred = deferredPromise<InputMedia>();
|
||||
|
||||
if(preloader) {
|
||||
preloader.attachPromise(sentDeferred);
|
||||
sentDeferred.cancel = () => {
|
||||
const error = new Error('Download canceled');
|
||||
error.name = 'AbortError';
|
||||
sentDeferred.reject(error);
|
||||
};
|
||||
|
||||
sentDeferred.catch(err => {
|
||||
if(err.name === 'AbortError' && !uploaded) {
|
||||
this.log('cancelling upload', media);
|
||||
|
||||
sentDeferred.reject(err);
|
||||
this.cancelPendingMessage(message.random_id);
|
||||
this.setTyping(peerId, 'sendMessageCancelAction');
|
||||
|
||||
if(uploadPromise?.cancel) {
|
||||
uploadPromise.cancel();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const media = isDocument ? undefined : {
|
||||
_: photo ? 'messageMediaPhoto' : 'messageMediaDocument',
|
||||
pFlags: {},
|
||||
@ -821,7 +847,7 @@ export class AppMessagesManager {
|
||||
if(!uploaded || message.error) {
|
||||
uploaded = false;
|
||||
uploadPromise = appDownloadManager.upload(file);
|
||||
preloader.attachPromise(uploadPromise);
|
||||
sentDeferred.notifyAll({done: 0, total: file.size});
|
||||
}
|
||||
|
||||
let thumbUploadPromise: typeof uploadPromise;
|
||||
@ -886,16 +912,7 @@ export class AppMessagesManager {
|
||||
|
||||
const percents = Math.max(1, Math.floor(100 * progress.done / progress.total));
|
||||
this.setTyping(peerId, {_: actionName, progress: percents | 0});
|
||||
});
|
||||
|
||||
uploadPromise.catch(err => {
|
||||
if(err.name === 'AbortError' && !uploaded) {
|
||||
this.log('cancelling upload', media);
|
||||
|
||||
sentDeferred.reject(err);
|
||||
this.cancelPendingMessage(message.random_id);
|
||||
this.setTyping(peerId, 'sendMessageCancelAction');
|
||||
}
|
||||
sentDeferred.notifyAll(progress);
|
||||
});
|
||||
|
||||
return sentDeferred;
|
||||
@ -995,6 +1012,8 @@ export class AppMessagesManager {
|
||||
|
||||
this.log('sendAlbum', files, options);
|
||||
|
||||
const groupId = '' + ++this.groupedTempId;
|
||||
|
||||
const messages = files.map((file, idx) => {
|
||||
const details = options.sendFileDetails[idx];
|
||||
const o: any = {
|
||||
@ -1004,6 +1023,7 @@ export class AppMessagesManager {
|
||||
silent: options.silent,
|
||||
replyToMsgId,
|
||||
threadId: options.threadId,
|
||||
groupId,
|
||||
...details
|
||||
};
|
||||
|
||||
@ -1016,23 +1036,6 @@ export class AppMessagesManager {
|
||||
return this.sendFile(peerId, file, o).message;
|
||||
});
|
||||
|
||||
const message = messages[messages.length - 1];
|
||||
const groupId = message.id;
|
||||
messages.forEach(message => {
|
||||
message.grouped_id = groupId;
|
||||
});
|
||||
|
||||
const storage = options.scheduleDate ? this.getScheduledMessagesStorage(peerId) : this.getMessagesStorage(peerId);
|
||||
if(options.scheduleDate) {
|
||||
this.saveMessages(messages, {storage, isScheduled: true, isOutgoing: true});
|
||||
rootScope.broadcast('scheduled_new', {peerId, mid: groupId});
|
||||
} else {
|
||||
this.saveMessages(messages, {storage, isOutgoing: true});
|
||||
rootScope.broadcast('history_append', {peerId, messageId: groupId, my: true});
|
||||
|
||||
this.setDialogTopMessage(message);
|
||||
}
|
||||
|
||||
if(options.clearDraft) {
|
||||
appDraftsManager.syncDraft(peerId, options.threadId);
|
||||
}
|
||||
@ -1314,10 +1317,11 @@ export class AppMessagesManager {
|
||||
const storage = options.isScheduled ? this.getScheduledMessagesStorage(peerId) : this.getMessagesStorage(peerId);
|
||||
|
||||
if(options.isScheduled) {
|
||||
if(!options.isGroupedItem) {
|
||||
this.saveMessages([message], {storage, isScheduled: true, isOutgoing: true});
|
||||
//if(!options.isGroupedItem) {
|
||||
this.saveMessages([message], {storage, isScheduled: true, isOutgoing: true});
|
||||
setTimeout(() => {
|
||||
rootScope.broadcast('scheduled_new', {peerId, mid: messageId});
|
||||
}
|
||||
}, 0);
|
||||
} else {
|
||||
if(options.threadId && this.threadsStorage[peerId]) {
|
||||
delete this.threadsStorage[peerId][options.threadId];
|
||||
@ -1330,12 +1334,13 @@ export class AppMessagesManager {
|
||||
/* const historyStorage = this.getHistoryStorage(peerId);
|
||||
historyStorage.history.unshift(messageId); */
|
||||
|
||||
if(!options.isGroupedItem) {
|
||||
this.saveMessages([message], {storage, isOutgoing: true});
|
||||
//if(!options.isGroupedItem) {
|
||||
this.saveMessages([message], {storage, isOutgoing: true});
|
||||
setTimeout(() => {
|
||||
rootScope.broadcast('history_append', {peerId, messageId, my: true});
|
||||
|
||||
this.setDialogTopMessage(message);
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
if(!options.isGroupedItem && options.clearDraft && !options.threadId) {
|
||||
@ -1344,7 +1349,7 @@ export class AppMessagesManager {
|
||||
|
||||
this.pendingByRandomId[message.random_id] = {peerId, tempId: messageId, storage};
|
||||
|
||||
if(!options.isGroupedItem) {
|
||||
if(!options.isGroupedItem && message.send) {
|
||||
setTimeout(message.send, 0);
|
||||
//setTimeout(message.send, 4000);
|
||||
//setTimeout(message.send, 7000);
|
||||
@ -1356,7 +1361,8 @@ export class AppMessagesManager {
|
||||
replyToMsgId: number,
|
||||
threadId: number,
|
||||
viaBotId: number,
|
||||
reply_markup: any
|
||||
groupId: string,
|
||||
reply_markup: any,
|
||||
}>) {
|
||||
if(options.threadId && !options.replyToMsgId) {
|
||||
options.replyToMsgId = options.threadId;
|
||||
@ -1370,6 +1376,7 @@ export class AppMessagesManager {
|
||||
pFlags: this.generateFlags(peerId),
|
||||
date: options.scheduleDate || (tsNow(true) + serverTimeManager.serverTimeOffset),
|
||||
message: '',
|
||||
grouped_id: options.groupId,
|
||||
random_id: randomLong(),
|
||||
reply_to: this.generateReplyHeader(options.replyToMsgId, options.threadId),
|
||||
via_bot_id: options.viaBotId,
|
||||
@ -1446,13 +1453,26 @@ export class AppMessagesManager {
|
||||
}
|
||||
|
||||
private generateForwardHeader(peerId: number, originalMessage: Message.message) {
|
||||
const myId = appUsersManager.getSelf().id;
|
||||
if(originalMessage.fromId === myId && !originalMessage.fwd_from) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fwdHeader: MessageFwdHeader.messageFwdHeader = {
|
||||
_: 'messageFwdHeader',
|
||||
flags: 0,
|
||||
date: originalMessage.date,
|
||||
from_id: appPeersManager.getOutputPeer(originalMessage.fromId)
|
||||
date: originalMessage.date
|
||||
};
|
||||
|
||||
if(originalMessage.fwd_from) {
|
||||
fwdHeader.from_id = originalMessage.fwd_from.from_id;
|
||||
fwdHeader.from_name = originalMessage.fwd_from.from_name;
|
||||
fwdHeader.post_author = originalMessage.fwd_from.post_author;
|
||||
} else {
|
||||
fwdHeader.from_id = appPeersManager.getOutputPeer(originalMessage.fromId);
|
||||
fwdHeader.post_author = originalMessage.post_author;
|
||||
}
|
||||
|
||||
if(appPeersManager.isBroadcast(originalMessage.peerId)) {
|
||||
if(originalMessage.post_author) {
|
||||
fwdHeader.post_author = originalMessage.post_author;
|
||||
@ -1462,7 +1482,7 @@ export class AppMessagesManager {
|
||||
}
|
||||
|
||||
// * there is no way to detect whether user profile is hidden
|
||||
if(peerId === appUsersManager.getSelf().id) {
|
||||
if(peerId === myId) {
|
||||
fwdHeader.saved_from_msg_id = originalMessage.id;
|
||||
fwdHeader.saved_from_peer = appPeersManager.getOutputPeer(originalMessage.peerId);
|
||||
}
|
||||
@ -1733,6 +1753,13 @@ export class AppMessagesManager {
|
||||
peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;
|
||||
mids = mids.slice().sort((a, b) => a - b);
|
||||
|
||||
const groups: {
|
||||
[groupId: string]: {
|
||||
tempId: string,
|
||||
messages: any[]
|
||||
}
|
||||
} = {};
|
||||
|
||||
const newMessages = mids.map(mid => {
|
||||
const originalMessage = this.getMessageByPeer(fromPeerId, mid);
|
||||
const message = this.generateOutgoingMessage(peerId, options);
|
||||
@ -1742,11 +1769,27 @@ export class AppMessagesManager {
|
||||
message[key] = originalMessage[key];
|
||||
});
|
||||
|
||||
if(originalMessage.grouped_id) {
|
||||
const group = groups[originalMessage.grouped_id] ?? (groups[originalMessage.grouped_id] = {tempId: '' + ++this.groupedTempId, messages: []});
|
||||
group.messages.push(message);
|
||||
}
|
||||
|
||||
return message;
|
||||
});
|
||||
|
||||
for(const groupId in groups) {
|
||||
const group = groups[groupId];
|
||||
if(group.messages.length > 1) {
|
||||
group.messages.forEach(message => {
|
||||
message.grouped_id = group.tempId;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
newMessages.forEach(message => {
|
||||
this.beforeMessageSending(message, {
|
||||
isScheduled: !!options.scheduleDate || undefined
|
||||
});
|
||||
|
||||
return message;
|
||||
});
|
||||
|
||||
const sentRequestOptions: InvokeApiOptions = {};
|
||||
@ -1754,7 +1797,7 @@ export class AppMessagesManager {
|
||||
sentRequestOptions.afterMessageId = this.pendingAfterMsgs[peerId].messageId;
|
||||
}
|
||||
|
||||
const promise = apiManager.invokeApiAfter('messages.forwardMessages', {
|
||||
const promise = /* true ? Promise.resolve() : */apiManager.invokeApiAfter('messages.forwardMessages', {
|
||||
from_peer: appPeersManager.getInputPeerById(fromPeerId),
|
||||
id: mids.map(mid => this.getServerMessageId(mid)),
|
||||
random_id: newMessages.map(message => message.random_id),
|
||||
@ -4860,7 +4903,7 @@ export class AppMessagesManager {
|
||||
|
||||
this.updateMessageRepliesIfNeeded(message);
|
||||
|
||||
if(!message.pFlags.out && message.pFlags.unread) {
|
||||
if(!message.pFlags.out && !message.pFlags.is_outgoing && message.pFlags.unread) {
|
||||
history.unread++;
|
||||
}
|
||||
history.count++;
|
||||
|
@ -87,7 +87,7 @@ export class ApiFileManager {
|
||||
|
||||
public downloadCheck(dcId: string | number) {
|
||||
const downloadPull = this.downloadPulls[dcId];
|
||||
const downloadLimit = dcId === 'upload' ? 100 : 100;
|
||||
const downloadLimit = dcId === 'upload' ? 24 : 48;
|
||||
//const downloadLimit = Infinity;
|
||||
|
||||
if(this.downloadActives[dcId] >= downloadLimit || !downloadPull || !downloadPull.length) {
|
||||
@ -454,6 +454,10 @@ export class ApiFileManager {
|
||||
|
||||
const id = this.tempId++;
|
||||
|
||||
/* setInterval(() => {
|
||||
console.log(file);
|
||||
}, 1e3); */
|
||||
|
||||
const self = this;
|
||||
function* generator() {
|
||||
for(let offset = 0; offset < fileSize; offset += partSize) {
|
||||
@ -485,6 +489,23 @@ export class ApiFileManager {
|
||||
}
|
||||
buffer = u.buffer; */
|
||||
|
||||
/* setTimeout(() => {
|
||||
doneParts++;
|
||||
uploadResolve();
|
||||
|
||||
//////this.log('Progress', doneParts * partSize / fileSize);
|
||||
|
||||
self.log('done part', part, doneParts);
|
||||
|
||||
deferred.notify({done: doneParts * partSize, total: fileSize});
|
||||
|
||||
if(doneParts >= totalParts) {
|
||||
deferred.resolve(resultInputFile);
|
||||
resolved = true;
|
||||
}
|
||||
}, 1250);
|
||||
return; */
|
||||
|
||||
apiManager.invokeApi(method, {
|
||||
file_id: fileId,
|
||||
file_part: part,
|
||||
|
@ -13,6 +13,7 @@ import type { MethodDeclMap } from '../../layer';
|
||||
import { CancellablePromise, deferredPromise } from '../../helpers/cancellablePromise';
|
||||
import { bytesFromHex, bytesToHex } from '../../helpers/bytes';
|
||||
//import { clamp } from '../../helpers/number';
|
||||
import { isSafari } from '../../helpers/userAgent';
|
||||
|
||||
/// #if !MTPROTO_WORKER
|
||||
import rootScope from '../rootScope';
|
||||
@ -161,7 +162,7 @@ export class ApiManager {
|
||||
|
||||
/// #if MTPROTO_HTTP_UPLOAD
|
||||
// @ts-ignore
|
||||
const transportType: TransportType = connectionType === 'upload' ? 'https' : 'websocket';
|
||||
const transportType: TransportType = connectionType === 'upload' && isSafari ? 'https' : 'websocket';
|
||||
//const transportType: TransportType = connectionType !== 'client' ? 'https' : 'websocket';
|
||||
/// #else
|
||||
// @ts-ignore
|
||||
@ -182,7 +183,7 @@ export class ApiManager {
|
||||
}
|
||||
|
||||
const networkers = cache[dcId];
|
||||
if(networkers.length >= /* 1 */(connectionType === 'client' ? 1 : (connectionType === 'download' ? 3 : 3))) {
|
||||
if(networkers.length >= /* 1 */(connectionType === 'client' || transportType === 'https' ? 1 : (connectionType === 'download' ? 3 : 3))) {
|
||||
let i = networkers.length - 1, found = false;
|
||||
for(; i >= 0; --i) {
|
||||
if(networkers[i].isOnline) {
|
||||
|
@ -43,6 +43,7 @@ export class DcConfigurator {
|
||||
|
||||
private chosenServers: Servers = {} as any;
|
||||
|
||||
/// #if !MTPROTO_HTTP
|
||||
private transportSocket = (dcId: number, connectionType: ConnectionType) => {
|
||||
const subdomain = this.sslSubdomains[dcId - 1];
|
||||
const path = Modes.test ? 'apiws_test' : 'apiws';
|
||||
@ -50,7 +51,9 @@ export class DcConfigurator {
|
||||
const suffix = connectionType === 'upload' ? '-U' : connectionType === 'download' ? '-D' : '';
|
||||
return new Socket(dcId, chosenServer, suffix, connectionType === 'client' ? 30000 : 10000);
|
||||
};
|
||||
/// #endif
|
||||
|
||||
/// #if MTPROTO_HTTP_UPLOAD || MTPROTO_HTTP
|
||||
private transportHTTP = (dcId: number, connectionType: ConnectionType) => {
|
||||
if(Modes.ssl || !Modes.http) {
|
||||
const subdomain = this.sslSubdomains[dcId - 1] + (connectionType !== 'client' ? '-1' : '');
|
||||
@ -66,6 +69,7 @@ export class DcConfigurator {
|
||||
}
|
||||
}
|
||||
};
|
||||
/// #endif
|
||||
|
||||
public chooseServer(dcId: number, connectionType: ConnectionType = 'client', transportType: TransportType = 'websocket', reuse = true) {
|
||||
/* if(transportType === 'websocket' && !Modes.multipleConnections) {
|
||||
|
@ -7,11 +7,10 @@ import networkerFactory from "./networkerFactory";
|
||||
import apiFileManager from './apiFileManager';
|
||||
//import { logger, LogLevels } from '../logger';
|
||||
import type { ServiceWorkerTask, ServiceWorkerTaskResponse } from './mtproto.service';
|
||||
import { ctx } from '../../helpers/userAgent';
|
||||
|
||||
//const log = logger('DW', LogLevels.error);
|
||||
|
||||
const ctx = self as any as DedicatedWorkerGlobalScope;
|
||||
|
||||
//console.error('INCLUDE !!!', new Error().stack);
|
||||
|
||||
/* function isObject(object: any) {
|
||||
@ -64,7 +63,15 @@ networkerFactory.onConnectionStatusChange = (status) => {
|
||||
respond({type: 'connectionStatusChange', payload: status});
|
||||
};
|
||||
|
||||
ctx.addEventListener('message', async(e) => {
|
||||
/* ctx.onerror = (error) => {
|
||||
console.error('error:', error);
|
||||
};
|
||||
|
||||
ctx.onunhandledrejection = (error) => {
|
||||
console.error('onunhandledrejection:', error);
|
||||
}; */
|
||||
|
||||
const onMessage = async(e: any) => {
|
||||
try {
|
||||
const task = e.data;
|
||||
const taskId = task.taskId;
|
||||
@ -103,6 +110,10 @@ ctx.addEventListener('message', async(e) => {
|
||||
webpSupported = task.payload;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!task.task) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(task.task) {
|
||||
case 'computeSRP':
|
||||
@ -131,6 +142,8 @@ ctx.addEventListener('message', async(e) => {
|
||||
} catch(error) {
|
||||
respond({taskId, error});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'getNetworker': {
|
||||
@ -157,12 +170,15 @@ ctx.addEventListener('message', async(e) => {
|
||||
}
|
||||
|
||||
//throw new Error('Unknown task: ' + task.task);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ctx.addEventListener('message', onMessage);
|
||||
|
||||
//console.log('[WORKER] Will send ready', Date.now() / 1000);
|
||||
ctx.postMessage('ready');
|
||||
|
@ -1,4 +1,5 @@
|
||||
import MTProtoWorker from 'worker-loader!./mtproto.worker';
|
||||
//import './mtproto.worker';
|
||||
import { isObject } from '../../helpers/object';
|
||||
import type { MethodDeclMap } from '../../layer';
|
||||
import type { InvokeApiOptions } from '../../types';
|
||||
@ -9,7 +10,7 @@ import webpWorkerController from '../webp/webpWorkerController';
|
||||
import type { DownloadOptions } from './apiFileManager';
|
||||
import { ApiError } from './apiManager';
|
||||
import type { ServiceWorkerTask, ServiceWorkerTaskResponse } from './mtproto.service';
|
||||
import { MOUNT_CLASS_TO, UserAuth } from './mtproto_config';
|
||||
import { DEBUG, MOUNT_CLASS_TO, UserAuth } from './mtproto_config';
|
||||
import type { MTMessage } from './networker';
|
||||
import referenceDatabase from './referenceDatabase';
|
||||
import appDocsManager from '../appManagers/appDocsManager';
|
||||
@ -32,7 +33,7 @@ type HashOptions = {
|
||||
};
|
||||
|
||||
export class ApiManagerProxy extends CryptoWorkerMethods {
|
||||
public worker: Worker;
|
||||
public worker: /* Window */Worker;
|
||||
public postMessage: (...args: any[]) => void;
|
||||
private afterMessageIdTemp = 0;
|
||||
|
||||
@ -54,6 +55,8 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
|
||||
|
||||
private isSWRegistered = true;
|
||||
|
||||
private debug = DEBUG;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.log('constructor');
|
||||
@ -118,6 +121,7 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
|
||||
//return;
|
||||
|
||||
const worker = new MTProtoWorker();
|
||||
//const worker = window;
|
||||
worker.addEventListener('message', (e) => {
|
||||
if(!this.worker) {
|
||||
this.worker = worker;
|
||||
@ -182,23 +186,27 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
|
||||
} else {
|
||||
navigator.serviceWorker.controller.postMessage(task);
|
||||
}
|
||||
} else {
|
||||
} else if(task.hasOwnProperty('result') || task.hasOwnProperty('error')) {
|
||||
this.finalizeTask(task.taskId, task.result, task.error);
|
||||
}
|
||||
});
|
||||
|
||||
worker.addEventListener('error', (err) => {
|
||||
this.log.error('WORKER ERROR', err);
|
||||
});
|
||||
}
|
||||
|
||||
private finalizeTask(taskId: number, result: any, error: any) {
|
||||
const deferred = this.awaiting[taskId];
|
||||
if(deferred !== undefined) {
|
||||
this.log.debug('done', deferred.taskName, result, error);
|
||||
this.debug && this.log.debug('done', deferred.taskName, result, error);
|
||||
error ? deferred.reject(error) : deferred.resolve(result);
|
||||
delete this.awaiting[taskId];
|
||||
}
|
||||
}
|
||||
|
||||
public performTaskWorker<T>(task: string, ...args: any[]) {
|
||||
this.log.debug('start', task, args);
|
||||
this.debug && this.log.debug('start', task, args);
|
||||
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
this.awaiting[this.taskId] = {resolve, reject, taskName: task};
|
||||
@ -218,12 +226,12 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
|
||||
|
||||
private releasePending() {
|
||||
if(this.postMessage) {
|
||||
this.log.debug('releasing tasks, length:', this.pending.length);
|
||||
this.debug && this.log.debug('releasing tasks, length:', this.pending.length);
|
||||
this.pending.forEach(pending => {
|
||||
this.postMessage(pending);
|
||||
});
|
||||
|
||||
this.log.debug('released tasks');
|
||||
this.debug && this.log.debug('released tasks');
|
||||
this.pending.length = 0;
|
||||
}
|
||||
}
|
||||
@ -262,7 +270,7 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
|
||||
|
||||
return this.performTaskWorker('invokeApi', method, params, options).then((result: any) => {
|
||||
if(result._.includes('NotModified')) {
|
||||
this.log.warn('NotModified saved!', method, queryJSON);
|
||||
this.debug && this.log.warn('NotModified saved!', method, queryJSON);
|
||||
return cached.result;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,8 @@ import { longToBytes } from '../crypto/crypto_utils';
|
||||
import MTTransport from './transports/transport';
|
||||
import { convertToUint8Array, bufferConcat, bytesCmp, bytesToHex } from '../../helpers/bytes';
|
||||
import { nextRandomInt, randomLong } from '../../helpers/random';
|
||||
import { CancellablePromise, deferredPromise } from '../../helpers/cancellablePromise';
|
||||
import { isSafari } from '../../helpers/userAgent';
|
||||
|
||||
/// #if MTPROTO_HTTP_UPLOAD
|
||||
// @ts-ignore
|
||||
@ -112,6 +114,9 @@ export default class MTPNetworker {
|
||||
public isOnline = false;
|
||||
private lastResponseTime = 0;
|
||||
private disconnectDelay: number;
|
||||
private pingPromise: CancellablePromise<any>;
|
||||
private sentPingTimes = 0;
|
||||
private tt = 0;
|
||||
//public onConnectionStatusChange: (online: boolean) => void;
|
||||
|
||||
constructor(public dcId: number, private authKey: number[], private authKeyId: Uint8Array,
|
||||
@ -161,9 +166,13 @@ export default class MTPNetworker {
|
||||
|
||||
// * handle outcoming dead socket, server will close the connection
|
||||
if((this.transport as Socket).networker) {
|
||||
this.disconnectDelay = (this.transport as Socket).retryTimeout / 1000 | 0;
|
||||
setInterval(this.sendPingDelayDisconnect, (this.disconnectDelay - 5) * 1000);
|
||||
this.sendPingDelayDisconnect();
|
||||
if(isSafari) {
|
||||
this.pingPromise = Promise.resolve();
|
||||
} else {
|
||||
this.disconnectDelay = (this.transport as Socket).retryTimeout / 1000 | 0;
|
||||
//setInterval(this.sendPingDelayDisconnect, (this.disconnectDelay - 5) * 1000);
|
||||
this.sendPingDelayDisconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -326,13 +335,63 @@ export default class MTPNetworker {
|
||||
}
|
||||
|
||||
private sendPingDelayDisconnect = () => {
|
||||
if(!this.isOnline) return; // * already disconnected
|
||||
this.wrapMtpCall('ping_delay_disconnect', {
|
||||
if(this.pingPromise) return;
|
||||
|
||||
if(!this.isOnline) {
|
||||
if((this.transport as Socket).connected) {
|
||||
(this.transport as Socket).handleClose();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.log('sendPingDelayDisconnect', this.sentPingTimes);
|
||||
|
||||
/* if(this.tt) clearTimeout(this.tt);
|
||||
this.tt = self.setTimeout(() => {
|
||||
(this.transport as any).ws.close(1000);
|
||||
this.tt = 0;
|
||||
}, this.disconnectDelay * 1000); */
|
||||
/* this.wrapMtpCall('ping_delay_disconnect', {
|
||||
ping_id: randomLong(),
|
||||
disconnect_delay: this.disconnectDelay
|
||||
}, {
|
||||
noResponse: true,
|
||||
notContentRelated: true
|
||||
}); */
|
||||
const deferred = this.pingPromise = deferredPromise<void>();
|
||||
|
||||
const timeoutTime = this.disconnectDelay * 1000;
|
||||
|
||||
/* if(!this.sentPingTimes || true) {
|
||||
++this.sentPingTimes; */
|
||||
const startTime = Date.now();
|
||||
this.wrapMtpCall('ping', {
|
||||
ping_id: randomLong()
|
||||
}, {}).then(pong => {
|
||||
const elapsedTime = Date.now() - startTime;
|
||||
this.log('sendPingDelayDisconnect: response', pong, elapsedTime > timeoutTime);
|
||||
|
||||
if(elapsedTime > timeoutTime) {
|
||||
deferred.reject();
|
||||
} else {
|
||||
setTimeout(deferred.resolve, timeoutTime - elapsedTime);
|
||||
}
|
||||
}, deferred.reject).finally(() => {
|
||||
clearTimeout(rejectTimeout);
|
||||
//--this.sentPingTimes;
|
||||
});
|
||||
//}
|
||||
|
||||
const rejectTimeout = self.setTimeout(deferred.reject, timeoutTime);
|
||||
|
||||
deferred.catch(() => {
|
||||
(this.transport as Socket).handleClose();
|
||||
});
|
||||
|
||||
deferred.finally(() => {
|
||||
this.pingPromise = null;
|
||||
this.sendPingDelayDisconnect();
|
||||
});
|
||||
};
|
||||
|
||||
@ -543,6 +602,10 @@ export default class MTPNetworker {
|
||||
|
||||
this.log.error('timeout', message);
|
||||
this.setConnectionStatus(false);
|
||||
|
||||
this.getEncryptedOutput(message).then(bytes => {
|
||||
this.log.error('timeout encrypted', bytes);
|
||||
});
|
||||
}, CONNECTION_TIMEOUT);
|
||||
|
||||
promise.finally(() => {
|
||||
@ -571,7 +634,11 @@ export default class MTPNetworker {
|
||||
});
|
||||
}
|
||||
|
||||
this.sendPingDelayDisconnect();
|
||||
if(!this.pingPromise && (this.transport as Socket).networker) {
|
||||
this.sendPingDelayDisconnect();
|
||||
}
|
||||
/* this.sentPingTimes = 0;
|
||||
this.sendPingDelayDisconnect(); */
|
||||
}
|
||||
/* if(this.onConnectionStatusChange) {
|
||||
this.onConnectionStatusChange(this.isOnline);
|
||||
@ -845,10 +912,14 @@ export default class MTPNetworker {
|
||||
});
|
||||
}
|
||||
|
||||
public sendEncryptedRequest(message: MTMessage) {
|
||||
public getEncryptedOutput(message: MTMessage) {
|
||||
/* if(DEBUG) {
|
||||
this.log.debug('Send encrypted', message, this.authKeyId);
|
||||
} */
|
||||
/* if(!this.isOnline) {
|
||||
this.log('trying to send message when offline:', Object.assign({}, message));
|
||||
//debugger;
|
||||
} */
|
||||
|
||||
const data = new TLSerialization({
|
||||
startMaxLength: message.body.length + 2048
|
||||
@ -859,26 +930,48 @@ export default class MTPNetworker {
|
||||
|
||||
data.storeLong(message.msg_id, 'message_id');
|
||||
data.storeInt(message.seq_no, 'seq_no');
|
||||
|
||||
|
||||
data.storeInt(message.body.length, 'message_data_length');
|
||||
data.storeRawBytes(message.body, 'message_data');
|
||||
|
||||
/* const messageDataLength = message.body.length;
|
||||
let canBeLength = 0; // bytes
|
||||
canBeLength += 8;
|
||||
canBeLength += 8;
|
||||
canBeLength += 8;
|
||||
canBeLength += 4;
|
||||
canBeLength += 4;
|
||||
canBeLength += message.body.length; */
|
||||
|
||||
const dataBuffer = data.getBuffer();
|
||||
|
||||
|
||||
/* if(dataBuffer.byteLength !== canBeLength || !bytesCmp(new Uint8Array(dataBuffer.slice(dataBuffer.byteLength - message.body.length)), new Uint8Array(message.body))) {
|
||||
this.log.error('wrong length', dataBuffer, canBeLength, message.msg_id);
|
||||
} */
|
||||
|
||||
const paddingLength = (16 - (data.offset % 16)) + 16 * (1 + nextRandomInt(5));
|
||||
const padding = [...new Uint8Array(paddingLength).randomize()];
|
||||
/* const padding = [167, 148, 207, 226, 86, 192, 193, 57, 124, 153, 174, 145, 159, 1, 5, 70, 127, 157,
|
||||
51, 241, 46, 85, 141, 212, 139, 234, 213, 164, 197, 116, 245, 70, 184, 40, 40, 201, 233, 211, 150,
|
||||
94, 57, 84, 1, 135, 108, 253, 34, 139, 222, 208, 71, 214, 90, 67, 36, 28, 167, 148, 207, 226, 86, 192, 193, 57, 124, 153, 174, 145, 159, 1, 5, 70, 127, 157,
|
||||
51, 241, 46, 85, 141, 212, 139, 234, 213, 164, 197, 116, 245, 70, 184, 40, 40, 201, 233, 211, 150,
|
||||
94, 57, 84, 1, 135, 108, 253, 34, 139, 222, 208, 71, 214, 90, 67, 36, 28].slice(0, paddingLength); */
|
||||
|
||||
const dataWithPadding = bufferConcat(dataBuffer, padding);
|
||||
// this.log('Adding padding', dataBuffer, padding, dataWithPadding)
|
||||
// this.log('auth_key_id', bytesToHex(self.authKeyID))
|
||||
|
||||
/* if(message.fileUpload) {
|
||||
/* if(dataWithPadding.byteLength % 16) {
|
||||
this.log.error('aaa', dataWithPadding, paddingLength);
|
||||
}
|
||||
|
||||
if(message.fileUpload) {
|
||||
this.log('Send encrypted: body length:', (message.body as ArrayBuffer).byteLength, paddingLength, dataWithPadding);
|
||||
} */
|
||||
|
||||
|
||||
return this.getEncryptedMessage(dataWithPadding).then((encryptedResult) => {
|
||||
/* if(DEBUG) {
|
||||
this.log.debug('Got encrypted out message', encryptedResult);
|
||||
this.log('Got encrypted out message', encryptedResult);
|
||||
} */
|
||||
|
||||
const request = new TLSerialization({
|
||||
@ -890,10 +983,17 @@ export default class MTPNetworker {
|
||||
|
||||
const requestData = request.getBytes(true);
|
||||
|
||||
/* if(message.fileUpload) {
|
||||
this.log('Send encrypted: requestData length:', requestData.length, requestData.length % 16, paddingLength % 16, paddingLength, data.offset);
|
||||
} */
|
||||
//if(message.fileUpload) {
|
||||
//this.log('Send encrypted: requestData length:', requestData.length, requestData.length % 16, paddingLength % 16, paddingLength, data.offset, encryptedResult.msgKey.length % 16, encryptedResult.bytes.length % 16);
|
||||
//this.log('Send encrypted: messageId:', message.msg_id, requestData.length);
|
||||
//}
|
||||
|
||||
return requestData;
|
||||
});
|
||||
}
|
||||
|
||||
public sendEncryptedRequest(message: MTMessage) {
|
||||
return this.getEncryptedOutput(message).then(requestData => {
|
||||
const promise = this.transport.send(requestData);
|
||||
/// #if !MTPROTO_HTTP && !MTPROTO_HTTP_UPLOAD
|
||||
return promise;
|
||||
@ -1381,17 +1481,16 @@ export default class MTPNetworker {
|
||||
break;
|
||||
}
|
||||
|
||||
case 'pong': { // * https://core.telegram.org/mtproto/service_messages#ping-messages-pingpong - These messages do not require acknowledgments
|
||||
/* if((this.transport as Socket).networker) {
|
||||
case 'pong': { // * https://core.telegram.org/mtproto/service_messages#ping-messages-pingpong - These messages doesn't require acknowledgments
|
||||
if((this.transport as Socket).networker) {
|
||||
const sentMessageId = message.msg_id;
|
||||
const sentMessage = this.sentMessages[sentMessageId];
|
||||
const sentMessage = this.sentMessages[sentMessageId];
|
||||
|
||||
if(sentMessage) {
|
||||
sentMessage.deferred.resolve(message);
|
||||
delete this.sentMessages[sentMessageId];
|
||||
}
|
||||
|
||||
|
||||
} */
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1,6 +1,14 @@
|
||||
import sessionStorage from '../sessionStorage';
|
||||
import { longFromInts } from './bin_utils';
|
||||
import { nextRandomInt } from '../../helpers/random';
|
||||
import { MOUNT_CLASS_TO } from './mtproto_config';
|
||||
|
||||
/*
|
||||
let lol: any = {};
|
||||
for(var i = 0; i < 100; i++) {
|
||||
timeManager.generateId();
|
||||
}
|
||||
*/
|
||||
|
||||
export class TimeManager {
|
||||
private lastMessageId = [0, 0];
|
||||
@ -30,7 +38,12 @@ export class TimeManager {
|
||||
|
||||
const ret = longFromInts(messageId[0], messageId[1]);
|
||||
|
||||
//console.log('[TimeManager]: Generated msg id', messageId, this.timeOffset, ret);
|
||||
/* if(lol[ret]) {
|
||||
console.error('[TimeManager]: Generated SAME msg id', messageId, this.timeOffset, ret);
|
||||
}
|
||||
lol[ret] = true;
|
||||
|
||||
console.log('[TimeManager]: Generated msg id', messageId, this.timeOffset, ret); */
|
||||
|
||||
return ret
|
||||
}
|
||||
@ -52,4 +65,6 @@ export class TimeManager {
|
||||
}
|
||||
}
|
||||
|
||||
export default new TimeManager();
|
||||
const timeManager = new TimeManager();
|
||||
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.timeManager = timeManager);
|
||||
export default timeManager;
|
||||
|
@ -25,7 +25,7 @@ class TLSerialization {
|
||||
public byteView: Uint8Array;
|
||||
|
||||
constructor(options: Partial<{startMaxLength: number, mtproto: true}> = {}) {
|
||||
this.maxLength = options.startMaxLength || 2048 // 2Kb
|
||||
this.maxLength = options.startMaxLength || 2048; // 2Kb
|
||||
this.mtproto = options.mtproto || false;
|
||||
this.createBuffer();
|
||||
}
|
||||
@ -38,11 +38,22 @@ class TLSerialization {
|
||||
|
||||
public getArray() {
|
||||
const resultBuffer = new ArrayBuffer(this.offset);
|
||||
const resultArray = new Int32Array(resultBuffer);
|
||||
|
||||
//let perf = performance.now();
|
||||
/* const resultUint8: any = new Uint8Array(resultBuffer);
|
||||
resultUint8.set(this.byteView.subarray(0, this.offset)); */
|
||||
//console.log('perf uint8', performance.now() - perf);
|
||||
|
||||
//perf = performance.now();
|
||||
const resultInt32 = new Int32Array(resultBuffer);
|
||||
resultInt32.set(this.intView.subarray(0, this.offset / 4));
|
||||
//console.log('perf int32', performance.now() - perf);
|
||||
|
||||
/* if(resultUint8.buffer.byteLength !== resultInt32.buffer.byteLength) {
|
||||
console.error(resultUint8, resultInt32);
|
||||
} */
|
||||
|
||||
resultArray.set(this.intView.subarray(0, this.offset / 4));
|
||||
|
||||
return resultArray;
|
||||
return resultInt32;
|
||||
}
|
||||
|
||||
public getBuffer() {
|
||||
|
@ -1,8 +1,55 @@
|
||||
//import aesjs from 'aes-js';
|
||||
import { CTR } from "@cryptography/aes";
|
||||
import AES from "@cryptography/aes";
|
||||
import { bytesFromWordss } from "../../../helpers/bytes";
|
||||
import { Codec } from "./codec";
|
||||
|
||||
class Counter {
|
||||
_counter: Uint8Array;
|
||||
|
||||
constructor(initialValue: Uint8Array) {
|
||||
this._counter = initialValue;
|
||||
}
|
||||
|
||||
increment() {
|
||||
for(let i = 15; i >= 0; i--) {
|
||||
if(this._counter[i] === 255) {
|
||||
this._counter[i] = 0;
|
||||
} else {
|
||||
this._counter[i]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CTR {
|
||||
_counter: Counter;
|
||||
_remainingCounter: Uint8Array = null;
|
||||
_remainingCounterIndex = 16;
|
||||
_aes: AES;
|
||||
|
||||
constructor(key: Uint8Array, counter: Uint8Array) {
|
||||
this._counter = new Counter(counter);
|
||||
this._aes = new AES(key);
|
||||
}
|
||||
|
||||
update(payload: Uint8Array) {
|
||||
const encrypted = payload.slice();
|
||||
|
||||
for(let i = 0; i < encrypted.length; i++) {
|
||||
if(this._remainingCounterIndex === 16) {
|
||||
this._remainingCounter = new Uint8Array(bytesFromWordss(this._aes.encrypt(this._counter._counter)));
|
||||
this._remainingCounterIndex = 0;
|
||||
this._counter.increment();
|
||||
}
|
||||
|
||||
encrypted[i] ^= this._remainingCounter[this._remainingCounterIndex++];
|
||||
}
|
||||
|
||||
return encrypted;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@cryptography/aes не работает с массивами которые не кратны 4, поэтому использую intermediate а не abridged
|
||||
*/
|
||||
@ -98,6 +145,13 @@ export default class Obfuscation {
|
||||
return res;
|
||||
} */
|
||||
public encode(payload: Uint8Array) {
|
||||
return this.encNew.update(payload);
|
||||
}
|
||||
|
||||
public decode(payload: Uint8Array) {
|
||||
return this.decNew.update(payload);
|
||||
}
|
||||
/* public encode(payload: Uint8Array) {
|
||||
let res = this.encNew.encrypt(payload);
|
||||
let bytes = new Uint8Array(bytesFromWordss(res));
|
||||
|
||||
@ -109,5 +163,5 @@ export default class Obfuscation {
|
||||
let bytes = new Uint8Array(bytesFromWordss(res));
|
||||
|
||||
return bytes;
|
||||
}
|
||||
} */
|
||||
}
|
@ -1,39 +1,38 @@
|
||||
import MTTransport from './transport';
|
||||
|
||||
//import abridgetPacketCodec from './abridged';
|
||||
//import abridgedPacketCodec from './abridged';
|
||||
import intermediatePacketCodec from './intermediate';
|
||||
import MTPNetworker from '../networker';
|
||||
import { logger, LogLevels } from '../../logger';
|
||||
import Obfuscation from './obfuscation';
|
||||
import { DEBUG, Modes } from '../mtproto_config';
|
||||
//import { debounce } from '../../../helpers/schedulers';
|
||||
|
||||
export default class Socket extends MTTransport {
|
||||
ws: WebSocket;
|
||||
public ws: WebSocket;
|
||||
|
||||
pending: Array<Partial<{
|
||||
private pending: Array<Partial<{
|
||||
resolve: any,
|
||||
reject: any,
|
||||
body: Uint8Array,
|
||||
bodySent: boolean
|
||||
}>> = [];
|
||||
|
||||
connected = false;
|
||||
|
||||
transport = 'websocket';
|
||||
public connected = false;
|
||||
private codec = intermediatePacketCodec;
|
||||
private log: ReturnType<typeof logger>;
|
||||
private obfuscation = new Obfuscation();
|
||||
public networker: MTPNetworker;
|
||||
|
||||
obfuscation = new Obfuscation();
|
||||
private lastCloseTime: number;
|
||||
|
||||
networker: MTPNetworker;
|
||||
private debug = Modes.debug && false;
|
||||
//private releasePendingDebounced: () => void;
|
||||
|
||||
log: ReturnType<typeof logger>;
|
||||
|
||||
codec = intermediatePacketCodec;
|
||||
|
||||
lastCloseTime: number;
|
||||
|
||||
debug = Modes.debug;
|
||||
//releasePendingDebounced: () => void;
|
||||
/* private stream: Array<any>;
|
||||
private canRead: Promise<any>;
|
||||
private resolveRead: () => void; */
|
||||
//private lol: Uint8Array[] = [];
|
||||
//private dd: () => void;
|
||||
|
||||
constructor(dcId: number, url: string, logSuffix: string, public retryTimeout: number) {
|
||||
super(dcId, url);
|
||||
@ -43,18 +42,37 @@ export default class Socket extends MTTransport {
|
||||
this.log = logger(`WS-${dcId}` + logSuffix, logLevel);
|
||||
this.log('constructor');
|
||||
this.connect();
|
||||
//this.releasePendingDebounced = debounce(() => this.releasePending(true), 2000, false, true);
|
||||
//this.releasePendingDebounced = debounce(() => this.releasePending(true), 200, false, true);
|
||||
|
||||
/* this.dd = debounce(() => {
|
||||
if(this.connected && this.lol.length) {
|
||||
this.ws.send(this.lol.shift());
|
||||
|
||||
if(this.lol.length) {
|
||||
this.dd();
|
||||
}
|
||||
}
|
||||
}, 100, false, true); */
|
||||
}
|
||||
|
||||
private removeListeners() {
|
||||
this.ws.removeEventListener('open', this.handleOpen);
|
||||
this.ws.removeEventListener('close', this.handleClose);
|
||||
this.ws.removeEventListener('error', this.handleError);
|
||||
this.ws.removeEventListener('message', this.handleMessage);
|
||||
}
|
||||
|
||||
connect = () => {
|
||||
if(this.ws) {
|
||||
this.ws.removeEventListener('open', this.handleOpen);
|
||||
this.ws.removeEventListener('close', this.handleClose);
|
||||
this.ws.removeEventListener('error', this.handleError);
|
||||
this.ws.removeEventListener('message', this.handleMessage);
|
||||
this.removeListeners();
|
||||
this.ws.close(1000);
|
||||
}
|
||||
|
||||
/* this.stream = [];
|
||||
this.canRead = new Promise<void>(resolve => {
|
||||
this.resolveRead = resolve;
|
||||
}); */
|
||||
|
||||
this.ws = new WebSocket(this.url, 'binary');
|
||||
this.ws.binaryType = 'arraybuffer';
|
||||
this.ws.addEventListener('open', this.handleOpen);
|
||||
@ -89,9 +107,10 @@ export default class Socket extends MTTransport {
|
||||
this.log.error(e);
|
||||
};
|
||||
|
||||
handleClose = (event: CloseEvent) => {
|
||||
this.log('closed', event, this.pending, this.ws.bufferedAmount);
|
||||
handleClose = () => {
|
||||
this.log('closed'/* , event, this.pending, this.ws.bufferedAmount */);
|
||||
this.connected = false;
|
||||
this.removeListeners();
|
||||
|
||||
const time = Date.now();
|
||||
const diff = time - this.lastCloseTime;
|
||||
@ -117,7 +136,7 @@ export default class Socket extends MTTransport {
|
||||
};
|
||||
|
||||
handleMessage = (event: MessageEvent) => {
|
||||
this.debug && this.log.debug('<-', 'handleMessage', event);
|
||||
this.debug && this.log.debug('<-', 'handleMessage', /* event, */event.data.byteLength);
|
||||
|
||||
let data = this.obfuscation.decode(new Uint8Array(event.data));
|
||||
data = this.codec.readPacket(data);
|
||||
@ -125,11 +144,23 @@ export default class Socket extends MTTransport {
|
||||
if(this.networker) { // authenticated!
|
||||
//this.pending = this.pending.filter(p => p.body); // clear pending
|
||||
|
||||
this.debug && this.log.debug('redirecting to networker');
|
||||
return this.networker.parseResponse(data).then(response => {
|
||||
this.debug && this.log.debug('redirecting to networker', data.length);
|
||||
this.networker.parseResponse(data).then(response => {
|
||||
this.debug && this.log.debug('redirecting to networker response:', response);
|
||||
this.networker.processMessage(response.response, response.messageId, response.sessionId);
|
||||
|
||||
try {
|
||||
this.networker.processMessage(response.response, response.messageId, response.sessionId);
|
||||
} catch(err) {
|
||||
this.log.error('handleMessage networker processMessage error', err);
|
||||
}
|
||||
|
||||
//this.releasePending();
|
||||
}).catch(err => {
|
||||
this.log.error('handleMessage networker parseResponse error', err);
|
||||
});
|
||||
|
||||
//this.dd();
|
||||
return;
|
||||
}
|
||||
|
||||
//console.log('got hex:', data.hex);
|
||||
@ -159,7 +190,7 @@ export default class Socket extends MTTransport {
|
||||
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
releasePending(/* tt = false */) {
|
||||
if(!this.connected) {
|
||||
@ -172,10 +203,14 @@ export default class Socket extends MTTransport {
|
||||
return;
|
||||
} */
|
||||
|
||||
//this.log.error('Pending length:', this.pending.length);
|
||||
//this.log('-> messages to send:', this.pending.length);
|
||||
let length = this.pending.length;
|
||||
//for(let i = length - 1; i >= 0; --i) {
|
||||
for(let i = 0; i < length; ++i) {
|
||||
/* if(this.ws.bufferedAmount) {
|
||||
break;
|
||||
} */
|
||||
|
||||
const pending = this.pending[i];
|
||||
const {body, bodySent} = pending;
|
||||
if(body && !bodySent) {
|
||||
@ -190,13 +225,17 @@ export default class Socket extends MTTransport {
|
||||
this.log.error('bufferedAmount:', this.ws.bufferedAmount);
|
||||
} */
|
||||
|
||||
if(this.ws.readyState !== this.ws.OPEN) {
|
||||
/* if(this.ws.readyState !== this.ws.OPEN) {
|
||||
this.log.error('ws is closed?');
|
||||
this.connected = false;
|
||||
break;
|
||||
}
|
||||
} */
|
||||
|
||||
this.ws.send(enc);
|
||||
//this.lol.push(enc);
|
||||
//setTimeout(() => {
|
||||
this.ws.send(enc);
|
||||
//}, 100);
|
||||
//this.dd();
|
||||
|
||||
if(!pending.resolve) { // remove if no response needed
|
||||
this.pending.splice(i--, 1);
|
||||
|
@ -18,7 +18,7 @@ if(devMode) {
|
||||
const opts = {
|
||||
MTPROTO_WORKER: true,
|
||||
MTPROTO_HTTP: false,
|
||||
MTPROTO_HTTP_UPLOAD: false,
|
||||
MTPROTO_HTTP_UPLOAD: true,
|
||||
DEBUG: devMode,
|
||||
version: 3,
|
||||
"ifdef-verbose": devMode, // add this for verbose output
|
||||
@ -87,8 +87,8 @@ module.exports = {
|
||||
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'public'),
|
||||
filename: "[name].bundle.js",
|
||||
chunkFilename: "[name].chunk.js"
|
||||
filename: "[name].[chunkhash].bundle.js",
|
||||
chunkFilename: "[name].[chunkhash].chunk.js"
|
||||
},
|
||||
|
||||
devServer: {
|
||||
@ -164,8 +164,8 @@ module.exports = {
|
||||
new MiniCssExtractPlugin({
|
||||
// Options similar to the same options in webpackOptions.output
|
||||
// both options are optional
|
||||
filename: '[name].css',
|
||||
chunkFilename: '[id].css',
|
||||
filename: '[name].[contenthash].css',
|
||||
chunkFilename: '[id].[contenthash].css',
|
||||
}),
|
||||
|
||||
new MediaQueryPlugin({
|
||||
|
Loading…
x
Reference in New Issue
Block a user