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