|
|
|
@ -2,8 +2,7 @@ import Modes from "../../../config/modes";
@@ -2,8 +2,7 @@ import Modes from "../../../config/modes";
|
|
|
|
|
import { logger, LogLevels } from "../../logger"; |
|
|
|
|
import MTPNetworker from "../networker"; |
|
|
|
|
import Obfuscation from "./obfuscation"; |
|
|
|
|
import MTTransport from "./transport"; |
|
|
|
|
import Socket from "./websocket"; |
|
|
|
|
import MTTransport, { MTConnection, MTConnectionConstructable } from "./transport"; |
|
|
|
|
import intermediatePacketCodec from './intermediate'; |
|
|
|
|
|
|
|
|
|
export default class TcpObfuscated implements MTTransport { |
|
|
|
@ -27,11 +26,11 @@ export default class TcpObfuscated implements MTTransport {
@@ -27,11 +26,11 @@ export default class TcpObfuscated implements MTTransport {
|
|
|
|
|
|
|
|
|
|
private lastCloseTime: number; |
|
|
|
|
|
|
|
|
|
private socket: Socket; |
|
|
|
|
private connection: MTConnection; |
|
|
|
|
|
|
|
|
|
//private debugPayloads: MTPNetworker['debugRequests'] = [];
|
|
|
|
|
|
|
|
|
|
constructor(private dcId: number, private url: string, private logSuffix: string, public retryTimeout: number) { |
|
|
|
|
constructor(private Connection: MTConnectionConstructable, private dcId: number, private url: string, private logSuffix: string, public retryTimeout: number) { |
|
|
|
|
let logLevel = LogLevels.error | LogLevels.log; |
|
|
|
|
if(this.debug) logLevel |= LogLevels.debug; |
|
|
|
|
this.log = logger(`WS-${dcId}` + logSuffix, logLevel); |
|
|
|
@ -40,92 +39,100 @@ export default class TcpObfuscated implements MTTransport {
@@ -40,92 +39,100 @@ export default class TcpObfuscated implements MTTransport {
|
|
|
|
|
this.connect(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private connect() { |
|
|
|
|
this.socket = new Socket(this.dcId, this.url, this.logSuffix); |
|
|
|
|
|
|
|
|
|
this.socket.addListener('open', () => { |
|
|
|
|
this.connected = true; |
|
|
|
|
private onOpen = () => { |
|
|
|
|
this.connected = true; |
|
|
|
|
|
|
|
|
|
const initPayload = this.obfuscation.init(this.codec); |
|
|
|
|
const initPayload = this.obfuscation.init(this.codec); |
|
|
|
|
|
|
|
|
|
if(this.networker) { |
|
|
|
|
this.networker.setConnectionStatus(true); |
|
|
|
|
if(this.networker) { |
|
|
|
|
this.networker.setConnectionStatus(true); |
|
|
|
|
|
|
|
|
|
if(this.lastCloseTime) { |
|
|
|
|
this.networker.cleanupSent(); |
|
|
|
|
this.networker.resend(); |
|
|
|
|
} |
|
|
|
|
if(this.lastCloseTime) { |
|
|
|
|
this.networker.cleanupSent(); |
|
|
|
|
this.networker.resend(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
this.releasePending(); |
|
|
|
|
}, 0); |
|
|
|
|
|
|
|
|
|
this.socket.send(initPayload); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
this.socket.addListener('message', (buffer) => { |
|
|
|
|
let data = this.obfuscation.decode(new Uint8Array(buffer)); |
|
|
|
|
data = this.codec.readPacket(data); |
|
|
|
|
setTimeout(() => { |
|
|
|
|
this.releasePending(); |
|
|
|
|
}, 0); |
|
|
|
|
|
|
|
|
|
if(this.networker) { // authenticated!
|
|
|
|
|
//this.pending = this.pending.filter(p => p.body); // clear pending
|
|
|
|
|
this.connection.send(initPayload); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
this.debug && this.log.debug('redirecting to networker', data.length); |
|
|
|
|
this.networker.parseResponse(data).then(response => { |
|
|
|
|
this.debug && this.log.debug('redirecting to networker response:', response); |
|
|
|
|
private onMessage = (buffer: ArrayBuffer) => { |
|
|
|
|
let data = this.obfuscation.decode(new Uint8Array(buffer)); |
|
|
|
|
data = this.codec.readPacket(data); |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
this.networker.processMessage(response.response, response.messageId, response.sessionId); |
|
|
|
|
} catch(err) { |
|
|
|
|
this.log.error('handleMessage networker processMessage error', err); |
|
|
|
|
} |
|
|
|
|
if(this.networker) { // authenticated!
|
|
|
|
|
//this.pending = this.pending.filter(p => p.body); // clear pending
|
|
|
|
|
|
|
|
|
|
//this.releasePending();
|
|
|
|
|
}).catch(err => { |
|
|
|
|
this.log.error('handleMessage networker parseResponse error', err); |
|
|
|
|
}); |
|
|
|
|
this.debug && this.log.debug('redirecting to networker', data.length); |
|
|
|
|
this.networker.parseResponse(data).then(response => { |
|
|
|
|
this.debug && this.log.debug('redirecting to networker response:', response); |
|
|
|
|
|
|
|
|
|
//this.dd();
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
try { |
|
|
|
|
this.networker.processMessage(response.response, response.messageId, response.sessionId); |
|
|
|
|
} catch(err) { |
|
|
|
|
this.log.error('handleMessage networker processMessage error', err); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//console.log('got hex:', data.hex);
|
|
|
|
|
const pending = this.pending.shift(); |
|
|
|
|
if(!pending) { |
|
|
|
|
this.debug && this.log.debug('no pending for res:', data.hex); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
//this.releasePending();
|
|
|
|
|
}).catch(err => { |
|
|
|
|
this.log.error('handleMessage networker parseResponse error', err); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
pending.resolve(data); |
|
|
|
|
}); |
|
|
|
|
//this.dd();
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.socket.addListener('close', () => { |
|
|
|
|
this.connected = false; |
|
|
|
|
this.socket = undefined; |
|
|
|
|
//console.log('got hex:', data.hex);
|
|
|
|
|
const pending = this.pending.shift(); |
|
|
|
|
if(!pending) { |
|
|
|
|
this.debug && this.log.debug('no pending for res:', data.hex); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const time = Date.now(); |
|
|
|
|
const diff = time - this.lastCloseTime; |
|
|
|
|
const needTimeout = !isNaN(diff) && diff < this.retryTimeout ? this.retryTimeout - diff : 0; |
|
|
|
|
pending.resolve(data); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
if(this.networker) { |
|
|
|
|
this.networker.setConnectionStatus(false); |
|
|
|
|
private onClose = () => { |
|
|
|
|
this.connected = false; |
|
|
|
|
|
|
|
|
|
const time = Date.now(); |
|
|
|
|
const diff = time - this.lastCloseTime; |
|
|
|
|
const needTimeout = !isNaN(diff) && diff < this.retryTimeout ? this.retryTimeout - diff : 0; |
|
|
|
|
|
|
|
|
|
if(this.networker) { |
|
|
|
|
this.networker.setConnectionStatus(false); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.log('will try to reconnect after timeout:', needTimeout / 1000); |
|
|
|
|
setTimeout(() => { |
|
|
|
|
this.log('trying to reconnect...'); |
|
|
|
|
this.lastCloseTime = Date.now(); |
|
|
|
|
|
|
|
|
|
for(const pending of this.pending) { |
|
|
|
|
if(pending.bodySent) { |
|
|
|
|
pending.bodySent = false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.connect(); |
|
|
|
|
}, needTimeout); |
|
|
|
|
|
|
|
|
|
this.connection.removeListener('open', this.onOpen); |
|
|
|
|
this.connection.removeListener('close', this.onClose); |
|
|
|
|
this.connection.removeListener('message', this.onMessage); |
|
|
|
|
this.connection = undefined; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
this.log('will try to reconnect after timeout:', needTimeout / 1000); |
|
|
|
|
setTimeout(() => { |
|
|
|
|
this.log('trying to reconnect...'); |
|
|
|
|
this.lastCloseTime = Date.now(); |
|
|
|
|
|
|
|
|
|
for(const pending of this.pending) { |
|
|
|
|
if(pending.bodySent) { |
|
|
|
|
pending.bodySent = false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
private connect() { |
|
|
|
|
this.connection = new this.Connection(this.dcId, this.url, this.logSuffix); |
|
|
|
|
|
|
|
|
|
this.connect(); |
|
|
|
|
}, needTimeout); |
|
|
|
|
}); |
|
|
|
|
this.connection.addListener('open', this.onOpen); |
|
|
|
|
this.connection.addListener('close', this.onClose); |
|
|
|
|
this.connection.addListener('message', this.onMessage); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private encodeBody = (body: Uint8Array) => { |
|
|
|
@ -202,7 +209,7 @@ export default class TcpObfuscated implements MTTransport {
@@ -202,7 +209,7 @@ export default class TcpObfuscated implements MTTransport {
|
|
|
|
|
|
|
|
|
|
//this.lol.push(body);
|
|
|
|
|
//setTimeout(() => {
|
|
|
|
|
this.socket.send(encoded); |
|
|
|
|
this.connection.send(encoded); |
|
|
|
|
//}, 100);
|
|
|
|
|
//this.dd();
|
|
|
|
|
|
|
|
|
|