Browse Source

Maybe fixed network disconnect

Fix audio waveform
Fix video preview resolution in reply
Fix USA country on auth page
master
morethanwords 4 years ago
parent
commit
1d214b38e3
  1. 20
      src/components/audio.ts
  2. 28
      src/components/chat/replyContainer.ts
  3. 4
      src/components/sidebarRight/tabs/sharedMedia.ts
  4. 1
      src/countries.ts
  5. 12
      src/lib/appManagers/appPhotosManager.ts
  6. 9
      src/lib/mtproto/apiManager.ts
  7. 1
      src/lib/mtproto/dcConfigurator.ts
  8. 412
      src/lib/mtproto/networker.ts
  9. 18
      src/lib/mtproto/timeManager.ts
  10. 97
      src/lib/mtproto/tl_utils.ts
  11. 41
      src/lib/mtproto/transports/websocket.ts
  12. 6
      src/scss/partials/_chatBubble.scss
  13. 2
      src/scss/partials/_leftSidebar.scss

20
src/components/audio.ts

@ -34,13 +34,17 @@ export function decodeWaveform(waveform: Uint8Array | number[]) { @@ -34,13 +34,17 @@ export function decodeWaveform(waveform: Uint8Array | number[]) {
return new Uint8Array([]);
}
var dataView = new DataView(waveform.buffer);
var result = new Uint8Array(valueCount);
for(var i = 0; i < valueCount; i++) {
var byteIndex = i * 5 / 8 | 0;
var bitShift = i * 5 % 8;
var value = dataView.getUint16(byteIndex, true);
result[i] = (value >> bitShift) & 0b00011111;
try {
var dataView = new DataView(waveform.buffer);
var result = new Uint8Array(valueCount);
for(var i = 0; i < valueCount; i++) {
var byteIndex = i * 5 / 8 | 0;
var bitShift = i * 5 % 8;
var value = dataView.getUint16(byteIndex, true);
result[i] = (value >> bitShift) & 0b00011111;
}
} catch(err) {
return new Uint8Array([]);
}
/* var byteIndex = (valueCount - 1) / 8 | 0;
@ -82,7 +86,7 @@ function wrapVoiceMessage(doc: MyDocument, audioEl: AudioElement, mid: number) { @@ -82,7 +86,7 @@ function wrapVoiceMessage(doc: MyDocument, audioEl: AudioElement, mid: number) {
audioEl.append(svg, timeDiv);
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);

28
src/components/chat/replyContainer.ts

@ -31,11 +31,13 @@ export default class ReplyContainer extends DivAndCaption<(title: string, subtit @@ -31,11 +31,13 @@ export default class ReplyContainer extends DivAndCaption<(title: string, subtit
//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');
replyMedia.classList.add(this.className + '-media');
if(media.document?.type == 'sticker') {
good = true;
wrapSticker({
doc: media.document,
div: replyMedia,
@ -48,22 +50,30 @@ export default class ReplyContainer extends DivAndCaption<(title: string, subtit @@ -48,22 +50,30 @@ export default class ReplyContainer extends DivAndCaption<(title: string, subtit
} else {
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;
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 */);
appPhotosManager.preloadPhoto(photo, size)
.then(() => {
renderImageFromUrl(replyMedia, photo._ == 'photo' ? photo.url : appPhotosManager.getDocumentCachedThumb(photo.id).url);
});
if(size._ != 'photoSizeEmpty') {
good = true;
appPhotosManager.preloadPhoto(photo, size)
.then(() => {
renderImageFromUrl(replyMedia, photo._ == 'photo' ? photo.url : appPhotosManager.getDocumentCachedThumb(photo.id).url);
});
}
}
this.content.prepend(this.mediaEl = replyMedia);
this.container.classList.add('is-media');
if(good) {
this.content.prepend(this.mediaEl = replyMedia);
this.container.classList.add('is-media');
}
}
} else {
subtitle = subtitle ? RichTextProcessor.wrapEmojiText(subtitle) : '';

4
src/components/sidebarRight/tabs/sharedMedia.ts

@ -202,6 +202,8 @@ export default class AppSharedMediaTab implements SliderTab { @@ -202,6 +202,8 @@ export default class AppSharedMediaTab implements SliderTab {
}
public renderNewMessages(mids: number[]) {
if(this.init) return; // * not inited yet
mids = mids.slice().reverse(); // ! because it will be ascend sorted array
for(const sharedMediaType of this.sharedMediaTypes) {
const filtered = this.filterMessagesByType(mids, sharedMediaType);
@ -218,6 +220,8 @@ export default class AppSharedMediaTab implements SliderTab { @@ -218,6 +220,8 @@ export default class AppSharedMediaTab implements SliderTab {
}
public deleteDeletedMessages(mids: number[]) {
if(this.init) return; // * not inited yet
for(const mid of mids) {
for(const sharedMediaType of this.sharedMediaTypes) {
if(!this.historiesStorage[this.peerID] || !this.historiesStorage[this.peerID][sharedMediaType]) continue;

1
src/countries.ts

File diff suppressed because one or more lines are too long

12
src/lib/appManagers/appPhotosManager.ts

@ -15,15 +15,17 @@ export type MyPhoto = Photo.photo; @@ -15,15 +15,17 @@ export type MyPhoto = Photo.photo;
// TIMES = 2 DUE TO SIDEBAR AND CHAT
//let TEST_FILE_REFERENCE = "5440692274120994569", TEST_FILE_REFERENCE_TIMES = 2;
type DocumentCacheThumb = {
downloaded: number,
url: string
};
export class AppPhotosManager {
private photos: {
[id: string]: MyPhoto
} = {};
private documentThumbsCache: {
[docID: string]: {
downloaded: number,
url: string
}
[docID: string]: DocumentCacheThumb
} = {};
public windowW = 0;
public windowH = 0;
@ -294,7 +296,7 @@ export class AppPhotosManager { @@ -294,7 +296,7 @@ export class AppPhotosManager {
return download;
}
public getCacheContext(photo: any) {
public getCacheContext(photo: any): DocumentCacheThumb {
return photo._ == 'document' ? this.getDocumentCachedThumb(photo.id) : photo;
}

9
src/lib/mtproto/apiManager.ts

@ -48,6 +48,8 @@ export class ApiManager { @@ -48,6 +48,8 @@ export class ApiManager {
private log: ReturnType<typeof logger> = logger('API');
private afterMessageTempIDs: {[tempID: string]: string} = {};
//private lol = false;
constructor() {
//MtpSingleInstanceService.start();
@ -193,6 +195,11 @@ export class ApiManager { @@ -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"]> {
///////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 afterMessageIDTemp = options.afterMessageID;
@ -211,7 +218,7 @@ export class ApiManager { @@ -211,7 +218,7 @@ export class ApiManager {
const interval = MOUNT_CLASS_TO.setInterval(() => {
this.log.error('Request is still processing:', method, params, options, 'time:', (Date.now() - startTime) / 1000);
//this.cachedUploadNetworkers[2].requestMessageStatus();
}, 30e3);
}, 5e3);
}
const rejectPromise = (error: ApiError) => {

1
src/lib/mtproto/dcConfigurator.ts

@ -47,6 +47,7 @@ export class DcConfigurator { @@ -47,6 +47,7 @@ export class DcConfigurator {
const subdomain = this.sslSubdomains[dcID - 1];
const path = Modes.test ? 'apiws_test' : 'apiws';
const chosenServer = 'wss://' + subdomain + '.web.telegram.org/' + path;
const suffix = connectionType == 'upload' ? '-U' : connectionType == 'download' ? '-D' : '';
return new Socket(dcID, chosenServer, connectionType != 'client' ? '-U' : '');
};

412
src/lib/mtproto/networker.ts

@ -30,10 +30,10 @@ import Socket from './transports/websocket'; @@ -30,10 +30,10 @@ import Socket from './transports/websocket';
//console.error('networker included!', new Error().stack);
export type MTMessageOptions = InvokeApiOptions & Partial<{
noResponse: true,
noResponse: true, // http_wait
longPoll: true,
notContentRelated: true,
notContentRelated: true, // ACK
noSchedule: true,
messageID: string,
}>;
@ -114,13 +114,15 @@ export default class MTPNetworker { @@ -114,13 +114,15 @@ export default class MTPNetworker {
//console.trace('Create', dcID, options);
const suffix = this.options.fileUpload ? '-U' : this.options.fileDownload ? '-D' : '';
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 + (this.upload ? '-U' : ''), LogLevels.log | 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 + suffix, LogLevels.log | LogLevels.error);
this.log('constructor'/* , this.authKey, this.authKeyID, this.serverSalt */);
/* // Test resend after bad_server_salt
if(this.dcID == 1 && this.upload) {
// Test resend after bad_server_salt
/* if(this.dcID == 1 && this.upload) {
timeManager.applyServerTime((Date.now() / 1000 - 86400) | 0);
this.serverSalt[0] = 0;
} */
@ -134,14 +136,14 @@ export default class MTPNetworker { @@ -134,14 +136,14 @@ export default class MTPNetworker {
/// #if MTPROTO_HTTP_UPLOAD
if(this.transport instanceof HTTP) {
/* this.longPollInt = */setInterval(this.checkLongPoll.bind(this), 10000);
/* this.longPollInt = */setInterval(this.checkLongPoll, 10000);
this.checkLongPoll();
} else {
(this.transport as Socket).networker = this;
}
/// #elif MTPROTO_HTTP
//if(this.transport instanceof HTTP) {
/* this.longPollInt = */setInterval(this.checkLongPoll.bind(this), 10000);
/* this.longPollInt = */setInterval(this.checkLongPoll, 10000);
this.checkLongPoll();
/// #else
//} else {
@ -161,6 +163,7 @@ export default class MTPNetworker { @@ -161,6 +163,7 @@ export default class MTPNetworker {
if(!sentMessage) {
return false;
}
if(sentMessage.container) {
const newInner: string[] = [];
sentMessage.inner.forEach((innerSentMessageID) => {
@ -168,15 +171,16 @@ export default class MTPNetworker { @@ -168,15 +171,16 @@ export default class MTPNetworker {
if(innerSentMessage) {
newInner.push(innerSentMessage.msg_id);
}
})
});
sentMessage.inner = newInner;
}
sentMessage.msg_id = timeManager.generateID();
sentMessage.seq_no = this.generateSeqNo(
sentMessage.notContentRelated ||
sentMessage.container
);
sentMessage.seq_no = this.generateSeqNo(sentMessage.notContentRelated || sentMessage.container);
this.log('updateSentMessage', sentMessage.msg_id, sentMessageID);
this.sentMessages[sentMessage.msg_id] = sentMessage;
delete this.sentMessages[sentMessageID];
@ -234,19 +238,19 @@ export default class MTPNetworker { @@ -234,19 +238,19 @@ export default class MTPNetworker {
}
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
///////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!');
serializer.storeInt(+invokeWithLayer.id >>> 0, 'invokeWithLayer');
// @ts-ignore
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!');
serializer.storeInt(+initConnection.id >>> 0, 'initConnection');
@ -272,7 +276,7 @@ export default class MTPNetworker { @@ -272,7 +276,7 @@ export default class MTPNetworker {
}
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!');
this.log('Api call options.afterMessageID!');
@ -286,9 +290,9 @@ export default class MTPNetworker { @@ -286,9 +290,9 @@ export default class MTPNetworker {
this.log('api call body:', serializer.getBytes(true));
} */
var messageID = timeManager.generateID();
var seqNo = this.generateSeqNo();
var message = {
const messageID = timeManager.generateID();
const seqNo = this.generateSeqNo();
const message = {
msg_id: messageID,
seq_no: seqNo,
body: serializer.getBytes(true),
@ -305,7 +309,7 @@ export default class MTPNetworker { @@ -305,7 +309,7 @@ export default class MTPNetworker {
}
/// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD
public checkLongPoll() {
public checkLongPoll = () => {
const isClean = this.cleanupSent();
//this.log.error('Check lp', this.longPollPending, this.dcID, isClean, this);
if((this.longPollPending && Date.now() < this.longPollPending) ||
@ -326,10 +330,10 @@ export default class MTPNetworker { @@ -326,10 +330,10 @@ export default class MTPNetworker {
this.sendLongPoll();
});
}
};
public sendLongPoll() {
let maxWait = 25000;
const maxWait = 25000;
this.longPollPending = Date.now() + maxWait;
//this.log('Set lp', this.longPollPending, tsNow())
@ -343,7 +347,7 @@ export default class MTPNetworker { @@ -343,7 +347,7 @@ export default class MTPNetworker {
longPoll: true
}).then(() => {
this.longPollPending = 0;
setTimeout(this.checkLongPoll.bind(this), 0);
setTimeout(this.checkLongPoll, 0);
}, (error: ErrorEvent) => {
this.log('Long-poll failed', error);
});
@ -356,29 +360,26 @@ export default class MTPNetworker { @@ -356,29 +360,26 @@ export default class MTPNetworker {
clearTimeout(this.checkConnectionTimeout);
this.checkConnectionTimeout = 0;
var serializer = new TLSerialization({mtproto: true});
var pingID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)];
const serializer = new TLSerialization({mtproto: true});
const pingID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)];
serializer.storeMethod('ping', {
ping_id: pingID
});
var pingMessage = {
const pingMessage = {
msg_id: timeManager.generateID(),
seq_no: this.generateSeqNo(true),
body: serializer.getBytes()
};
var self = this;
this.sendEncryptedRequest(pingMessage, {
timeout: 15000
}).then((result) => {
this.sendEncryptedRequest(pingMessage).then((result) => {
/* delete $rootScope.offlineConnecting */
self.toggleOffline(false);
this.toggleOffline(false);
}, () => {
this.log('Delay ', self.checkConnectionPeriod * 1000);
self.checkConnectionTimeout = setTimeout(self.checkConnection.bind(self), self.checkConnectionPeriod * 1000 | 0);
self.checkConnectionPeriod = Math.min(60, self.checkConnectionPeriod * 1.5);
this.log('Delay ', this.checkConnectionPeriod * 1000);
this.checkConnectionTimeout = setTimeout(this.checkConnection, this.checkConnectionPeriod * 1000 | 0);
this.checkConnectionPeriod = Math.min(60, this.checkConnectionPeriod * 1.5);
/* setTimeout(function() {
delete $rootScope.offlineConnecting
}, 1000); */
@ -404,7 +405,7 @@ export default class MTPNetworker { @@ -404,7 +405,7 @@ export default class MTPNetworker {
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);
document.body.addEventListener('online', this.checkConnection, false);
@ -430,14 +431,14 @@ export default class MTPNetworker { @@ -430,14 +431,14 @@ export default class MTPNetworker {
// this.log('parse for', message)
this.parseResponse(result).then((response) => {
if(Modes.debug) {
this.log('Server response', this.dcID, response);
this.log('Server response', response);
}
this.processMessage(response.response, response.messageID, response.sessionID);
noResponseMsgs.forEach((msgID) => {
if(this.sentMessages[msgID]) {
var deferred = this.sentMessages[msgID].deferred;
const deferred = this.sentMessages[msgID].deferred;
delete this.sentMessages[msgID];
deferred.resolve();
}
@ -462,7 +463,7 @@ export default class MTPNetworker { @@ -462,7 +463,7 @@ export default class MTPNetworker {
noResponseMsgs.forEach((msgID) => {
if(this.sentMessages[msgID]) {
var deferred = this.sentMessages[msgID].deferred;
const deferred = this.sentMessages[msgID].deferred;
delete this.sentMessages[msgID];
delete this.pendingMessages[msgID];
deferred.reject();
@ -504,14 +505,14 @@ export default class MTPNetworker { @@ -504,14 +505,14 @@ export default class MTPNetworker {
const value = delay ? Date.now() + delay : 0;
const sentMessage = this.sentMessages[messageID];
if(sentMessage.container) {
for(let i = 0, length = sentMessage.inner.length; i < length; i++) {
this.pendingMessages[sentMessage.inner[i]] = value;
for(const innerMsgID of sentMessage.inner) {
this.pendingMessages[innerMsgID] = value;
}
} else {
this.pendingMessages[messageID] = value;
}
this.log('Resend due', messageID, this.pendingMessages);
this.log('Resend', messageID, sentMessage, this.pendingMessages);
this.scheduleRequest(delay);
}
@ -527,11 +528,11 @@ export default class MTPNetworker { @@ -527,11 +528,11 @@ export default class MTPNetworker {
};
public getAesKeyIv(msgKey: Uint8Array | number[], isOut: boolean): Promise<[Uint8Array, Uint8Array]> {
var authKey = this.authKeyUint8;
var x = isOut ? 0 : 8;
var sha2aText = new Uint8Array(52);
var sha2bText = new Uint8Array(52);
var promises: Array<Promise<number[]>> = [];
const authKey = this.authKeyUint8;
const x = isOut ? 0 : 8;
const sha2aText = new Uint8Array(52);
const sha2bText = new Uint8Array(52);
const promises: Array<Promise<number[]>> = [];
sha2aText.set(msgKey, 0);
sha2aText.set(authKey.subarray(x, x + 36), 16);
@ -542,10 +543,10 @@ export default class MTPNetworker { @@ -542,10 +543,10 @@ export default class MTPNetworker {
promises.push(CryptoWorker.sha256Hash(sha2bText));
return Promise.all(promises).then((results) => {
var aesKey = new Uint8Array(32);
var aesIv = new Uint8Array(32);
var sha2a = new Uint8Array(results[0]);
var sha2b = new Uint8Array(results[1]);
const aesKey = new Uint8Array(32);
const aesIv = new Uint8Array(32);
const sha2a = new Uint8Array(results[0]);
const sha2b = new Uint8Array(results[1]);
aesKey.set(sha2a.subarray(0, 8));
aesKey.set(sha2b.subarray(8, 24), 8);
@ -559,7 +560,7 @@ export default class MTPNetworker { @@ -559,7 +560,7 @@ export default class MTPNetworker {
});
}
public performScheduledRequest() {
public performScheduledRequest = () => {
// this.log('scheduled', this.dcID, this.iii)
/// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD
@ -604,24 +605,23 @@ export default class MTPNetworker { @@ -604,24 +605,23 @@ export default class MTPNetworker {
};
}
var message: MTPNetworker['sentMessages'][keyof MTPNetworker['sentMessages']];
var messages: typeof message[] = [];
let message: MTPNetworker['sentMessages'][keyof MTPNetworker['sentMessages']];
const messages: typeof message[] = [];
var messagesByteLen = 0;
var currentTime = Date.now();
var hasApiCall = false;
var hasHttpWait = false;
var lengthOverflow = false;
var singlesCount = 0;
var self = this;
for(let messageID in this.pendingMessages) {
let value = this.pendingMessages[messageID];
const currentTime = Date.now();
let messagesByteLen = 0;
let hasApiCall = false;
let hasHttpWait = false;
let lengthOverflow = false;
let singlesCount = 0;
for(const messageID in this.pendingMessages) {
const value = this.pendingMessages[messageID];
if(!value || value >= currentTime) {
if(message = this.sentMessages[messageID]) {
//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 &&
lengthOverflow) {
continue; // maybe break here
@ -653,7 +653,7 @@ export default class MTPNetworker { @@ -653,7 +653,7 @@ export default class MTPNetworker {
// this.log(message, messageID)
}
delete self.pendingMessages[messageID];
delete this.pendingMessages[messageID];
}
}
@ -662,7 +662,7 @@ export default class MTPNetworker { @@ -662,7 +662,7 @@ export default class MTPNetworker {
/// #endif
/// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD
if(hasApiCall && !hasHttpWait) {
var serializer = new TLSerialization({mtproto: true});
const serializer = new TLSerialization({mtproto: true});
serializer.storeMethod('http_wait', {
max_delay: 500,
wait_after: 150,
@ -682,10 +682,10 @@ export default class MTPNetworker { @@ -682,10 +682,10 @@ export default class MTPNetworker {
return;
}
var noResponseMsgs: Array<string> = [];
const noResponseMsgs: Array<string> = [];
if(messages.length > 1) {
var container = new TLSerialization({
const container = new TLSerialization({
mtproto: true,
startMaxLength: messagesByteLen + 64
});
@ -693,7 +693,7 @@ export default class MTPNetworker { @@ -693,7 +693,7 @@ export default class MTPNetworker {
container.storeInt(0x73f1f8dc, 'CONTAINER[id]');
container.storeInt(messages.length, 'CONTAINER[count]');
var innerMessages: string[] = [];
const innerMessages: string[] = [];
messages.forEach((message, i) => {
container.storeLong(message.msg_id, 'CONTAINER[' + i + '][msg_id]');
innerMessages.push(message.msg_id);
@ -705,7 +705,7 @@ export default class MTPNetworker { @@ -705,7 +705,7 @@ export default class MTPNetworker {
}
});
var containerSentMessage: MTMessage = {
const containerSentMessage: MTMessage = {
msg_id: timeManager.generateID(),
seq_no: this.generateSeqNo(true),
container: true,
@ -731,17 +731,19 @@ export default class MTPNetworker { @@ -731,17 +731,19 @@ export default class MTPNetworker {
this.pendingAcks = [];
let promise = this.sendEncryptedRequest(message);
const promise = this.sendEncryptedRequest(message);
/// #if MTPROTO_HTTP_UPLOAD
if(!(this.transport instanceof HTTP)) {
if(noResponseMsgs.length) this.log.error('noResponseMsgs length!', noResponseMsgs);
this.cleanupSent(); // ! WARNING
} else {
this.handleSentEncryptedRequestHTTP(promise, message, noResponseMsgs);
}
/// #elif !MTPROTO_HTTP
//if(!(this.transport instanceof HTTP)) {
if(noResponseMsgs.length) this.log.error('noResponseMsgs length!', noResponseMsgs);
this.cleanupSent(); // ! WARNING
//} else {
/// #else
this.handleSentEncryptedRequestHTTP(promise, message, noResponseMsgs);
@ -751,14 +753,14 @@ export default class MTPNetworker { @@ -751,14 +753,14 @@ export default class MTPNetworker {
if(lengthOverflow || singlesCount > 1) {
this.scheduleRequest();
}
}
};
public async getEncryptedMessage(dataWithPadding: ArrayBuffer) {
let msgKey = await this.getMsgKey(dataWithPadding, true);
let keyIv = await this.getAesKeyIv(msgKey, true);
const msgKey = await this.getMsgKey(dataWithPadding, true);
const keyIv = await this.getAesKeyIv(msgKey, true);
// 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')
return {
@ -775,10 +777,8 @@ export default class MTPNetworker { @@ -775,10 +777,8 @@ export default class MTPNetworker {
});
}
public sendEncryptedRequest(message: MTMessage, options: any = {}) {
const self = this;
this.log.debug('Send encrypted', message, options, this.authKeyID);
public sendEncryptedRequest(message: MTMessage) {
this.log.debug('Send encrypted', message, this.authKeyID);
// console.trace()
const data = new TLSerialization({
startMaxLength: message.body.length + 2048
@ -813,7 +813,7 @@ export default class MTPNetworker { @@ -813,7 +813,7 @@ export default class MTPNetworker {
const request = new TLSerialization({
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.storeRawBytes(encryptedResult.bytes, 'encrypted_data');
@ -826,9 +826,9 @@ export default class MTPNetworker { @@ -826,9 +826,9 @@ export default class MTPNetworker {
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);
}
} */
const promise = this.transport.send(requestData);
/// #if !MTPROTO_HTTP && !MTPROTO_HTTP_UPLOAD
@ -858,19 +858,19 @@ export default class MTPNetworker { @@ -858,19 +858,19 @@ export default class MTPNetworker {
public parseResponse(responseBuffer: Uint8Array) {
this.log.debug('Start parsing response'/* , responseBuffer */);
let self = this;
let deserializer = new TLDeserialization(responseBuffer);
const 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)) {
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');
const msgKey = deserializer.fetchIntBytes(128, true, 'msg_key');
const encryptedData = deserializer.fetchRawBytes(responseBuffer.byteLength - deserializer.getOffset(), true, 'encrypted_data');
return self.getDecryptedMessage(msgKey, encryptedData).then((dataWithPadding) => {
return this.getDecryptedMessage(msgKey, encryptedData).then((dataWithPadding) => {
// this.log('after decrypt')
return self.getMsgKey(dataWithPadding, false).then((calcMsgKey) => {
return this.getMsgKey(dataWithPadding, false).then((calcMsgKey) => {
if(!bytesCmp(msgKey, calcMsgKey)) {
this.log.warn('[MT] msg_keys', msgKey, calcMsgKey);
this.updateSession(); // fix 28.01.2020
@ -880,103 +880,103 @@ export default class MTPNetworker { @@ -880,103 +880,103 @@ export default class MTPNetworker {
let deserializer = new TLDeserialization(dataWithPadding, {mtproto: true});
/* let salt = */deserializer.fetchIntBytes(64, false, 'salt'); // need
let sessionID = deserializer.fetchIntBytes(64, false, 'session_id');
let messageID = deserializer.fetchLong('message_id');
/* const salt = */deserializer.fetchIntBytes(64, false, 'salt'); // need
const sessionID = deserializer.fetchIntBytes(64, false, 'session_id');
const messageID = deserializer.fetchLong('message_id');
if(!bytesCmp(sessionID, self.sessionID) &&
(!self.prevSessionID || !bytesCmp(sessionID, self.prevSessionID))) {
this.log.warn('Sessions', sessionID, self.sessionID, self.prevSessionID, dataWithPadding);
if(!bytesCmp(sessionID, this.sessionID) &&
(!this.prevSessionID || !bytesCmp(sessionID, this.prevSessionID))) {
this.log.warn('Sessions', sessionID, this.sessionID, this.prevSessionID, dataWithPadding);
//this.updateSession();
//this.sessionID = 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();
if((messageBodyLength % 4) ||
messageBodyLength > totalLength - offset) {
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();
let paddingLength = totalLength - offset;
const paddingLength = totalLength - offset;
if(paddingLength < 12 || paddingLength > 1024) {
throw new Error('[MT] Invalid padding length: ' + paddingLength);
}
//let buffer = bytesToArrayBuffer(messageBody);
deserializer = new TLDeserialization(/* buffer */messageBody, {mtproto: true});
// костыль
deserializer.override = {
mt_message: (function(this: TLDeserialization, result: any, field: string) {
result.msg_id = this.fetchLong(field + '[msg_id]');
result.seqno = this.fetchInt(field + '[seqno]');
result.bytes = this.fetchInt(field + '[bytes]');
var offset = this.getOffset();
//self.log('mt_message!!!!!', result, field);
try {
result.body = this.fetchObject('Object', field + '[body]');
} catch(e) {
self.log.error('parse error', e.message, e.stack);
result.body = {
_: 'parse_error',
error: e
};
}
if(this.offset != offset + result.bytes) {
// console.warn(dT(), 'set offset', this.offset, offset, result.bytes)
// this.log(result)
this.offset = offset + result.bytes;
}
// this.log('override message', result)
}).bind(deserializer),
mt_rpc_result: (function(this: TLDeserialization, result: any, field: any) {
result.req_msg_id = this.fetchLong(field + '[req_msg_id]');
var sentMessage = self.sentMessages[result.req_msg_id];
var type = sentMessage && sentMessage.resultType || 'Object';
deserializer = new TLDeserialization(/* buffer */messageBody, {
mtproto: true,
override: {
mt_message: (result: any, field: string) => {
result.msg_id = deserializer.fetchLong(field + '[msg_id]');
result.seqno = deserializer.fetchInt(field + '[seqno]');
result.bytes = deserializer.fetchInt(field + '[bytes]');
const offset = deserializer.getOffset();
//self.log('mt_message!!!!!', result, field);
try {
result.body = deserializer.fetchObject('Object', field + '[body]');
} catch(e) {
this.log.error('parse error', e.message, e.stack);
result.body = {
_: 'parse_error',
error: e
};
}
if(result.req_msg_id && !sentMessage) {
// console.warn(dT(), 'Result for unknown message', result);
return;
if(deserializer.offset != offset + result.bytes) {
// console.warn(dT(), 'set offset', this.offset, offset, result.bytes)
// this.log(result)
deserializer.offset = offset + result.bytes;
}
// this.log('override message', result)
},
mt_rpc_result: (result: any, field: any) => {
result.req_msg_id = deserializer.fetchLong(field + '[req_msg_id]');
const sentMessage = this.sentMessages[result.req_msg_id];
const type = sentMessage && sentMessage.resultType || 'Object';
if(result.req_msg_id && !sentMessage) {
// console.warn(dT(), 'Result for unknown message', result);
return;
}
result.result = deserializer.fetchObject(type, field + '[result]');
// self.log(dT(), 'override rpc_result', sentMessage, type, result);
}
}
});
result.result = this.fetchObject(type, field + '[result]');
// self.log(dT(), 'override rpc_result', sentMessage, type, result);
}).bind(deserializer)
};
var response = deserializer.fetchObject('', 'INPUT');
const response = deserializer.fetchObject('', 'INPUT');
return {
response: response,
messageID: messageID,
sessionID: sessionID,
seqNo: seqNo
response,
messageID,
sessionID,
seqNo
};
});
});
}
public applyServerSalt(newServerSalt: string) {
var serverSalt = longToBytes(newServerSalt);
const serverSalt = longToBytes(newServerSalt);
AppStorage.set({
['dc' + this.dcID + '_server_salt']: bytesToHex(serverSalt)
});
this.serverSalt = serverSalt;
return true;
}
public scheduleRequest(delay = 0) {
@ -1007,9 +1007,9 @@ export default class MTPNetworker { @@ -1007,9 +1007,9 @@ export default class MTPNetworker {
clearTimeout(this.nextReqTimeout);
this.nextReqTimeout = 0;
if(delay > 0) {
this.nextReqTimeout = self.setTimeout(this.performScheduledRequest.bind(this), delay || 0);
this.nextReqTimeout = self.setTimeout(this.performScheduledRequest, delay || 0);
} else {
setTimeout(this.performScheduledRequest.bind(this), 0);
setTimeout(this.performScheduledRequest, 0);
}
this.nextReq = nextReq;
@ -1039,8 +1039,8 @@ export default class MTPNetworker { @@ -1039,8 +1039,8 @@ export default class MTPNetworker {
// this.log('clean notContentRelated', msgID)
delete this.sentMessages[msgID];
} else if(message.container) {
for(let i = 0; i < message.inner.length; i++) {
if(this.sentMessages[message.inner[i]] !== undefined) {
for(const innerMsgID of message.inner) {
if(this.sentMessages[innerMsgID] !== undefined) {
// this.log('clean failed, found', msgID, message.inner[i], this.sentMessages[message.inner[i]].seq_no)
notEmpty = true;
return;
@ -1057,7 +1057,7 @@ export default class MTPNetworker { @@ -1057,7 +1057,7 @@ export default class MTPNetworker {
}
public processMessageAck(messageID: string) {
var sentMessage = this.sentMessages[messageID];
const sentMessage = this.sentMessages[messageID];
if(sentMessage && !sentMessage.acked) {
delete sentMessage.body;
sentMessage.acked = true;
@ -1069,7 +1069,7 @@ export default class MTPNetworker { @@ -1069,7 +1069,7 @@ export default class MTPNetworker {
}
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;
return {
@ -1084,7 +1084,7 @@ export default class MTPNetworker { @@ -1084,7 +1084,7 @@ export default class MTPNetworker {
* только для сокета, возможно это будет неправильно работать, но в тесте сработало правильно
*/
public resend() {
for(let id in this.sentMessages) {
for(const id in this.sentMessages) {
const msg = this.sentMessages[id];
if(msg.body) {
this.pushResend(id);
@ -1092,7 +1092,7 @@ export default class MTPNetworker { @@ -1092,7 +1092,7 @@ export default class MTPNetworker {
}
}
public requestMessageStatus() {
/* public requestMessageStatus() {
const ids: string[] = [];
for(const id in this.sentMessages) {
const message = this.sentMessages[id];
@ -1109,11 +1109,11 @@ export default class MTPNetworker { @@ -1109,11 +1109,11 @@ export default class MTPNetworker {
}).then(res => {
this.log('status', res);
});
}
} */
// * https://core.telegram.org/mtproto/service_messages_about_messages#notice-of-ignored-error-message
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) {
this.log.warn('[MT] Server even message id: ', messageID, message);
return;
@ -1122,27 +1122,27 @@ export default class MTPNetworker { @@ -1122,27 +1122,27 @@ export default class MTPNetworker {
this.log.debug('process message', message, messageID, sessionID);
switch(message._) {
case 'msg_container':
var len = message.messages.length;
for(var i = 0; i < len; i++) {
this.processMessage(message.messages[i], message.messages[i].msg_id, sessionID);
case 'msg_container': {
for(const innerMessage of message.messages) {
this.processMessage(innerMessage, innerMessage.msg_id, sessionID);
}
break;
}
case 'bad_server_salt':
case 'bad_server_salt': {
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');
}
this.applyServerSalt(message.new_server_salt);
this.pushResend(message.bad_msg_id);
if(this.sentMessages[message.bad_msg_id]) {
this.pushResend(message.bad_msg_id);
}
this.ackMessage(messageID);
/* // simulate disconnect
try {
// simulate disconnect
/* try {
this.log('networker state:', this);
// @ts-ignore
this.transport.ws.close(1000);
@ -1151,19 +1151,14 @@ export default class MTPNetworker { @@ -1151,19 +1151,14 @@ export default class MTPNetworker {
} */
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(timeManager.applyServerTime(
bigStringInt(messageID).shiftRight(32).toString(10)
)) {
const changedOffset = timeManager.applyServerTime(bigStringInt(messageID).shiftRight(32).toString(10));
if(message.error_code == 17 || changedOffset) {
this.log('Update session');
this.updateSession();
}
@ -1172,22 +1167,28 @@ export default class MTPNetworker { @@ -1172,22 +1167,28 @@ export default class MTPNetworker {
if(badMessage) this.pushResend(badMessage.msg_id); // fix 23.01.2020
this.ackMessage(messageID);
}
break;
}
case 'message':
case 'message': {
if(this.lastServerMessages.indexOf(messageID) != -1) {
// console.warn('[MT] Server same messageID: ', messageID)
this.ackMessage(messageID);
return;
}
this.lastServerMessages.push(messageID);
if(this.lastServerMessages.length > 100) {
this.lastServerMessages.shift();
}
this.processMessage(message.body, message.msg_id, sessionID);
break;
}
case 'new_session_created':
case 'new_session_created': {
this.ackMessage(messageID);
this.log.debug('new_session_created', message);
@ -1202,12 +1203,15 @@ export default class MTPNetworker { @@ -1202,12 +1203,15 @@ export default class MTPNetworker {
}
});
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;
}
case 'msg_detailed_info':
if(!this.sentMessages[message.msg_id]) {
@ -1221,34 +1225,34 @@ export default class MTPNetworker { @@ -1221,34 +1225,34 @@ export default class MTPNetworker {
this.reqResendMessage(message.answer_msg_id);
break;
case 'msgs_state_info':
case 'msgs_state_info': {
this.ackMessage(message.answer_msg_id);
if(this.lastResendReq &&
this.lastResendReq.req_msg_id == message.req_msg_id &&
this.pendingResends.length
) {
var badMsgID, pos;
for(let i = 0; i < this.lastResendReq.resend_msg_ids.length; i++) {
badMsgID = this.lastResendReq.resend_msg_ids[i];
pos = this.pendingResends.indexOf(badMsgID);
for(const badMsgID of this.lastResendReq.resend_msg_ids) {
const pos = this.pendingResends.indexOf(badMsgID);
if(pos != -1) {
this.pendingResends.splice(pos, 1);
}
}
}
break;
case 'rpc_result':
}
case 'rpc_result': {
this.ackMessage(messageID);
var sentMessageID = message.req_msg_id;
var sentMessage = this.sentMessages[sentMessageID];
const sentMessageID = message.req_msg_id;
const sentMessage = this.sentMessages[sentMessageID];
this.processMessageAck(sentMessageID);
if(sentMessage) {
var deferred = sentMessage.deferred;
const deferred = sentMessage.deferred;
if(message.result._ == 'rpc_error') {
var error = this.processError(message.result);
const error = this.processError(message.result);
this.log('Rpc error', error);
if(deferred) {
deferred.reject(error);
@ -1258,7 +1262,7 @@ export default class MTPNetworker { @@ -1258,7 +1262,7 @@ export default class MTPNetworker {
if(Modes.debug) {
this.log.debug('Rpc response', message.result);
} else {
var dRes = message.result._;
let dRes = message.result._;
if(!dRes) {
if(message.result.length > 5) {
dRes = '[..' + message.result.length + '..]';
@ -1266,6 +1270,7 @@ export default class MTPNetworker { @@ -1266,6 +1270,7 @@ export default class MTPNetworker {
dRes = message.result;
}
}
this.log.debug('Rpc response', dRes, sentMessage);
}
@ -1281,6 +1286,7 @@ export default class MTPNetworker { @@ -1281,6 +1286,7 @@ export default class MTPNetworker {
delete this.sentMessages[sentMessageID];
}
break;
}
default:
this.ackMessage(messageID);

18
src/lib/mtproto/timeManager.ts

@ -14,12 +14,12 @@ export class TimeManager { @@ -14,12 +14,12 @@ export class TimeManager {
}
public generateID(): string {
var timeTicks = Date.now(),
const timeTicks = Date.now(),
timeSec = Math.floor(timeTicks / 1000) + this.timeOffset,
timeMSec = timeTicks % 1000,
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] ||
this.lastMessageID[0] == messageID[0] && this.lastMessageID[1] >= messageID[1]) {
messageID = [this.lastMessageID[0], this.lastMessageID[1] + 4];
@ -27,21 +27,25 @@ export class TimeManager { @@ -27,21 +27,25 @@ export class TimeManager {
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) {
var newTimeOffset = serverTime - Math.floor((localTime || Date.now()) / 1000);
var changed = Math.abs(this.timeOffset - newTimeOffset) > 10;
localTime = (localTime || Date.now()) / 1000 | 0;
const newTimeOffset = serverTime - localTime;
const changed = Math.abs(this.timeOffset - newTimeOffset) > 10;
AppStorage.set({
server_time_offset: newTimeOffset
});
this.lastMessageID = [0, 0];
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;
}

97
src/lib/mtproto/tl_utils.ts

@ -396,7 +396,7 @@ class TLSerialization { @@ -396,7 +396,7 @@ class TLSerialization {
class TLDeserialization {
public offset = 0; // in bytes
public override: any;
public override: {[key: string]: (result: any, field: string) => void};
public buffer: ArrayBuffer;
//public intView: Uint32Array;
@ -616,13 +616,13 @@ class TLDeserialization { @@ -616,13 +616,13 @@ class TLDeserialization {
if(type.substr(0, 6) == 'Vector' || type.substr(0, 6) == 'vector') {
if(type.charAt(0) == 'V') {
var constructor = this.readInt(field + '[id]');
var constructorCmp = constructor;
const constructor = this.readInt(field + '[id]');
const constructorCmp = constructor;
if(constructorCmp == gzipPacked) { // Gzip packed
var compressed = this.fetchBytes(field + '[packed_string]');
var uncompressed = gzipUncompress(compressed);
var newDeserializer = new TLDeserialization(uncompressed);
const compressed = this.fetchBytes(field + '[packed_string]');
const uncompressed = gzipUncompress(compressed);
const newDeserializer = new TLDeserialization(uncompressed);
return newDeserializer.fetchObject(type, field);
}
@ -632,11 +632,11 @@ class TLDeserialization { @@ -632,11 +632,11 @@ class TLDeserialization {
}
}
var len = this.readInt(field + '[count]');
var result: any = [];
const len = this.readInt(field + '[count]');
const result: any = [];
if(len > 0) {
var itemType = type.substr(7, type.length - 8); // for "Vector<itemType>"
for(var i = 0; i < len; i++) {
const itemType = type.substr(7, type.length - 8); // for "Vector<itemType>"
for(let i = 0; i < len; i++) {
result.push(this.fetchObject(itemType, field + '[' + i + ']'));
}
}
@ -644,62 +644,49 @@ class TLDeserialization { @@ -644,62 +644,49 @@ class TLDeserialization {
return result;
}
var schema = this.mtproto ? Schema.MTProto : Schema.API;
var predicate = false;
var constructorData: any = false;
const schema = this.mtproto ? Schema.MTProto : Schema.API;
let constructorData: MTProtoConstructor = null;
let fallback = false;
if(type.charAt(0) == '%') {
var checkType = type.substr(1);
for(var i = 0; i < schema.constructors.length; i++) {
if(schema.constructors[i].type == checkType) {
constructorData = schema.constructors[i];
break;
}
}
const checkType = type.substr(1);
constructorData = schema.constructors.find(c => c.type == checkType);
if(!constructorData) {
throw new Error('Constructor not found for type: ' + type);
}
} else if(type.charAt(0) >= 97 && type.charAt(0) <= 122) {
for(var i = 0; i < schema.constructors.length; i++) {
if(schema.constructors[i].predicate == type) {
constructorData = schema.constructors[i];
break;
}
}
constructorData = schema.constructors.find(c => c.predicate == type);
if(!constructorData) {
throw new Error('Constructor not found for predicate: ' + type);
}
} else {
var constructor = this.readInt(field + '[id]');
var constructorCmp = constructor;
const constructor = this.readInt(field + '[id]');
const constructorCmp = constructor;
if(constructorCmp == gzipPacked) { // Gzip packed
var compressed = this.fetchBytes(field + '[packed_string]');
var uncompressed = gzipUncompress(compressed);
var newDeserializer = new TLDeserialization(uncompressed);
const compressed = this.fetchBytes(field + '[packed_string]');
const uncompressed = gzipUncompress(compressed);
const newDeserializer = new TLDeserialization(uncompressed);
return newDeserializer.fetchObject(type, field);
}
var index = schema.constructorsIndex;
let index = schema.constructorsIndex;
if(!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;
}
}
var i = index[constructorCmp];
const i = index[constructorCmp];
if(i) {
constructorData = schema.constructors[i];
}
var fallback = false;
if(!constructorData && this.mtproto) {
var schemaFallback = Schema.API;
for(i = 0; i < schemaFallback.constructors.length; i++) {
const schemaFallback = Schema.API;
for(let i = 0, len = schemaFallback.constructors.length; i < len; i++) {
if(+schemaFallback.constructors[i].id == constructorCmp) {
constructorData = schemaFallback.constructors[i];
@ -715,33 +702,27 @@ class TLDeserialization { @@ -715,33 +702,27 @@ class TLDeserialization {
}
}
predicate = constructorData.predicate;
var result: any = {'_': predicate};
var overrideKey = (this.mtproto ? 'mt_' : '') + predicate;
var self = this;
const predicate = constructorData.predicate;
const result: any = {'_': predicate};
const overrideKey = (this.mtproto ? 'mt_' : '') + predicate;
if(this.override[overrideKey]) {
this.override[overrideKey].apply(this, [result, field + '[' + predicate + ']']);
this.override[overrideKey](result, field + '[' + predicate + ']');
} else {
var i: number, param;
var type, isCond;
var condType, fieldBit;
var value;
var len: number = constructorData.params.length;
for(i = 0; i < len; i++) {
param = constructorData.params[i];
type = param.type;
for(let i = 0, len = constructorData.params.length; i < len; i++) {
const param = constructorData.params[i];
let type = param.type;
if(type == '#' && result.pFlags === undefined) {
result.pFlags = {};
}
if(isCond = (type.indexOf('?') !== -1)) {
condType = type.split('?');
fieldBit = condType[0].split('.');
const isCond = (type.indexOf('?') !== -1);
if(isCond) {
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);
continue;
}
@ -751,7 +732,7 @@ class TLDeserialization { @@ -751,7 +732,7 @@ class TLDeserialization {
type = condType[1];
}
value = self.fetchObject(type, field + '[' + predicate + '][' + param.name + ']');
const value = this.fetchObject(type, field + '[' + predicate + '][' + param.name + ']');
if(isCond && type === 'true') {
result.pFlags[param.name] = value;

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

@ -67,6 +67,11 @@ export default class Socket extends MTTransport { @@ -67,6 +67,11 @@ export default class Socket extends MTTransport {
this.connected = true;
this.releasePending();
if(this.networker && this.lastCloseTime) {
this.networker.cleanupSent();
this.networker.resend();
}
//}, 3e3);
};
@ -75,37 +80,29 @@ export default class Socket extends MTTransport { @@ -75,37 +80,29 @@ export default class Socket extends MTTransport {
};
handleClose = (event: CloseEvent) => {
this.log('closed', event, this.pending);
this.log('closed', event, this.pending, this.ws.bufferedAmount);
this.connected = false;
const time = Date.now();
const diff = time - this.lastCloseTime;
let needTimeout = !isNaN(diff) && diff < CONNECTION_RETRY_TIMEOUT ? CONNECTION_RETRY_TIMEOUT - diff : 0;
//this.pending.length = 0;
/* if(this.networker) {
this.networker.resend();
this.networker.cleanupSent();
} */
const needTimeout = !isNaN(diff) && diff < CONNECTION_RETRY_TIMEOUT ? CONNECTION_RETRY_TIMEOUT - diff : 0;
this.log('will try to reconnect after timeout:', needTimeout / 1000);
setTimeout(() => {
this.log('trying to reconnect...');
this.lastCloseTime = Date.now();
this.connect();
for(let pending of this.pending) {
for(const pending of this.pending) {
if(pending.bodySent) {
pending.bodySent = false;
}
}
if(this.networker) {
this.ws.addEventListener('open', () => {
this.networker.resend();
this.networker.cleanupSent();
}, {once: true});
this.pending
}
this.connect();
}, needTimeout);
};
@ -126,7 +123,7 @@ export default class Socket extends MTTransport { @@ -126,7 +123,7 @@ export default class Socket extends MTTransport {
}
//console.log('got hex:', data.hex);
let pending = this.pending.shift();
const pending = this.pending.shift();
if(!pending) {
return this.log.debug('no pending for res:', data.hex);
}
@ -177,9 +174,13 @@ export default class Socket extends MTTransport { @@ -177,9 +174,13 @@ export default class Socket extends MTTransport {
this.log.error('bufferedAmount:', this.ws.bufferedAmount);
} */
//setTimeout(() => {
this.ws.send(enc);
//}, 500);
if(this.ws.readyState !== this.ws.OPEN) {
this.log.error('ws is closed?');
this.connected = false;
break;
}
this.ws.send(enc);
if(!pending.resolve) { // remove if no response needed
this.pending.splice(i--, 1);

6
src/scss/partials/_chatBubble.scss

@ -159,11 +159,11 @@ $bubble-margin: .25rem; @@ -159,11 +159,11 @@ $bubble-margin: .25rem;
&-select-checkbox {
z-index: 2;
position: absolute;
/* left: 0;
bottom: .75rem; // * by avatar */
left: 0;
bottom: .75rem; // * by avatar
/* left: 0;
top: 50%;
transform: translateY(-50%);
transform: translateY(-50%); */
display: flex;
[type="checkbox"] {

2
src/scss/partials/_leftSidebar.scss

@ -45,6 +45,8 @@ @@ -45,6 +45,8 @@
z-index: 1;
background-color: #fff;
border-bottom: 1px solid #dadce0;
position: relative;
box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, .16);
.scrollable {
position: relative;

Loading…
Cancel
Save