Maybe fixed network disconnect
Fix audio waveform Fix video preview resolution in reply Fix USA country on auth page
This commit is contained in:
parent
c43fa1021e
commit
1d214b38e3
@ -34,6 +34,7 @@ export function decodeWaveform(waveform: Uint8Array | number[]) {
|
|||||||
return new Uint8Array([]);
|
return new Uint8Array([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
var dataView = new DataView(waveform.buffer);
|
var dataView = new DataView(waveform.buffer);
|
||||||
var result = new Uint8Array(valueCount);
|
var result = new Uint8Array(valueCount);
|
||||||
for(var i = 0; i < valueCount; i++) {
|
for(var i = 0; i < valueCount; i++) {
|
||||||
@ -42,6 +43,9 @@ export function decodeWaveform(waveform: Uint8Array | number[]) {
|
|||||||
var value = dataView.getUint16(byteIndex, true);
|
var value = dataView.getUint16(byteIndex, true);
|
||||||
result[i] = (value >> bitShift) & 0b00011111;
|
result[i] = (value >> bitShift) & 0b00011111;
|
||||||
}
|
}
|
||||||
|
} catch(err) {
|
||||||
|
return new Uint8Array([]);
|
||||||
|
}
|
||||||
|
|
||||||
/* var byteIndex = (valueCount - 1) / 8 | 0;
|
/* var byteIndex = (valueCount - 1) / 8 | 0;
|
||||||
var bitShift = (valueCount - 1) % 8;
|
var bitShift = (valueCount - 1) % 8;
|
||||||
@ -82,7 +86,7 @@ function wrapVoiceMessage(doc: MyDocument, audioEl: AudioElement, mid: number) {
|
|||||||
audioEl.append(svg, timeDiv);
|
audioEl.append(svg, timeDiv);
|
||||||
|
|
||||||
let waveform = (doc.attributes.find(attribute => attribute._ == 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio).waveform || new Uint8Array([]);
|
let waveform = (doc.attributes.find(attribute => attribute._ == 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio).waveform || new Uint8Array([]);
|
||||||
waveform = decodeWaveform(waveform.slice());
|
waveform = decodeWaveform(waveform.slice(0, 63));
|
||||||
|
|
||||||
//console.log('decoded waveform:', waveform);
|
//console.log('decoded waveform:', waveform);
|
||||||
|
|
||||||
|
@ -31,11 +31,13 @@ export default class ReplyContainer extends DivAndCaption<(title: string, subtit
|
|||||||
|
|
||||||
//console.log('wrap reply', media);
|
//console.log('wrap reply', media);
|
||||||
|
|
||||||
if(media.photo || (media.document && ['video', 'sticker'].indexOf(media.document.type) !== -1)) {
|
if(media.photo || (media.document && ['video', 'sticker', 'gif'].indexOf(media.document.type) !== -1)) {
|
||||||
|
let good = false;
|
||||||
const replyMedia = document.createElement('div');
|
const replyMedia = document.createElement('div');
|
||||||
replyMedia.classList.add(this.className + '-media');
|
replyMedia.classList.add(this.className + '-media');
|
||||||
|
|
||||||
if(media.document?.type == 'sticker') {
|
if(media.document?.type == 'sticker') {
|
||||||
|
good = true;
|
||||||
wrapSticker({
|
wrapSticker({
|
||||||
doc: media.document,
|
doc: media.document,
|
||||||
div: replyMedia,
|
div: replyMedia,
|
||||||
@ -48,23 +50,31 @@ export default class ReplyContainer extends DivAndCaption<(title: string, subtit
|
|||||||
} else {
|
} else {
|
||||||
const photo = media.photo || media.document;
|
const photo = media.photo || media.document;
|
||||||
|
|
||||||
if(photo._ == 'document' || !photo.downloaded) {
|
const cacheContext = appPhotosManager.getCacheContext(photo);
|
||||||
|
|
||||||
|
if(!cacheContext.downloaded) {
|
||||||
const sizes = photo.sizes || photo.thumbs;
|
const sizes = photo.sizes || photo.thumbs;
|
||||||
if(sizes && sizes[0].bytes) {
|
if(sizes && sizes[0].bytes) {
|
||||||
appPhotosManager.setAttachmentPreview(sizes[0].bytes, replyMedia, false, true);
|
good = true;
|
||||||
|
renderImageFromUrl(replyMedia, appPhotosManager.getPreviewURLFromThumb(sizes[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const size = appPhotosManager.choosePhotoSize(photo, 32, 32/* mediaSizes.active.regular.width, mediaSizes.active.regular.height */);
|
const size = appPhotosManager.choosePhotoSize(photo, 32, 32/* mediaSizes.active.regular.width, mediaSizes.active.regular.height */);
|
||||||
|
if(size._ != 'photoSizeEmpty') {
|
||||||
|
good = true;
|
||||||
appPhotosManager.preloadPhoto(photo, size)
|
appPhotosManager.preloadPhoto(photo, size)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
renderImageFromUrl(replyMedia, photo._ == 'photo' ? photo.url : appPhotosManager.getDocumentCachedThumb(photo.id).url);
|
renderImageFromUrl(replyMedia, photo._ == 'photo' ? photo.url : appPhotosManager.getDocumentCachedThumb(photo.id).url);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(good) {
|
||||||
this.content.prepend(this.mediaEl = replyMedia);
|
this.content.prepend(this.mediaEl = replyMedia);
|
||||||
this.container.classList.add('is-media');
|
this.container.classList.add('is-media');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
subtitle = subtitle ? RichTextProcessor.wrapEmojiText(subtitle) : '';
|
subtitle = subtitle ? RichTextProcessor.wrapEmojiText(subtitle) : '';
|
||||||
}
|
}
|
||||||
|
@ -202,6 +202,8 @@ export default class AppSharedMediaTab implements SliderTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public renderNewMessages(mids: number[]) {
|
public renderNewMessages(mids: number[]) {
|
||||||
|
if(this.init) return; // * not inited yet
|
||||||
|
|
||||||
mids = mids.slice().reverse(); // ! because it will be ascend sorted array
|
mids = mids.slice().reverse(); // ! because it will be ascend sorted array
|
||||||
for(const sharedMediaType of this.sharedMediaTypes) {
|
for(const sharedMediaType of this.sharedMediaTypes) {
|
||||||
const filtered = this.filterMessagesByType(mids, sharedMediaType);
|
const filtered = this.filterMessagesByType(mids, sharedMediaType);
|
||||||
@ -218,6 +220,8 @@ export default class AppSharedMediaTab implements SliderTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public deleteDeletedMessages(mids: number[]) {
|
public deleteDeletedMessages(mids: number[]) {
|
||||||
|
if(this.init) return; // * not inited yet
|
||||||
|
|
||||||
for(const mid of mids) {
|
for(const mid of mids) {
|
||||||
for(const sharedMediaType of this.sharedMediaTypes) {
|
for(const sharedMediaType of this.sharedMediaTypes) {
|
||||||
if(!this.historiesStorage[this.peerID] || !this.historiesStorage[this.peerID][sharedMediaType]) continue;
|
if(!this.historiesStorage[this.peerID] || !this.historiesStorage[this.peerID][sharedMediaType]) continue;
|
||||||
|
File diff suppressed because one or more lines are too long
@ -15,15 +15,17 @@ export type MyPhoto = Photo.photo;
|
|||||||
// TIMES = 2 DUE TO SIDEBAR AND CHAT
|
// TIMES = 2 DUE TO SIDEBAR AND CHAT
|
||||||
//let TEST_FILE_REFERENCE = "5440692274120994569", TEST_FILE_REFERENCE_TIMES = 2;
|
//let TEST_FILE_REFERENCE = "5440692274120994569", TEST_FILE_REFERENCE_TIMES = 2;
|
||||||
|
|
||||||
|
type DocumentCacheThumb = {
|
||||||
|
downloaded: number,
|
||||||
|
url: string
|
||||||
|
};
|
||||||
|
|
||||||
export class AppPhotosManager {
|
export class AppPhotosManager {
|
||||||
private photos: {
|
private photos: {
|
||||||
[id: string]: MyPhoto
|
[id: string]: MyPhoto
|
||||||
} = {};
|
} = {};
|
||||||
private documentThumbsCache: {
|
private documentThumbsCache: {
|
||||||
[docID: string]: {
|
[docID: string]: DocumentCacheThumb
|
||||||
downloaded: number,
|
|
||||||
url: string
|
|
||||||
}
|
|
||||||
} = {};
|
} = {};
|
||||||
public windowW = 0;
|
public windowW = 0;
|
||||||
public windowH = 0;
|
public windowH = 0;
|
||||||
@ -294,7 +296,7 @@ export class AppPhotosManager {
|
|||||||
return download;
|
return download;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCacheContext(photo: any) {
|
public getCacheContext(photo: any): DocumentCacheThumb {
|
||||||
return photo._ == 'document' ? this.getDocumentCachedThumb(photo.id) : photo;
|
return photo._ == 'document' ? this.getDocumentCachedThumb(photo.id) : photo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,8 @@ export class ApiManager {
|
|||||||
|
|
||||||
private afterMessageTempIDs: {[tempID: string]: string} = {};
|
private afterMessageTempIDs: {[tempID: string]: string} = {};
|
||||||
|
|
||||||
|
//private lol = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
//MtpSingleInstanceService.start();
|
//MtpSingleInstanceService.start();
|
||||||
|
|
||||||
@ -193,6 +195,11 @@ export class ApiManager {
|
|||||||
public invokeApi<T extends keyof MethodDeclMap>(method: T, params: MethodDeclMap[T]['req'] = {}, options: InvokeApiOptions = {}): CancellablePromise<MethodDeclMap[T]["res"]> {
|
public invokeApi<T extends keyof MethodDeclMap>(method: T, params: MethodDeclMap[T]['req'] = {}, options: InvokeApiOptions = {}): CancellablePromise<MethodDeclMap[T]["res"]> {
|
||||||
///////this.log('Invoke api', method, params, options);
|
///////this.log('Invoke api', method, params, options);
|
||||||
|
|
||||||
|
/* if(!this.lol) {
|
||||||
|
networkerFactory.updatesProcessor({_: 'new_session_created'}, true);
|
||||||
|
this.lol = true;
|
||||||
|
} */
|
||||||
|
|
||||||
const deferred = deferredPromise<MethodDeclMap[T]['res']>();
|
const deferred = deferredPromise<MethodDeclMap[T]['res']>();
|
||||||
|
|
||||||
const afterMessageIDTemp = options.afterMessageID;
|
const afterMessageIDTemp = options.afterMessageID;
|
||||||
@ -211,7 +218,7 @@ export class ApiManager {
|
|||||||
const interval = MOUNT_CLASS_TO.setInterval(() => {
|
const interval = MOUNT_CLASS_TO.setInterval(() => {
|
||||||
this.log.error('Request is still processing:', method, params, options, 'time:', (Date.now() - startTime) / 1000);
|
this.log.error('Request is still processing:', method, params, options, 'time:', (Date.now() - startTime) / 1000);
|
||||||
//this.cachedUploadNetworkers[2].requestMessageStatus();
|
//this.cachedUploadNetworkers[2].requestMessageStatus();
|
||||||
}, 30e3);
|
}, 5e3);
|
||||||
}
|
}
|
||||||
|
|
||||||
const rejectPromise = (error: ApiError) => {
|
const rejectPromise = (error: ApiError) => {
|
||||||
|
@ -47,6 +47,7 @@ export class DcConfigurator {
|
|||||||
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';
|
||||||
const chosenServer = 'wss://' + subdomain + '.web.telegram.org/' + path;
|
const chosenServer = 'wss://' + subdomain + '.web.telegram.org/' + path;
|
||||||
|
const suffix = connectionType == 'upload' ? '-U' : connectionType == 'download' ? '-D' : '';
|
||||||
return new Socket(dcID, chosenServer, connectionType != 'client' ? '-U' : '');
|
return new Socket(dcID, chosenServer, connectionType != 'client' ? '-U' : '');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,10 +30,10 @@ import Socket from './transports/websocket';
|
|||||||
//console.error('networker included!', new Error().stack);
|
//console.error('networker included!', new Error().stack);
|
||||||
|
|
||||||
export type MTMessageOptions = InvokeApiOptions & Partial<{
|
export type MTMessageOptions = InvokeApiOptions & Partial<{
|
||||||
noResponse: true,
|
noResponse: true, // http_wait
|
||||||
longPoll: true,
|
longPoll: true,
|
||||||
|
|
||||||
notContentRelated: true,
|
notContentRelated: true, // ACK
|
||||||
noSchedule: true,
|
noSchedule: true,
|
||||||
messageID: string,
|
messageID: string,
|
||||||
}>;
|
}>;
|
||||||
@ -114,13 +114,15 @@ export default class MTPNetworker {
|
|||||||
|
|
||||||
//console.trace('Create', dcID, options);
|
//console.trace('Create', dcID, options);
|
||||||
|
|
||||||
|
const suffix = this.options.fileUpload ? '-U' : this.options.fileDownload ? '-D' : '';
|
||||||
this.upload = this.options.fileUpload || this.options.fileDownload;
|
this.upload = this.options.fileUpload || this.options.fileDownload;
|
||||||
//this.log = logger('NET-' + dcID + (this.upload ? '-U' : ''), this.upload && this.dcID == 2 ? LogLevels.debug | LogLevels.warn | LogLevels.log | LogLevels.error : LogLevels.error);
|
//this.log = logger('NET-' + dcID + suffix, this.upload && this.dcID == 1 ? LogLevels.debug | LogLevels.warn | LogLevels.log | LogLevels.error : LogLevels.error);
|
||||||
this.log = logger('NET-' + dcID + (this.upload ? '-U' : ''), LogLevels.log | LogLevels.error);
|
this.log = logger('NET-' + dcID + suffix, LogLevels.log | LogLevels.error);
|
||||||
this.log('constructor'/* , this.authKey, this.authKeyID, this.serverSalt */);
|
this.log('constructor'/* , this.authKey, this.authKeyID, this.serverSalt */);
|
||||||
|
|
||||||
/* // Test resend after bad_server_salt
|
// Test resend after bad_server_salt
|
||||||
if(this.dcID == 1 && this.upload) {
|
/* if(this.dcID == 1 && this.upload) {
|
||||||
|
timeManager.applyServerTime((Date.now() / 1000 - 86400) | 0);
|
||||||
this.serverSalt[0] = 0;
|
this.serverSalt[0] = 0;
|
||||||
} */
|
} */
|
||||||
|
|
||||||
@ -134,14 +136,14 @@ export default class MTPNetworker {
|
|||||||
|
|
||||||
/// #if MTPROTO_HTTP_UPLOAD
|
/// #if MTPROTO_HTTP_UPLOAD
|
||||||
if(this.transport instanceof HTTP) {
|
if(this.transport instanceof HTTP) {
|
||||||
/* this.longPollInt = */setInterval(this.checkLongPoll.bind(this), 10000);
|
/* this.longPollInt = */setInterval(this.checkLongPoll, 10000);
|
||||||
this.checkLongPoll();
|
this.checkLongPoll();
|
||||||
} else {
|
} else {
|
||||||
(this.transport as Socket).networker = this;
|
(this.transport as Socket).networker = this;
|
||||||
}
|
}
|
||||||
/// #elif MTPROTO_HTTP
|
/// #elif MTPROTO_HTTP
|
||||||
//if(this.transport instanceof HTTP) {
|
//if(this.transport instanceof HTTP) {
|
||||||
/* this.longPollInt = */setInterval(this.checkLongPoll.bind(this), 10000);
|
/* this.longPollInt = */setInterval(this.checkLongPoll, 10000);
|
||||||
this.checkLongPoll();
|
this.checkLongPoll();
|
||||||
/// #else
|
/// #else
|
||||||
//} else {
|
//} else {
|
||||||
@ -161,6 +163,7 @@ export default class MTPNetworker {
|
|||||||
if(!sentMessage) {
|
if(!sentMessage) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sentMessage.container) {
|
if(sentMessage.container) {
|
||||||
const newInner: string[] = [];
|
const newInner: string[] = [];
|
||||||
sentMessage.inner.forEach((innerSentMessageID) => {
|
sentMessage.inner.forEach((innerSentMessageID) => {
|
||||||
@ -168,15 +171,16 @@ export default class MTPNetworker {
|
|||||||
if(innerSentMessage) {
|
if(innerSentMessage) {
|
||||||
newInner.push(innerSentMessage.msg_id);
|
newInner.push(innerSentMessage.msg_id);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
sentMessage.inner = newInner;
|
sentMessage.inner = newInner;
|
||||||
}
|
}
|
||||||
|
|
||||||
sentMessage.msg_id = timeManager.generateID();
|
sentMessage.msg_id = timeManager.generateID();
|
||||||
sentMessage.seq_no = this.generateSeqNo(
|
sentMessage.seq_no = this.generateSeqNo(sentMessage.notContentRelated || sentMessage.container);
|
||||||
sentMessage.notContentRelated ||
|
|
||||||
sentMessage.container
|
this.log('updateSentMessage', sentMessage.msg_id, sentMessageID);
|
||||||
);
|
|
||||||
this.sentMessages[sentMessage.msg_id] = sentMessage;
|
this.sentMessages[sentMessage.msg_id] = sentMessage;
|
||||||
delete this.sentMessages[sentMessageID];
|
delete this.sentMessages[sentMessageID];
|
||||||
|
|
||||||
@ -234,19 +238,19 @@ export default class MTPNetworker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public wrapApiCall(method: string, params: any = {}, options: InvokeApiOptions = {}) {
|
public wrapApiCall(method: string, params: any = {}, options: InvokeApiOptions = {}) {
|
||||||
let serializer = new TLSerialization(options);
|
const serializer = new TLSerialization(options);
|
||||||
|
|
||||||
if(!this.connectionInited) { // this will call once for each new session
|
if(!this.connectionInited) { // this will call once for each new session
|
||||||
///////this.log('Wrap api call !this.connectionInited');
|
///////this.log('Wrap api call !this.connectionInited');
|
||||||
|
|
||||||
let invokeWithLayer = Schema.API.methods.find(m => m.method == 'invokeWithLayer');
|
const invokeWithLayer = Schema.API.methods.find(m => m.method == 'invokeWithLayer');
|
||||||
if(!invokeWithLayer) throw new Error('no invokeWithLayer!');
|
if(!invokeWithLayer) throw new Error('no invokeWithLayer!');
|
||||||
serializer.storeInt(+invokeWithLayer.id >>> 0, 'invokeWithLayer');
|
serializer.storeInt(+invokeWithLayer.id >>> 0, 'invokeWithLayer');
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
serializer.storeInt(Schema.layer, 'layer');
|
serializer.storeInt(Schema.layer, 'layer');
|
||||||
|
|
||||||
let initConnection = Schema.API.methods.find(m => m.method == 'initConnection');
|
const initConnection = Schema.API.methods.find(m => m.method == 'initConnection');
|
||||||
if(!initConnection) throw new Error('no initConnection!');
|
if(!initConnection) throw new Error('no initConnection!');
|
||||||
|
|
||||||
serializer.storeInt(+initConnection.id >>> 0, 'initConnection');
|
serializer.storeInt(+initConnection.id >>> 0, 'initConnection');
|
||||||
@ -272,7 +276,7 @@ export default class MTPNetworker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(options.afterMessageID) {
|
if(options.afterMessageID) {
|
||||||
let invokeAfterMsg = Schema.API.methods.find(m => m.method == 'invokeAfterMsg');
|
const invokeAfterMsg = Schema.API.methods.find(m => m.method == 'invokeAfterMsg');
|
||||||
if(!invokeAfterMsg) throw new Error('no invokeAfterMsg!');
|
if(!invokeAfterMsg) throw new Error('no invokeAfterMsg!');
|
||||||
|
|
||||||
this.log('Api call options.afterMessageID!');
|
this.log('Api call options.afterMessageID!');
|
||||||
@ -286,9 +290,9 @@ export default class MTPNetworker {
|
|||||||
this.log('api call body:', serializer.getBytes(true));
|
this.log('api call body:', serializer.getBytes(true));
|
||||||
} */
|
} */
|
||||||
|
|
||||||
var messageID = timeManager.generateID();
|
const messageID = timeManager.generateID();
|
||||||
var seqNo = this.generateSeqNo();
|
const seqNo = this.generateSeqNo();
|
||||||
var message = {
|
const message = {
|
||||||
msg_id: messageID,
|
msg_id: messageID,
|
||||||
seq_no: seqNo,
|
seq_no: seqNo,
|
||||||
body: serializer.getBytes(true),
|
body: serializer.getBytes(true),
|
||||||
@ -305,7 +309,7 @@ export default class MTPNetworker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD
|
/// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD
|
||||||
public checkLongPoll() {
|
public checkLongPoll = () => {
|
||||||
const isClean = this.cleanupSent();
|
const isClean = this.cleanupSent();
|
||||||
//this.log.error('Check lp', this.longPollPending, this.dcID, isClean, this);
|
//this.log.error('Check lp', this.longPollPending, this.dcID, isClean, this);
|
||||||
if((this.longPollPending && Date.now() < this.longPollPending) ||
|
if((this.longPollPending && Date.now() < this.longPollPending) ||
|
||||||
@ -326,10 +330,10 @@ export default class MTPNetworker {
|
|||||||
|
|
||||||
this.sendLongPoll();
|
this.sendLongPoll();
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
public sendLongPoll() {
|
public sendLongPoll() {
|
||||||
let maxWait = 25000;
|
const maxWait = 25000;
|
||||||
|
|
||||||
this.longPollPending = Date.now() + maxWait;
|
this.longPollPending = Date.now() + maxWait;
|
||||||
//this.log('Set lp', this.longPollPending, tsNow())
|
//this.log('Set lp', this.longPollPending, tsNow())
|
||||||
@ -343,7 +347,7 @@ export default class MTPNetworker {
|
|||||||
longPoll: true
|
longPoll: true
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.longPollPending = 0;
|
this.longPollPending = 0;
|
||||||
setTimeout(this.checkLongPoll.bind(this), 0);
|
setTimeout(this.checkLongPoll, 0);
|
||||||
}, (error: ErrorEvent) => {
|
}, (error: ErrorEvent) => {
|
||||||
this.log('Long-poll failed', error);
|
this.log('Long-poll failed', error);
|
||||||
});
|
});
|
||||||
@ -356,29 +360,26 @@ export default class MTPNetworker {
|
|||||||
clearTimeout(this.checkConnectionTimeout);
|
clearTimeout(this.checkConnectionTimeout);
|
||||||
this.checkConnectionTimeout = 0;
|
this.checkConnectionTimeout = 0;
|
||||||
|
|
||||||
var serializer = new TLSerialization({mtproto: true});
|
const serializer = new TLSerialization({mtproto: true});
|
||||||
var pingID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)];
|
const pingID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)];
|
||||||
|
|
||||||
serializer.storeMethod('ping', {
|
serializer.storeMethod('ping', {
|
||||||
ping_id: pingID
|
ping_id: pingID
|
||||||
});
|
});
|
||||||
|
|
||||||
var pingMessage = {
|
const pingMessage = {
|
||||||
msg_id: timeManager.generateID(),
|
msg_id: timeManager.generateID(),
|
||||||
seq_no: this.generateSeqNo(true),
|
seq_no: this.generateSeqNo(true),
|
||||||
body: serializer.getBytes()
|
body: serializer.getBytes()
|
||||||
};
|
};
|
||||||
|
|
||||||
var self = this;
|
this.sendEncryptedRequest(pingMessage).then((result) => {
|
||||||
this.sendEncryptedRequest(pingMessage, {
|
|
||||||
timeout: 15000
|
|
||||||
}).then((result) => {
|
|
||||||
/* delete $rootScope.offlineConnecting */
|
/* delete $rootScope.offlineConnecting */
|
||||||
self.toggleOffline(false);
|
this.toggleOffline(false);
|
||||||
}, () => {
|
}, () => {
|
||||||
this.log('Delay ', self.checkConnectionPeriod * 1000);
|
this.log('Delay ', this.checkConnectionPeriod * 1000);
|
||||||
self.checkConnectionTimeout = setTimeout(self.checkConnection.bind(self), self.checkConnectionPeriod * 1000 | 0);
|
this.checkConnectionTimeout = setTimeout(this.checkConnection, this.checkConnectionPeriod * 1000 | 0);
|
||||||
self.checkConnectionPeriod = Math.min(60, self.checkConnectionPeriod * 1.5);
|
this.checkConnectionPeriod = Math.min(60, this.checkConnectionPeriod * 1.5);
|
||||||
/* setTimeout(function() {
|
/* setTimeout(function() {
|
||||||
delete $rootScope.offlineConnecting
|
delete $rootScope.offlineConnecting
|
||||||
}, 1000); */
|
}, 1000); */
|
||||||
@ -404,7 +405,7 @@ export default class MTPNetworker {
|
|||||||
this.checkConnectionPeriod = 0;
|
this.checkConnectionPeriod = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.checkConnectionTimeout = setTimeout(this.checkConnection.bind(this), this.checkConnectionPeriod * 1000 | 0);
|
this.checkConnectionTimeout = setTimeout(this.checkConnection, this.checkConnectionPeriod * 1000 | 0);
|
||||||
this.checkConnectionPeriod = Math.min(30, (1 + this.checkConnectionPeriod) * 1.5);
|
this.checkConnectionPeriod = Math.min(30, (1 + this.checkConnectionPeriod) * 1.5);
|
||||||
|
|
||||||
document.body.addEventListener('online', this.checkConnection, false);
|
document.body.addEventListener('online', this.checkConnection, false);
|
||||||
@ -430,14 +431,14 @@ export default class MTPNetworker {
|
|||||||
// this.log('parse for', message)
|
// this.log('parse for', message)
|
||||||
this.parseResponse(result).then((response) => {
|
this.parseResponse(result).then((response) => {
|
||||||
if(Modes.debug) {
|
if(Modes.debug) {
|
||||||
this.log('Server response', this.dcID, response);
|
this.log('Server response', response);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.processMessage(response.response, response.messageID, response.sessionID);
|
this.processMessage(response.response, response.messageID, response.sessionID);
|
||||||
|
|
||||||
noResponseMsgs.forEach((msgID) => {
|
noResponseMsgs.forEach((msgID) => {
|
||||||
if(this.sentMessages[msgID]) {
|
if(this.sentMessages[msgID]) {
|
||||||
var deferred = this.sentMessages[msgID].deferred;
|
const deferred = this.sentMessages[msgID].deferred;
|
||||||
delete this.sentMessages[msgID];
|
delete this.sentMessages[msgID];
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
}
|
}
|
||||||
@ -462,7 +463,7 @@ export default class MTPNetworker {
|
|||||||
|
|
||||||
noResponseMsgs.forEach((msgID) => {
|
noResponseMsgs.forEach((msgID) => {
|
||||||
if(this.sentMessages[msgID]) {
|
if(this.sentMessages[msgID]) {
|
||||||
var deferred = this.sentMessages[msgID].deferred;
|
const deferred = this.sentMessages[msgID].deferred;
|
||||||
delete this.sentMessages[msgID];
|
delete this.sentMessages[msgID];
|
||||||
delete this.pendingMessages[msgID];
|
delete this.pendingMessages[msgID];
|
||||||
deferred.reject();
|
deferred.reject();
|
||||||
@ -504,14 +505,14 @@ export default class MTPNetworker {
|
|||||||
const value = delay ? Date.now() + delay : 0;
|
const value = delay ? Date.now() + delay : 0;
|
||||||
const sentMessage = this.sentMessages[messageID];
|
const sentMessage = this.sentMessages[messageID];
|
||||||
if(sentMessage.container) {
|
if(sentMessage.container) {
|
||||||
for(let i = 0, length = sentMessage.inner.length; i < length; i++) {
|
for(const innerMsgID of sentMessage.inner) {
|
||||||
this.pendingMessages[sentMessage.inner[i]] = value;
|
this.pendingMessages[innerMsgID] = value;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.pendingMessages[messageID] = value;
|
this.pendingMessages[messageID] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.log('Resend due', messageID, this.pendingMessages);
|
this.log('Resend', messageID, sentMessage, this.pendingMessages);
|
||||||
|
|
||||||
this.scheduleRequest(delay);
|
this.scheduleRequest(delay);
|
||||||
}
|
}
|
||||||
@ -527,11 +528,11 @@ export default class MTPNetworker {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public getAesKeyIv(msgKey: Uint8Array | number[], isOut: boolean): Promise<[Uint8Array, Uint8Array]> {
|
public getAesKeyIv(msgKey: Uint8Array | number[], isOut: boolean): Promise<[Uint8Array, Uint8Array]> {
|
||||||
var authKey = this.authKeyUint8;
|
const authKey = this.authKeyUint8;
|
||||||
var x = isOut ? 0 : 8;
|
const x = isOut ? 0 : 8;
|
||||||
var sha2aText = new Uint8Array(52);
|
const sha2aText = new Uint8Array(52);
|
||||||
var sha2bText = new Uint8Array(52);
|
const sha2bText = new Uint8Array(52);
|
||||||
var promises: Array<Promise<number[]>> = [];
|
const promises: Array<Promise<number[]>> = [];
|
||||||
|
|
||||||
sha2aText.set(msgKey, 0);
|
sha2aText.set(msgKey, 0);
|
||||||
sha2aText.set(authKey.subarray(x, x + 36), 16);
|
sha2aText.set(authKey.subarray(x, x + 36), 16);
|
||||||
@ -542,10 +543,10 @@ export default class MTPNetworker {
|
|||||||
promises.push(CryptoWorker.sha256Hash(sha2bText));
|
promises.push(CryptoWorker.sha256Hash(sha2bText));
|
||||||
|
|
||||||
return Promise.all(promises).then((results) => {
|
return Promise.all(promises).then((results) => {
|
||||||
var aesKey = new Uint8Array(32);
|
const aesKey = new Uint8Array(32);
|
||||||
var aesIv = new Uint8Array(32);
|
const aesIv = new Uint8Array(32);
|
||||||
var sha2a = new Uint8Array(results[0]);
|
const sha2a = new Uint8Array(results[0]);
|
||||||
var sha2b = new Uint8Array(results[1]);
|
const sha2b = new Uint8Array(results[1]);
|
||||||
|
|
||||||
aesKey.set(sha2a.subarray(0, 8));
|
aesKey.set(sha2a.subarray(0, 8));
|
||||||
aesKey.set(sha2b.subarray(8, 24), 8);
|
aesKey.set(sha2b.subarray(8, 24), 8);
|
||||||
@ -559,7 +560,7 @@ export default class MTPNetworker {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public performScheduledRequest() {
|
public performScheduledRequest = () => {
|
||||||
// this.log('scheduled', this.dcID, this.iii)
|
// this.log('scheduled', this.dcID, this.iii)
|
||||||
|
|
||||||
/// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD
|
/// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD
|
||||||
@ -604,24 +605,23 @@ export default class MTPNetworker {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var message: MTPNetworker['sentMessages'][keyof MTPNetworker['sentMessages']];
|
let message: MTPNetworker['sentMessages'][keyof MTPNetworker['sentMessages']];
|
||||||
var messages: typeof message[] = [];
|
const messages: typeof message[] = [];
|
||||||
|
|
||||||
var messagesByteLen = 0;
|
const currentTime = Date.now();
|
||||||
var currentTime = Date.now();
|
let messagesByteLen = 0;
|
||||||
var hasApiCall = false;
|
let hasApiCall = false;
|
||||||
var hasHttpWait = false;
|
let hasHttpWait = false;
|
||||||
var lengthOverflow = false;
|
let lengthOverflow = false;
|
||||||
var singlesCount = 0;
|
let singlesCount = 0;
|
||||||
var self = this;
|
|
||||||
|
|
||||||
for(let messageID in this.pendingMessages) {
|
for(const messageID in this.pendingMessages) {
|
||||||
let value = this.pendingMessages[messageID];
|
const value = this.pendingMessages[messageID];
|
||||||
|
|
||||||
if(!value || value >= currentTime) {
|
if(!value || value >= currentTime) {
|
||||||
if(message = this.sentMessages[messageID]) {
|
if(message = this.sentMessages[messageID]) {
|
||||||
//this.log('performScheduledRequest message:', message);
|
//this.log('performScheduledRequest message:', message);
|
||||||
var messageByteLength = (/* message.body.byteLength || */message.body.length) + 32;
|
const messageByteLength = (/* message.body.byteLength || */message.body.length) + 32;
|
||||||
if(!message.notContentRelated &&
|
if(!message.notContentRelated &&
|
||||||
lengthOverflow) {
|
lengthOverflow) {
|
||||||
continue; // maybe break here
|
continue; // maybe break here
|
||||||
@ -653,7 +653,7 @@ export default class MTPNetworker {
|
|||||||
// this.log(message, messageID)
|
// this.log(message, messageID)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete self.pendingMessages[messageID];
|
delete this.pendingMessages[messageID];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,7 +662,7 @@ export default class MTPNetworker {
|
|||||||
/// #endif
|
/// #endif
|
||||||
/// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD
|
/// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD
|
||||||
if(hasApiCall && !hasHttpWait) {
|
if(hasApiCall && !hasHttpWait) {
|
||||||
var serializer = new TLSerialization({mtproto: true});
|
const serializer = new TLSerialization({mtproto: true});
|
||||||
serializer.storeMethod('http_wait', {
|
serializer.storeMethod('http_wait', {
|
||||||
max_delay: 500,
|
max_delay: 500,
|
||||||
wait_after: 150,
|
wait_after: 150,
|
||||||
@ -682,10 +682,10 @@ export default class MTPNetworker {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var noResponseMsgs: Array<string> = [];
|
const noResponseMsgs: Array<string> = [];
|
||||||
|
|
||||||
if(messages.length > 1) {
|
if(messages.length > 1) {
|
||||||
var container = new TLSerialization({
|
const container = new TLSerialization({
|
||||||
mtproto: true,
|
mtproto: true,
|
||||||
startMaxLength: messagesByteLen + 64
|
startMaxLength: messagesByteLen + 64
|
||||||
});
|
});
|
||||||
@ -693,7 +693,7 @@ export default class MTPNetworker {
|
|||||||
container.storeInt(0x73f1f8dc, 'CONTAINER[id]');
|
container.storeInt(0x73f1f8dc, 'CONTAINER[id]');
|
||||||
container.storeInt(messages.length, 'CONTAINER[count]');
|
container.storeInt(messages.length, 'CONTAINER[count]');
|
||||||
|
|
||||||
var innerMessages: string[] = [];
|
const innerMessages: string[] = [];
|
||||||
messages.forEach((message, i) => {
|
messages.forEach((message, i) => {
|
||||||
container.storeLong(message.msg_id, 'CONTAINER[' + i + '][msg_id]');
|
container.storeLong(message.msg_id, 'CONTAINER[' + i + '][msg_id]');
|
||||||
innerMessages.push(message.msg_id);
|
innerMessages.push(message.msg_id);
|
||||||
@ -705,7 +705,7 @@ export default class MTPNetworker {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var containerSentMessage: MTMessage = {
|
const containerSentMessage: MTMessage = {
|
||||||
msg_id: timeManager.generateID(),
|
msg_id: timeManager.generateID(),
|
||||||
seq_no: this.generateSeqNo(true),
|
seq_no: this.generateSeqNo(true),
|
||||||
container: true,
|
container: true,
|
||||||
@ -731,17 +731,19 @@ export default class MTPNetworker {
|
|||||||
|
|
||||||
this.pendingAcks = [];
|
this.pendingAcks = [];
|
||||||
|
|
||||||
let promise = this.sendEncryptedRequest(message);
|
const promise = this.sendEncryptedRequest(message);
|
||||||
|
|
||||||
/// #if MTPROTO_HTTP_UPLOAD
|
/// #if MTPROTO_HTTP_UPLOAD
|
||||||
if(!(this.transport instanceof HTTP)) {
|
if(!(this.transport instanceof HTTP)) {
|
||||||
if(noResponseMsgs.length) this.log.error('noResponseMsgs length!', noResponseMsgs);
|
if(noResponseMsgs.length) this.log.error('noResponseMsgs length!', noResponseMsgs);
|
||||||
|
this.cleanupSent(); // ! WARNING
|
||||||
} else {
|
} else {
|
||||||
this.handleSentEncryptedRequestHTTP(promise, message, noResponseMsgs);
|
this.handleSentEncryptedRequestHTTP(promise, message, noResponseMsgs);
|
||||||
}
|
}
|
||||||
/// #elif !MTPROTO_HTTP
|
/// #elif !MTPROTO_HTTP
|
||||||
//if(!(this.transport instanceof HTTP)) {
|
//if(!(this.transport instanceof HTTP)) {
|
||||||
if(noResponseMsgs.length) this.log.error('noResponseMsgs length!', noResponseMsgs);
|
if(noResponseMsgs.length) this.log.error('noResponseMsgs length!', noResponseMsgs);
|
||||||
|
this.cleanupSent(); // ! WARNING
|
||||||
//} else {
|
//} else {
|
||||||
/// #else
|
/// #else
|
||||||
this.handleSentEncryptedRequestHTTP(promise, message, noResponseMsgs);
|
this.handleSentEncryptedRequestHTTP(promise, message, noResponseMsgs);
|
||||||
@ -751,14 +753,14 @@ export default class MTPNetworker {
|
|||||||
if(lengthOverflow || singlesCount > 1) {
|
if(lengthOverflow || singlesCount > 1) {
|
||||||
this.scheduleRequest();
|
this.scheduleRequest();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
public async getEncryptedMessage(dataWithPadding: ArrayBuffer) {
|
public async getEncryptedMessage(dataWithPadding: ArrayBuffer) {
|
||||||
let msgKey = await this.getMsgKey(dataWithPadding, true);
|
const msgKey = await this.getMsgKey(dataWithPadding, true);
|
||||||
let keyIv = await this.getAesKeyIv(msgKey, true);
|
const keyIv = await this.getAesKeyIv(msgKey, true);
|
||||||
// this.log('after msg key iv')
|
// this.log('after msg key iv')
|
||||||
|
|
||||||
let encryptedBytes = await CryptoWorker.aesEncrypt(dataWithPadding, keyIv[0], keyIv[1]);
|
const encryptedBytes = await CryptoWorker.aesEncrypt(dataWithPadding, keyIv[0], keyIv[1]);
|
||||||
// this.log('Finish encrypt')
|
// this.log('Finish encrypt')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -775,10 +777,8 @@ export default class MTPNetworker {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendEncryptedRequest(message: MTMessage, options: any = {}) {
|
public sendEncryptedRequest(message: MTMessage) {
|
||||||
const self = this;
|
this.log.debug('Send encrypted', message, this.authKeyID);
|
||||||
|
|
||||||
this.log.debug('Send encrypted', message, options, this.authKeyID);
|
|
||||||
// console.trace()
|
// console.trace()
|
||||||
const data = new TLSerialization({
|
const data = new TLSerialization({
|
||||||
startMaxLength: message.body.length + 2048
|
startMaxLength: message.body.length + 2048
|
||||||
@ -813,7 +813,7 @@ export default class MTPNetworker {
|
|||||||
const request = new TLSerialization({
|
const request = new TLSerialization({
|
||||||
startMaxLength: encryptedResult.bytes.length + 256
|
startMaxLength: encryptedResult.bytes.length + 256
|
||||||
});
|
});
|
||||||
request.storeIntBytes(self.authKeyID, 64, 'auth_key_id');
|
request.storeIntBytes(this.authKeyID, 64, 'auth_key_id');
|
||||||
request.storeIntBytes(encryptedResult.msgKey, 128, 'msg_key');
|
request.storeIntBytes(encryptedResult.msgKey, 128, 'msg_key');
|
||||||
request.storeRawBytes(encryptedResult.bytes, 'encrypted_data');
|
request.storeRawBytes(encryptedResult.bytes, 'encrypted_data');
|
||||||
|
|
||||||
@ -826,9 +826,9 @@ export default class MTPNetworker {
|
|||||||
transport: this.transport
|
transport: this.transport
|
||||||
};
|
};
|
||||||
|
|
||||||
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);
|
||||||
}
|
} */
|
||||||
|
|
||||||
const promise = this.transport.send(requestData);
|
const promise = this.transport.send(requestData);
|
||||||
/// #if !MTPROTO_HTTP && !MTPROTO_HTTP_UPLOAD
|
/// #if !MTPROTO_HTTP && !MTPROTO_HTTP_UPLOAD
|
||||||
@ -858,19 +858,19 @@ export default class MTPNetworker {
|
|||||||
public parseResponse(responseBuffer: Uint8Array) {
|
public parseResponse(responseBuffer: Uint8Array) {
|
||||||
this.log.debug('Start parsing response'/* , responseBuffer */);
|
this.log.debug('Start parsing response'/* , responseBuffer */);
|
||||||
|
|
||||||
let self = this;
|
const deserializer = new TLDeserialization(responseBuffer);
|
||||||
let deserializer = new TLDeserialization(responseBuffer);
|
|
||||||
|
|
||||||
let authKeyID = deserializer.fetchIntBytes(64, true, 'auth_key_id');
|
const authKeyID = deserializer.fetchIntBytes(64, true, 'auth_key_id');
|
||||||
if(!bytesCmp(authKeyID, this.authKeyID)) {
|
if(!bytesCmp(authKeyID, this.authKeyID)) {
|
||||||
throw new Error('[MT] Invalid server auth_key_id: ' + authKeyID.hex);
|
throw new Error('[MT] Invalid server auth_key_id: ' + authKeyID.hex);
|
||||||
}
|
}
|
||||||
let msgKey = deserializer.fetchIntBytes(128, true, 'msg_key');
|
|
||||||
let encryptedData = deserializer.fetchRawBytes(responseBuffer.byteLength - deserializer.getOffset(), true, 'encrypted_data');
|
|
||||||
|
|
||||||
return self.getDecryptedMessage(msgKey, encryptedData).then((dataWithPadding) => {
|
const msgKey = deserializer.fetchIntBytes(128, true, 'msg_key');
|
||||||
|
const encryptedData = deserializer.fetchRawBytes(responseBuffer.byteLength - deserializer.getOffset(), true, 'encrypted_data');
|
||||||
|
|
||||||
|
return this.getDecryptedMessage(msgKey, encryptedData).then((dataWithPadding) => {
|
||||||
// this.log('after decrypt')
|
// this.log('after decrypt')
|
||||||
return self.getMsgKey(dataWithPadding, false).then((calcMsgKey) => {
|
return this.getMsgKey(dataWithPadding, false).then((calcMsgKey) => {
|
||||||
if(!bytesCmp(msgKey, calcMsgKey)) {
|
if(!bytesCmp(msgKey, calcMsgKey)) {
|
||||||
this.log.warn('[MT] msg_keys', msgKey, calcMsgKey);
|
this.log.warn('[MT] msg_keys', msgKey, calcMsgKey);
|
||||||
this.updateSession(); // fix 28.01.2020
|
this.updateSession(); // fix 28.01.2020
|
||||||
@ -880,103 +880,103 @@ export default class MTPNetworker {
|
|||||||
|
|
||||||
let deserializer = new TLDeserialization(dataWithPadding, {mtproto: true});
|
let deserializer = new TLDeserialization(dataWithPadding, {mtproto: true});
|
||||||
|
|
||||||
/* let salt = */deserializer.fetchIntBytes(64, false, 'salt'); // need
|
/* const salt = */deserializer.fetchIntBytes(64, false, 'salt'); // need
|
||||||
let sessionID = deserializer.fetchIntBytes(64, false, 'session_id');
|
const sessionID = deserializer.fetchIntBytes(64, false, 'session_id');
|
||||||
let messageID = deserializer.fetchLong('message_id');
|
const messageID = deserializer.fetchLong('message_id');
|
||||||
|
|
||||||
if(!bytesCmp(sessionID, self.sessionID) &&
|
if(!bytesCmp(sessionID, this.sessionID) &&
|
||||||
(!self.prevSessionID || !bytesCmp(sessionID, self.prevSessionID))) {
|
(!this.prevSessionID || !bytesCmp(sessionID, this.prevSessionID))) {
|
||||||
this.log.warn('Sessions', sessionID, self.sessionID, self.prevSessionID, dataWithPadding);
|
this.log.warn('Sessions', sessionID, this.sessionID, this.prevSessionID, dataWithPadding);
|
||||||
//this.updateSession();
|
//this.updateSession();
|
||||||
//this.sessionID = sessionID;
|
//this.sessionID = sessionID;
|
||||||
throw new Error('[MT] Invalid server session_id: ' + bytesToHex(sessionID));
|
throw new Error('[MT] Invalid server session_id: ' + bytesToHex(sessionID));
|
||||||
}
|
}
|
||||||
|
|
||||||
let seqNo = deserializer.fetchInt('seq_no');
|
const seqNo = deserializer.fetchInt('seq_no');
|
||||||
|
|
||||||
let totalLength = dataWithPadding.byteLength;
|
const totalLength = dataWithPadding.byteLength;
|
||||||
|
|
||||||
let messageBodyLength = deserializer.fetchInt('message_data[length]');
|
const messageBodyLength = deserializer.fetchInt('message_data[length]');
|
||||||
let offset = deserializer.getOffset();
|
let offset = deserializer.getOffset();
|
||||||
|
|
||||||
if((messageBodyLength % 4) ||
|
if((messageBodyLength % 4) ||
|
||||||
messageBodyLength > totalLength - offset) {
|
messageBodyLength > totalLength - offset) {
|
||||||
throw new Error('[MT] Invalid body length: ' + messageBodyLength);
|
throw new Error('[MT] Invalid body length: ' + messageBodyLength);
|
||||||
}
|
}
|
||||||
let messageBody = deserializer.fetchRawBytes(messageBodyLength, true, 'message_data');
|
const messageBody = deserializer.fetchRawBytes(messageBodyLength, true, 'message_data');
|
||||||
|
|
||||||
offset = deserializer.getOffset();
|
offset = deserializer.getOffset();
|
||||||
let paddingLength = totalLength - offset;
|
const paddingLength = totalLength - offset;
|
||||||
if(paddingLength < 12 || paddingLength > 1024) {
|
if(paddingLength < 12 || paddingLength > 1024) {
|
||||||
throw new Error('[MT] Invalid padding length: ' + paddingLength);
|
throw new Error('[MT] Invalid padding length: ' + paddingLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
//let buffer = bytesToArrayBuffer(messageBody);
|
//let buffer = bytesToArrayBuffer(messageBody);
|
||||||
deserializer = new TLDeserialization(/* buffer */messageBody, {mtproto: true});
|
deserializer = new TLDeserialization(/* buffer */messageBody, {
|
||||||
// костыль
|
mtproto: true,
|
||||||
deserializer.override = {
|
override: {
|
||||||
mt_message: (function(this: TLDeserialization, result: any, field: string) {
|
mt_message: (result: any, field: string) => {
|
||||||
result.msg_id = this.fetchLong(field + '[msg_id]');
|
result.msg_id = deserializer.fetchLong(field + '[msg_id]');
|
||||||
result.seqno = this.fetchInt(field + '[seqno]');
|
result.seqno = deserializer.fetchInt(field + '[seqno]');
|
||||||
result.bytes = this.fetchInt(field + '[bytes]');
|
result.bytes = deserializer.fetchInt(field + '[bytes]');
|
||||||
|
|
||||||
var offset = this.getOffset();
|
const offset = deserializer.getOffset();
|
||||||
|
|
||||||
//self.log('mt_message!!!!!', result, field);
|
//self.log('mt_message!!!!!', result, field);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result.body = this.fetchObject('Object', field + '[body]');
|
result.body = deserializer.fetchObject('Object', field + '[body]');
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
self.log.error('parse error', e.message, e.stack);
|
this.log.error('parse error', e.message, e.stack);
|
||||||
result.body = {
|
result.body = {
|
||||||
_: 'parse_error',
|
_: 'parse_error',
|
||||||
error: e
|
error: e
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if(this.offset != offset + result.bytes) {
|
|
||||||
|
if(deserializer.offset != offset + result.bytes) {
|
||||||
// console.warn(dT(), 'set offset', this.offset, offset, result.bytes)
|
// console.warn(dT(), 'set offset', this.offset, offset, result.bytes)
|
||||||
// this.log(result)
|
// this.log(result)
|
||||||
this.offset = offset + result.bytes;
|
deserializer.offset = offset + result.bytes;
|
||||||
}
|
}
|
||||||
// this.log('override message', result)
|
// this.log('override message', result)
|
||||||
}).bind(deserializer),
|
},
|
||||||
mt_rpc_result: (function(this: TLDeserialization, result: any, field: any) {
|
mt_rpc_result: (result: any, field: any) => {
|
||||||
result.req_msg_id = this.fetchLong(field + '[req_msg_id]');
|
result.req_msg_id = deserializer.fetchLong(field + '[req_msg_id]');
|
||||||
|
|
||||||
var sentMessage = self.sentMessages[result.req_msg_id];
|
const sentMessage = this.sentMessages[result.req_msg_id];
|
||||||
var type = sentMessage && sentMessage.resultType || 'Object';
|
const type = sentMessage && sentMessage.resultType || 'Object';
|
||||||
|
|
||||||
if(result.req_msg_id && !sentMessage) {
|
if(result.req_msg_id && !sentMessage) {
|
||||||
// console.warn(dT(), 'Result for unknown message', result);
|
// console.warn(dT(), 'Result for unknown message', result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.result = this.fetchObject(type, field + '[result]');
|
result.result = deserializer.fetchObject(type, field + '[result]');
|
||||||
// self.log(dT(), 'override rpc_result', sentMessage, type, result);
|
// self.log(dT(), 'override rpc_result', sentMessage, type, result);
|
||||||
}).bind(deserializer)
|
}
|
||||||
};
|
}
|
||||||
|
});
|
||||||
var response = deserializer.fetchObject('', 'INPUT');
|
|
||||||
|
|
||||||
|
const response = deserializer.fetchObject('', 'INPUT');
|
||||||
return {
|
return {
|
||||||
response: response,
|
response,
|
||||||
messageID: messageID,
|
messageID,
|
||||||
sessionID: sessionID,
|
sessionID,
|
||||||
seqNo: seqNo
|
seqNo
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public applyServerSalt(newServerSalt: string) {
|
public applyServerSalt(newServerSalt: string) {
|
||||||
var serverSalt = longToBytes(newServerSalt);
|
const serverSalt = longToBytes(newServerSalt);
|
||||||
|
|
||||||
AppStorage.set({
|
AppStorage.set({
|
||||||
['dc' + this.dcID + '_server_salt']: bytesToHex(serverSalt)
|
['dc' + this.dcID + '_server_salt']: bytesToHex(serverSalt)
|
||||||
});
|
});
|
||||||
|
|
||||||
this.serverSalt = serverSalt;
|
this.serverSalt = serverSalt;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public scheduleRequest(delay = 0) {
|
public scheduleRequest(delay = 0) {
|
||||||
@ -1007,9 +1007,9 @@ export default class MTPNetworker {
|
|||||||
clearTimeout(this.nextReqTimeout);
|
clearTimeout(this.nextReqTimeout);
|
||||||
this.nextReqTimeout = 0;
|
this.nextReqTimeout = 0;
|
||||||
if(delay > 0) {
|
if(delay > 0) {
|
||||||
this.nextReqTimeout = self.setTimeout(this.performScheduledRequest.bind(this), delay || 0);
|
this.nextReqTimeout = self.setTimeout(this.performScheduledRequest, delay || 0);
|
||||||
} else {
|
} else {
|
||||||
setTimeout(this.performScheduledRequest.bind(this), 0);
|
setTimeout(this.performScheduledRequest, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.nextReq = nextReq;
|
this.nextReq = nextReq;
|
||||||
@ -1039,8 +1039,8 @@ export default class MTPNetworker {
|
|||||||
// this.log('clean notContentRelated', msgID)
|
// this.log('clean notContentRelated', msgID)
|
||||||
delete this.sentMessages[msgID];
|
delete this.sentMessages[msgID];
|
||||||
} else if(message.container) {
|
} else if(message.container) {
|
||||||
for(let i = 0; i < message.inner.length; i++) {
|
for(const innerMsgID of message.inner) {
|
||||||
if(this.sentMessages[message.inner[i]] !== undefined) {
|
if(this.sentMessages[innerMsgID] !== undefined) {
|
||||||
// this.log('clean failed, found', msgID, message.inner[i], this.sentMessages[message.inner[i]].seq_no)
|
// this.log('clean failed, found', msgID, message.inner[i], this.sentMessages[message.inner[i]].seq_no)
|
||||||
notEmpty = true;
|
notEmpty = true;
|
||||||
return;
|
return;
|
||||||
@ -1057,7 +1057,7 @@ export default class MTPNetworker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public processMessageAck(messageID: string) {
|
public processMessageAck(messageID: string) {
|
||||||
var sentMessage = this.sentMessages[messageID];
|
const sentMessage = this.sentMessages[messageID];
|
||||||
if(sentMessage && !sentMessage.acked) {
|
if(sentMessage && !sentMessage.acked) {
|
||||||
delete sentMessage.body;
|
delete sentMessage.body;
|
||||||
sentMessage.acked = true;
|
sentMessage.acked = true;
|
||||||
@ -1069,7 +1069,7 @@ export default class MTPNetworker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public processError(rawError: {error_message: string, error_code: number}) {
|
public processError(rawError: {error_message: string, error_code: number}) {
|
||||||
var matches = (rawError.error_message || '').match(/^([A-Z_0-9]+\b)(: (.+))?/) || [];
|
const matches = (rawError.error_message || '').match(/^([A-Z_0-9]+\b)(: (.+))?/) || [];
|
||||||
rawError.error_code = rawError.error_code;
|
rawError.error_code = rawError.error_code;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -1084,7 +1084,7 @@ export default class MTPNetworker {
|
|||||||
* только для сокета, возможно это будет неправильно работать, но в тесте сработало правильно
|
* только для сокета, возможно это будет неправильно работать, но в тесте сработало правильно
|
||||||
*/
|
*/
|
||||||
public resend() {
|
public resend() {
|
||||||
for(let id in this.sentMessages) {
|
for(const id in this.sentMessages) {
|
||||||
const msg = this.sentMessages[id];
|
const msg = this.sentMessages[id];
|
||||||
if(msg.body) {
|
if(msg.body) {
|
||||||
this.pushResend(id);
|
this.pushResend(id);
|
||||||
@ -1092,7 +1092,7 @@ export default class MTPNetworker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public requestMessageStatus() {
|
/* public requestMessageStatus() {
|
||||||
const ids: string[] = [];
|
const ids: string[] = [];
|
||||||
for(const id in this.sentMessages) {
|
for(const id in this.sentMessages) {
|
||||||
const message = this.sentMessages[id];
|
const message = this.sentMessages[id];
|
||||||
@ -1109,11 +1109,11 @@ export default class MTPNetworker {
|
|||||||
}).then(res => {
|
}).then(res => {
|
||||||
this.log('status', res);
|
this.log('status', res);
|
||||||
});
|
});
|
||||||
}
|
} */
|
||||||
|
|
||||||
// * https://core.telegram.org/mtproto/service_messages_about_messages#notice-of-ignored-error-message
|
// * https://core.telegram.org/mtproto/service_messages_about_messages#notice-of-ignored-error-message
|
||||||
public processMessage(message: any, messageID: string, sessionID: Uint8Array | number[]) {
|
public processMessage(message: any, messageID: string, sessionID: Uint8Array | number[]) {
|
||||||
var msgidInt = parseInt(messageID/* .toString(10) */.substr(0, -10), 10);
|
const msgidInt = parseInt(messageID.substr(0, -10), 10);
|
||||||
if(msgidInt % 2) {
|
if(msgidInt % 2) {
|
||||||
this.log.warn('[MT] Server even message id: ', messageID, message);
|
this.log.warn('[MT] Server even message id: ', messageID, message);
|
||||||
return;
|
return;
|
||||||
@ -1122,27 +1122,27 @@ export default class MTPNetworker {
|
|||||||
this.log.debug('process message', message, messageID, sessionID);
|
this.log.debug('process message', message, messageID, sessionID);
|
||||||
|
|
||||||
switch(message._) {
|
switch(message._) {
|
||||||
case 'msg_container':
|
case 'msg_container': {
|
||||||
var len = message.messages.length;
|
for(const innerMessage of message.messages) {
|
||||||
for(var i = 0; i < len; i++) {
|
this.processMessage(innerMessage, innerMessage.msg_id, sessionID);
|
||||||
this.processMessage(message.messages[i], message.messages[i].msg_id, sessionID);
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case 'bad_server_salt':
|
break;
|
||||||
this.log('Bad server salt', message);
|
|
||||||
var sentMessage = this.sentMessages[message.bad_msg_id];
|
|
||||||
if(!sentMessage || sentMessage.seq_no != message.bad_msg_seqno) {
|
|
||||||
this.log(message.bad_msg_id, message.bad_msg_seqno);
|
|
||||||
throw new Error('[MT] Bad server salt for invalid message');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'bad_server_salt': {
|
||||||
|
this.log('Bad server salt', message);
|
||||||
|
|
||||||
this.applyServerSalt(message.new_server_salt);
|
this.applyServerSalt(message.new_server_salt);
|
||||||
|
|
||||||
|
if(this.sentMessages[message.bad_msg_id]) {
|
||||||
this.pushResend(message.bad_msg_id);
|
this.pushResend(message.bad_msg_id);
|
||||||
|
}
|
||||||
|
|
||||||
this.ackMessage(messageID);
|
this.ackMessage(messageID);
|
||||||
|
|
||||||
/* // simulate disconnect
|
// simulate disconnect
|
||||||
try {
|
/* try {
|
||||||
this.log('networker state:', this);
|
this.log('networker state:', this);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.transport.ws.close(1000);
|
this.transport.ws.close(1000);
|
||||||
@ -1151,19 +1151,14 @@ export default class MTPNetworker {
|
|||||||
} */
|
} */
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'bad_msg_notification':
|
|
||||||
var sentMessage = this.sentMessages[message.bad_msg_id];
|
|
||||||
this.log.error('Bad msg notification', message, sentMessage);
|
|
||||||
if(!sentMessage || sentMessage.seq_no != message.bad_msg_seqno) {
|
|
||||||
this.log(message.bad_msg_id, message.bad_msg_seqno);
|
|
||||||
throw new Error('[MT] Bad msg notification for invalid message');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'bad_msg_notification': {
|
||||||
|
this.log.error('Bad msg notification', message);
|
||||||
|
|
||||||
if(message.error_code == 16 || message.error_code == 17) {
|
if(message.error_code == 16 || message.error_code == 17) {
|
||||||
if(timeManager.applyServerTime(
|
const changedOffset = timeManager.applyServerTime(bigStringInt(messageID).shiftRight(32).toString(10));
|
||||||
bigStringInt(messageID).shiftRight(32).toString(10)
|
if(message.error_code == 17 || changedOffset) {
|
||||||
)) {
|
|
||||||
this.log('Update session');
|
this.log('Update session');
|
||||||
this.updateSession();
|
this.updateSession();
|
||||||
}
|
}
|
||||||
@ -1172,22 +1167,28 @@ export default class MTPNetworker {
|
|||||||
if(badMessage) this.pushResend(badMessage.msg_id); // fix 23.01.2020
|
if(badMessage) this.pushResend(badMessage.msg_id); // fix 23.01.2020
|
||||||
this.ackMessage(messageID);
|
this.ackMessage(messageID);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case 'message':
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'message': {
|
||||||
if(this.lastServerMessages.indexOf(messageID) != -1) {
|
if(this.lastServerMessages.indexOf(messageID) != -1) {
|
||||||
// console.warn('[MT] Server same messageID: ', messageID)
|
// console.warn('[MT] Server same messageID: ', messageID)
|
||||||
this.ackMessage(messageID);
|
this.ackMessage(messageID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lastServerMessages.push(messageID);
|
this.lastServerMessages.push(messageID);
|
||||||
if(this.lastServerMessages.length > 100) {
|
if(this.lastServerMessages.length > 100) {
|
||||||
this.lastServerMessages.shift();
|
this.lastServerMessages.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.processMessage(message.body, message.msg_id, sessionID);
|
this.processMessage(message.body, message.msg_id, sessionID);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'new_session_created':
|
|
||||||
|
case 'new_session_created': {
|
||||||
this.ackMessage(messageID);
|
this.ackMessage(messageID);
|
||||||
|
|
||||||
this.log.debug('new_session_created', message);
|
this.log.debug('new_session_created', message);
|
||||||
@ -1202,12 +1203,15 @@ export default class MTPNetworker {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'msgs_ack':
|
|
||||||
for(var i = 0; i < message.msg_ids.length; i++) {
|
|
||||||
this.processMessageAck(message.msg_ids[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'msgs_ack': {
|
||||||
|
for(const msgID of message.msg_ids) {
|
||||||
|
this.processMessageAck(msgID);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'msg_detailed_info':
|
case 'msg_detailed_info':
|
||||||
if(!this.sentMessages[message.msg_id]) {
|
if(!this.sentMessages[message.msg_id]) {
|
||||||
@ -1221,34 +1225,34 @@ export default class MTPNetworker {
|
|||||||
this.reqResendMessage(message.answer_msg_id);
|
this.reqResendMessage(message.answer_msg_id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'msgs_state_info':
|
case 'msgs_state_info': {
|
||||||
this.ackMessage(message.answer_msg_id);
|
this.ackMessage(message.answer_msg_id);
|
||||||
if(this.lastResendReq &&
|
if(this.lastResendReq &&
|
||||||
this.lastResendReq.req_msg_id == message.req_msg_id &&
|
this.lastResendReq.req_msg_id == message.req_msg_id &&
|
||||||
this.pendingResends.length
|
this.pendingResends.length
|
||||||
) {
|
) {
|
||||||
var badMsgID, pos;
|
for(const badMsgID of this.lastResendReq.resend_msg_ids) {
|
||||||
for(let i = 0; i < this.lastResendReq.resend_msg_ids.length; i++) {
|
const pos = this.pendingResends.indexOf(badMsgID);
|
||||||
badMsgID = this.lastResendReq.resend_msg_ids[i];
|
|
||||||
pos = this.pendingResends.indexOf(badMsgID);
|
|
||||||
if(pos != -1) {
|
if(pos != -1) {
|
||||||
this.pendingResends.splice(pos, 1);
|
this.pendingResends.splice(pos, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case 'rpc_result':
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'rpc_result': {
|
||||||
this.ackMessage(messageID);
|
this.ackMessage(messageID);
|
||||||
|
|
||||||
var sentMessageID = message.req_msg_id;
|
const sentMessageID = message.req_msg_id;
|
||||||
var sentMessage = this.sentMessages[sentMessageID];
|
const sentMessage = this.sentMessages[sentMessageID];
|
||||||
|
|
||||||
this.processMessageAck(sentMessageID);
|
this.processMessageAck(sentMessageID);
|
||||||
if(sentMessage) {
|
if(sentMessage) {
|
||||||
var deferred = sentMessage.deferred;
|
const deferred = sentMessage.deferred;
|
||||||
if(message.result._ == 'rpc_error') {
|
if(message.result._ == 'rpc_error') {
|
||||||
var error = this.processError(message.result);
|
const error = this.processError(message.result);
|
||||||
this.log('Rpc error', error);
|
this.log('Rpc error', error);
|
||||||
if(deferred) {
|
if(deferred) {
|
||||||
deferred.reject(error);
|
deferred.reject(error);
|
||||||
@ -1258,7 +1262,7 @@ export default class MTPNetworker {
|
|||||||
if(Modes.debug) {
|
if(Modes.debug) {
|
||||||
this.log.debug('Rpc response', message.result);
|
this.log.debug('Rpc response', message.result);
|
||||||
} else {
|
} else {
|
||||||
var dRes = message.result._;
|
let dRes = message.result._;
|
||||||
if(!dRes) {
|
if(!dRes) {
|
||||||
if(message.result.length > 5) {
|
if(message.result.length > 5) {
|
||||||
dRes = '[..' + message.result.length + '..]';
|
dRes = '[..' + message.result.length + '..]';
|
||||||
@ -1266,6 +1270,7 @@ export default class MTPNetworker {
|
|||||||
dRes = message.result;
|
dRes = message.result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.log.debug('Rpc response', dRes, sentMessage);
|
this.log.debug('Rpc response', dRes, sentMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1281,6 +1286,7 @@ export default class MTPNetworker {
|
|||||||
delete this.sentMessages[sentMessageID];
|
delete this.sentMessages[sentMessageID];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.ackMessage(messageID);
|
this.ackMessage(messageID);
|
||||||
|
@ -14,12 +14,12 @@ export class TimeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public generateID(): string {
|
public generateID(): string {
|
||||||
var timeTicks = Date.now(),
|
const timeTicks = Date.now(),
|
||||||
timeSec = Math.floor(timeTicks / 1000) + this.timeOffset,
|
timeSec = Math.floor(timeTicks / 1000) + this.timeOffset,
|
||||||
timeMSec = timeTicks % 1000,
|
timeMSec = timeTicks % 1000,
|
||||||
random = nextRandomInt(0xFFFF);
|
random = nextRandomInt(0xFFFF);
|
||||||
|
|
||||||
var messageID = [timeSec, (timeMSec << 21) | (random << 3) | 4];
|
let messageID = [timeSec, (timeMSec << 21) | (random << 3) | 4];
|
||||||
if(this.lastMessageID[0] > messageID[0] ||
|
if(this.lastMessageID[0] > messageID[0] ||
|
||||||
this.lastMessageID[0] == messageID[0] && this.lastMessageID[1] >= messageID[1]) {
|
this.lastMessageID[0] == messageID[0] && this.lastMessageID[1] >= messageID[1]) {
|
||||||
messageID = [this.lastMessageID[0], this.lastMessageID[1] + 4];
|
messageID = [this.lastMessageID[0], this.lastMessageID[1] + 4];
|
||||||
@ -27,21 +27,25 @@ export class TimeManager {
|
|||||||
|
|
||||||
this.lastMessageID = messageID;
|
this.lastMessageID = messageID;
|
||||||
|
|
||||||
// console.log('generated msg id', messageID, timeOffset)
|
const ret = longFromInts(messageID[0], messageID[1]);
|
||||||
|
|
||||||
return longFromInts(messageID[0], messageID[1]);
|
//console.log('[TimeManager]: Generated msg id', messageID, this.timeOffset, ret);
|
||||||
|
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
public applyServerTime(serverTime: number, localTime?: number) {
|
public applyServerTime(serverTime: number, localTime?: number) {
|
||||||
var newTimeOffset = serverTime - Math.floor((localTime || Date.now()) / 1000);
|
localTime = (localTime || Date.now()) / 1000 | 0;
|
||||||
var changed = Math.abs(this.timeOffset - newTimeOffset) > 10;
|
const newTimeOffset = serverTime - localTime;
|
||||||
|
const changed = Math.abs(this.timeOffset - newTimeOffset) > 10;
|
||||||
AppStorage.set({
|
AppStorage.set({
|
||||||
server_time_offset: newTimeOffset
|
server_time_offset: newTimeOffset
|
||||||
});
|
});
|
||||||
|
|
||||||
this.lastMessageID = [0, 0];
|
this.lastMessageID = [0, 0];
|
||||||
this.timeOffset = newTimeOffset;
|
this.timeOffset = newTimeOffset;
|
||||||
//console.log(dT(), 'Apply server time', serverTime, localTime, newTimeOffset, changed);
|
|
||||||
|
//console.log('[TimeManager]: Apply server time', serverTime, localTime, newTimeOffset, changed);
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
@ -396,7 +396,7 @@ class TLSerialization {
|
|||||||
|
|
||||||
class TLDeserialization {
|
class TLDeserialization {
|
||||||
public offset = 0; // in bytes
|
public offset = 0; // in bytes
|
||||||
public override: any;
|
public override: {[key: string]: (result: any, field: string) => void};
|
||||||
|
|
||||||
public buffer: ArrayBuffer;
|
public buffer: ArrayBuffer;
|
||||||
//public intView: Uint32Array;
|
//public intView: Uint32Array;
|
||||||
@ -616,13 +616,13 @@ class TLDeserialization {
|
|||||||
|
|
||||||
if(type.substr(0, 6) == 'Vector' || type.substr(0, 6) == 'vector') {
|
if(type.substr(0, 6) == 'Vector' || type.substr(0, 6) == 'vector') {
|
||||||
if(type.charAt(0) == 'V') {
|
if(type.charAt(0) == 'V') {
|
||||||
var constructor = this.readInt(field + '[id]');
|
const constructor = this.readInt(field + '[id]');
|
||||||
var constructorCmp = constructor;
|
const constructorCmp = constructor;
|
||||||
|
|
||||||
if(constructorCmp == gzipPacked) { // Gzip packed
|
if(constructorCmp == gzipPacked) { // Gzip packed
|
||||||
var compressed = this.fetchBytes(field + '[packed_string]');
|
const compressed = this.fetchBytes(field + '[packed_string]');
|
||||||
var uncompressed = gzipUncompress(compressed);
|
const uncompressed = gzipUncompress(compressed);
|
||||||
var newDeserializer = new TLDeserialization(uncompressed);
|
const newDeserializer = new TLDeserialization(uncompressed);
|
||||||
|
|
||||||
return newDeserializer.fetchObject(type, field);
|
return newDeserializer.fetchObject(type, field);
|
||||||
}
|
}
|
||||||
@ -632,11 +632,11 @@ class TLDeserialization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var len = this.readInt(field + '[count]');
|
const len = this.readInt(field + '[count]');
|
||||||
var result: any = [];
|
const result: any = [];
|
||||||
if(len > 0) {
|
if(len > 0) {
|
||||||
var itemType = type.substr(7, type.length - 8); // for "Vector<itemType>"
|
const itemType = type.substr(7, type.length - 8); // for "Vector<itemType>"
|
||||||
for(var i = 0; i < len; i++) {
|
for(let i = 0; i < len; i++) {
|
||||||
result.push(this.fetchObject(itemType, field + '[' + i + ']'));
|
result.push(this.fetchObject(itemType, field + '[' + i + ']'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -644,62 +644,49 @@ class TLDeserialization {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
var schema = this.mtproto ? Schema.MTProto : Schema.API;
|
const schema = this.mtproto ? Schema.MTProto : Schema.API;
|
||||||
var predicate = false;
|
let constructorData: MTProtoConstructor = null;
|
||||||
var constructorData: any = false;
|
let fallback = false;
|
||||||
|
|
||||||
if(type.charAt(0) == '%') {
|
if(type.charAt(0) == '%') {
|
||||||
var checkType = type.substr(1);
|
const checkType = type.substr(1);
|
||||||
for(var i = 0; i < schema.constructors.length; i++) {
|
constructorData = schema.constructors.find(c => c.type == checkType);
|
||||||
if(schema.constructors[i].type == checkType) {
|
|
||||||
constructorData = schema.constructors[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!constructorData) {
|
if(!constructorData) {
|
||||||
throw new Error('Constructor not found for type: ' + type);
|
throw new Error('Constructor not found for type: ' + type);
|
||||||
}
|
}
|
||||||
} else if(type.charAt(0) >= 97 && type.charAt(0) <= 122) {
|
} else if(type.charAt(0) >= 97 && type.charAt(0) <= 122) {
|
||||||
for(var i = 0; i < schema.constructors.length; i++) {
|
constructorData = schema.constructors.find(c => c.predicate == type);
|
||||||
if(schema.constructors[i].predicate == type) {
|
|
||||||
constructorData = schema.constructors[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!constructorData) {
|
if(!constructorData) {
|
||||||
throw new Error('Constructor not found for predicate: ' + type);
|
throw new Error('Constructor not found for predicate: ' + type);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var constructor = this.readInt(field + '[id]');
|
const constructor = this.readInt(field + '[id]');
|
||||||
var constructorCmp = constructor;
|
const constructorCmp = constructor;
|
||||||
|
|
||||||
if(constructorCmp == gzipPacked) { // Gzip packed
|
if(constructorCmp == gzipPacked) { // Gzip packed
|
||||||
var compressed = this.fetchBytes(field + '[packed_string]');
|
const compressed = this.fetchBytes(field + '[packed_string]');
|
||||||
var uncompressed = gzipUncompress(compressed);
|
const uncompressed = gzipUncompress(compressed);
|
||||||
var newDeserializer = new TLDeserialization(uncompressed);
|
const newDeserializer = new TLDeserialization(uncompressed);
|
||||||
|
|
||||||
return newDeserializer.fetchObject(type, field);
|
return newDeserializer.fetchObject(type, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
var index = schema.constructorsIndex;
|
let index = schema.constructorsIndex;
|
||||||
if(!index) {
|
if(!index) {
|
||||||
schema.constructorsIndex = index = {};
|
schema.constructorsIndex = index = {};
|
||||||
for(var i = 0; i < schema.constructors.length; i++) {
|
for(let i = 0, len = schema.constructors.length; i < len; i++) {
|
||||||
index[schema.constructors[i].id] = i;
|
index[schema.constructors[i].id] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var i = index[constructorCmp];
|
const i = index[constructorCmp];
|
||||||
if(i) {
|
if(i) {
|
||||||
constructorData = schema.constructors[i];
|
constructorData = schema.constructors[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
var fallback = false;
|
|
||||||
if(!constructorData && this.mtproto) {
|
if(!constructorData && this.mtproto) {
|
||||||
var schemaFallback = Schema.API;
|
const schemaFallback = Schema.API;
|
||||||
for(i = 0; i < schemaFallback.constructors.length; i++) {
|
for(let i = 0, len = schemaFallback.constructors.length; i < len; i++) {
|
||||||
if(+schemaFallback.constructors[i].id == constructorCmp) {
|
if(+schemaFallback.constructors[i].id == constructorCmp) {
|
||||||
constructorData = schemaFallback.constructors[i];
|
constructorData = schemaFallback.constructors[i];
|
||||||
|
|
||||||
@ -715,33 +702,27 @@ class TLDeserialization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate = constructorData.predicate;
|
const predicate = constructorData.predicate;
|
||||||
|
|
||||||
var result: any = {'_': predicate};
|
|
||||||
var overrideKey = (this.mtproto ? 'mt_' : '') + predicate;
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
|
const result: any = {'_': predicate};
|
||||||
|
const overrideKey = (this.mtproto ? 'mt_' : '') + predicate;
|
||||||
if(this.override[overrideKey]) {
|
if(this.override[overrideKey]) {
|
||||||
this.override[overrideKey].apply(this, [result, field + '[' + predicate + ']']);
|
this.override[overrideKey](result, field + '[' + predicate + ']');
|
||||||
} else {
|
} else {
|
||||||
var i: number, param;
|
for(let i = 0, len = constructorData.params.length; i < len; i++) {
|
||||||
var type, isCond;
|
const param = constructorData.params[i];
|
||||||
var condType, fieldBit;
|
let type = param.type;
|
||||||
var value;
|
|
||||||
var len: number = constructorData.params.length;
|
|
||||||
for(i = 0; i < len; i++) {
|
|
||||||
param = constructorData.params[i];
|
|
||||||
type = param.type;
|
|
||||||
|
|
||||||
if(type == '#' && result.pFlags === undefined) {
|
if(type == '#' && result.pFlags === undefined) {
|
||||||
result.pFlags = {};
|
result.pFlags = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isCond = (type.indexOf('?') !== -1)) {
|
const isCond = (type.indexOf('?') !== -1);
|
||||||
condType = type.split('?');
|
if(isCond) {
|
||||||
fieldBit = condType[0].split('.');
|
const condType = type.split('?');
|
||||||
|
const fieldBit = condType[0].split('.');
|
||||||
|
|
||||||
if(!(result[fieldBit[0]] & (1 << fieldBit[1]))) {
|
if(!(result[fieldBit[0]] & (1 << +fieldBit[1]))) {
|
||||||
//console.log('fetchObject bad', constructorData, result[fieldBit[0]], fieldBit);
|
//console.log('fetchObject bad', constructorData, result[fieldBit[0]], fieldBit);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -751,7 +732,7 @@ class TLDeserialization {
|
|||||||
type = condType[1];
|
type = condType[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
value = self.fetchObject(type, field + '[' + predicate + '][' + param.name + ']');
|
const value = this.fetchObject(type, field + '[' + predicate + '][' + param.name + ']');
|
||||||
|
|
||||||
if(isCond && type === 'true') {
|
if(isCond && type === 'true') {
|
||||||
result.pFlags[param.name] = value;
|
result.pFlags[param.name] = value;
|
||||||
|
@ -67,6 +67,11 @@ export default class Socket extends MTTransport {
|
|||||||
this.connected = true;
|
this.connected = true;
|
||||||
|
|
||||||
this.releasePending();
|
this.releasePending();
|
||||||
|
|
||||||
|
if(this.networker && this.lastCloseTime) {
|
||||||
|
this.networker.cleanupSent();
|
||||||
|
this.networker.resend();
|
||||||
|
}
|
||||||
//}, 3e3);
|
//}, 3e3);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -75,37 +80,29 @@ export default class Socket extends MTTransport {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleClose = (event: CloseEvent) => {
|
handleClose = (event: CloseEvent) => {
|
||||||
this.log('closed', event, this.pending);
|
this.log('closed', event, this.pending, this.ws.bufferedAmount);
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
|
|
||||||
const time = Date.now();
|
const time = Date.now();
|
||||||
const diff = time - this.lastCloseTime;
|
const diff = time - this.lastCloseTime;
|
||||||
let needTimeout = !isNaN(diff) && diff < CONNECTION_RETRY_TIMEOUT ? CONNECTION_RETRY_TIMEOUT - diff : 0;
|
const needTimeout = !isNaN(diff) && diff < CONNECTION_RETRY_TIMEOUT ? CONNECTION_RETRY_TIMEOUT - diff : 0;
|
||||||
|
|
||||||
//this.pending.length = 0;
|
|
||||||
/* if(this.networker) {
|
|
||||||
this.networker.resend();
|
|
||||||
this.networker.cleanupSent();
|
|
||||||
} */
|
|
||||||
|
|
||||||
this.log('will try to reconnect after timeout:', needTimeout / 1000);
|
this.log('will try to reconnect after timeout:', needTimeout / 1000);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.log('trying to reconnect...');
|
this.log('trying to reconnect...');
|
||||||
this.lastCloseTime = Date.now();
|
this.lastCloseTime = Date.now();
|
||||||
this.connect();
|
|
||||||
|
|
||||||
for(let pending of this.pending) {
|
for(const pending of this.pending) {
|
||||||
if(pending.bodySent) {
|
if(pending.bodySent) {
|
||||||
pending.bodySent = false;
|
pending.bodySent = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.networker) {
|
if(this.networker) {
|
||||||
this.ws.addEventListener('open', () => {
|
this.pending
|
||||||
this.networker.resend();
|
|
||||||
this.networker.cleanupSent();
|
|
||||||
}, {once: true});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.connect();
|
||||||
}, needTimeout);
|
}, needTimeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -126,7 +123,7 @@ export default class Socket extends MTTransport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//console.log('got hex:', data.hex);
|
//console.log('got hex:', data.hex);
|
||||||
let pending = this.pending.shift();
|
const pending = this.pending.shift();
|
||||||
if(!pending) {
|
if(!pending) {
|
||||||
return this.log.debug('no pending for res:', data.hex);
|
return this.log.debug('no pending for res:', data.hex);
|
||||||
}
|
}
|
||||||
@ -177,9 +174,13 @@ export default class Socket extends MTTransport {
|
|||||||
this.log.error('bufferedAmount:', this.ws.bufferedAmount);
|
this.log.error('bufferedAmount:', this.ws.bufferedAmount);
|
||||||
} */
|
} */
|
||||||
|
|
||||||
//setTimeout(() => {
|
if(this.ws.readyState !== this.ws.OPEN) {
|
||||||
|
this.log.error('ws is closed?');
|
||||||
|
this.connected = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
this.ws.send(enc);
|
this.ws.send(enc);
|
||||||
//}, 500);
|
|
||||||
|
|
||||||
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);
|
||||||
|
@ -159,11 +159,11 @@ $bubble-margin: .25rem;
|
|||||||
&-select-checkbox {
|
&-select-checkbox {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
/* left: 0;
|
|
||||||
bottom: .75rem; // * by avatar */
|
|
||||||
left: 0;
|
left: 0;
|
||||||
|
bottom: .75rem; // * by avatar
|
||||||
|
/* left: 0;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%); */
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
[type="checkbox"] {
|
[type="checkbox"] {
|
||||||
|
@ -45,6 +45,8 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-bottom: 1px solid #dadce0;
|
border-bottom: 1px solid #dadce0;
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, .16);
|
||||||
|
|
||||||
.scrollable {
|
.scrollable {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user