Socket proxy class for Safari
This commit is contained in:
parent
641c50ae82
commit
debac6f0e5
@ -105,7 +105,8 @@ export class Authorizer {
|
|||||||
this.log('mtpSendPlainRequest: creating requestPromise');
|
this.log('mtpSendPlainRequest: creating requestPromise');
|
||||||
}
|
}
|
||||||
|
|
||||||
return transport.send(resultArray).then(result => {
|
const promise = transport.send(resultArray) as any as Promise<Uint8Array>;
|
||||||
|
return promise.then(result => {
|
||||||
if(DEBUG) {
|
if(DEBUG) {
|
||||||
this.log('mtpSendPlainRequest: in good sector', result);
|
this.log('mtpSendPlainRequest: in good sector', result);
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,16 @@
|
|||||||
import MTTransport from './transports/transport';
|
import MTTransport, { MTConnection, MTConnectionConstructable } from './transports/transport';
|
||||||
import Modes from '../../config/modes';
|
import Modes from '../../config/modes';
|
||||||
|
|
||||||
/// #if MTPROTO_HTTP_UPLOAD
|
/// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD
|
||||||
// @ts-ignore
|
|
||||||
import TcpObfuscated from './transports/tcpObfuscated';
|
|
||||||
// @ts-ignore
|
|
||||||
import HTTP from './transports/http';
|
import HTTP from './transports/http';
|
||||||
/// #elif !MTPROTO_HTTP
|
/// #endif
|
||||||
// @ts-ignore
|
|
||||||
|
/// #if !MTPROTO_HTTP
|
||||||
|
import Socket from './transports/websocket';
|
||||||
import TcpObfuscated from './transports/tcpObfuscated';
|
import TcpObfuscated from './transports/tcpObfuscated';
|
||||||
|
import EventListenerBase from '../../helpers/eventListenerBase';
|
||||||
import { isSafari } from '../../helpers/userAgent';
|
import { isSafari } from '../../helpers/userAgent';
|
||||||
import type MTPNetworker from './networker';
|
|
||||||
import { notifyAll, isWebWorker } from '../../helpers/context';
|
import { notifyAll, isWebWorker } from '../../helpers/context';
|
||||||
import { CancellablePromise, deferredPromise } from '../../helpers/cancellablePromise';
|
|
||||||
/// #else
|
|
||||||
// @ts-ignore
|
|
||||||
import HTTP from './transports/http';
|
|
||||||
/// #endif
|
/// #endif
|
||||||
|
|
||||||
export type TransportType = 'websocket' | 'https' | 'http';
|
export type TransportType = 'websocket' | 'https' | 'http';
|
||||||
@ -31,6 +26,48 @@ type Servers = {
|
|||||||
let socketId = 0;
|
let socketId = 0;
|
||||||
const TEST_SUFFIX = Modes.test ? '_test' : '';
|
const TEST_SUFFIX = Modes.test ? '_test' : '';
|
||||||
|
|
||||||
|
class SocketProxied extends EventListenerBase<{
|
||||||
|
open: () => void,
|
||||||
|
message: (buffer: ArrayBuffer) => any,
|
||||||
|
close: () => void,
|
||||||
|
}> implements MTConnection {
|
||||||
|
private id: number;
|
||||||
|
|
||||||
|
constructor(protected dcId: number, protected url: string, logSuffix: string) {
|
||||||
|
super();
|
||||||
|
this.id = ++socketId;
|
||||||
|
socketsProxied.set(this.id, this);
|
||||||
|
|
||||||
|
notifyAll({
|
||||||
|
type: 'socketProxy',
|
||||||
|
payload: {
|
||||||
|
type: 'setup',
|
||||||
|
payload: {
|
||||||
|
dcId,
|
||||||
|
url,
|
||||||
|
logSuffix
|
||||||
|
},
|
||||||
|
id: this.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
send = (payload: Uint8Array) => {
|
||||||
|
const task: any = {
|
||||||
|
type: 'socketProxy',
|
||||||
|
payload: {
|
||||||
|
type: 'send',
|
||||||
|
payload,
|
||||||
|
id: this.id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
notifyAll(task);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const socketsProxied: Map<number, SocketProxied> = new Map();
|
||||||
|
|
||||||
export class DcConfigurator {
|
export class DcConfigurator {
|
||||||
private sslSubdomains = ['pluto', 'venus', 'aurora', 'vesta', 'flora'];
|
private sslSubdomains = ['pluto', 'venus', 'aurora', 'vesta', 'flora'];
|
||||||
|
|
||||||
@ -58,58 +95,10 @@ export class DcConfigurator {
|
|||||||
const logSuffix = connectionType === 'upload' ? '-U' : connectionType === 'download' ? '-D' : '';
|
const logSuffix = connectionType === 'upload' ? '-U' : connectionType === 'download' ? '-D' : '';
|
||||||
|
|
||||||
const retryTimeout = connectionType === 'client' ? 30000 : 10000;
|
const retryTimeout = connectionType === 'client' ? 30000 : 10000;
|
||||||
if(isSafari && isWebWorker && false) {
|
|
||||||
class P implements MTTransport {
|
|
||||||
private id: number;
|
|
||||||
private taskId = 0;
|
|
||||||
public networker: MTPNetworker;
|
|
||||||
public promises: Map<number, CancellablePromise<Uint8Array>> = new Map();
|
|
||||||
|
|
||||||
constructor(dcId: number, url: string) {
|
const oooohLetMeLive: MTConnectionConstructable = (isSafari && isWebWorker) || true ? SocketProxied : Socket;
|
||||||
this.id = ++socketId;
|
|
||||||
|
|
||||||
notifyAll({
|
return new TcpObfuscated(oooohLetMeLive, dcId, chosenServer, logSuffix, retryTimeout);
|
||||||
type: 'socketProxy',
|
|
||||||
payload: {
|
|
||||||
type: 'setup',
|
|
||||||
payload: {
|
|
||||||
dcId,
|
|
||||||
url,
|
|
||||||
logSuffix,
|
|
||||||
retryTimeout
|
|
||||||
},
|
|
||||||
id: this.id
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
send = (payload: Uint8Array) => {
|
|
||||||
const task: any = {
|
|
||||||
type: 'socketProxy',
|
|
||||||
payload: {
|
|
||||||
type: 'send',
|
|
||||||
payload,
|
|
||||||
id: this.id
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if(this.networker) {
|
|
||||||
notifyAll(task);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
task.payload.taskId = ++this.taskId;
|
|
||||||
const deferred = deferredPromise<Uint8Array>();
|
|
||||||
this.promises.set(task.id, deferred);
|
|
||||||
notifyAll(task);
|
|
||||||
return deferred;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return new P(dcId, chosenServer);
|
|
||||||
} else {
|
|
||||||
return new TcpObfuscated(dcId, chosenServer, logSuffix, retryTimeout);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
/// #endif
|
/// #endif
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import apiFileManager from './apiFileManager';
|
|||||||
//import { logger, LogLevels } from '../logger';
|
//import { logger, LogLevels } from '../logger';
|
||||||
import type { ServiceWorkerTask, ServiceWorkerTaskResponse } from './mtproto.service';
|
import type { ServiceWorkerTask, ServiceWorkerTaskResponse } from './mtproto.service';
|
||||||
import { ctx } from '../../helpers/userAgent';
|
import { ctx } from '../../helpers/userAgent';
|
||||||
|
import { socketsProxied } from './dcConfigurator';
|
||||||
|
|
||||||
//const log = logger('DW', LogLevels.error);
|
//const log = logger('DW', LogLevels.error);
|
||||||
|
|
||||||
@ -109,6 +110,19 @@ const onMessage = async(e: any) => {
|
|||||||
} else if(task.type === 'webpSupport') {
|
} else if(task.type === 'webpSupport') {
|
||||||
webpSupported = task.payload;
|
webpSupported = task.payload;
|
||||||
return;
|
return;
|
||||||
|
} else if(task.type === 'socketProxy') {
|
||||||
|
const socketTask = task.payload;
|
||||||
|
const id = socketTask.id;
|
||||||
|
|
||||||
|
const socketProxied = socketsProxied.get(id);
|
||||||
|
if(socketTask.type === 'message') {
|
||||||
|
socketProxied.setListenerResult('message', socketTask.payload);
|
||||||
|
} else if(socketTask.type === 'open') {
|
||||||
|
socketProxied.setListenerResult('open');
|
||||||
|
} else if(socketTask.type === 'close') {
|
||||||
|
socketProxied.setListenerResult('close');
|
||||||
|
socketsProxied.delete(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!task.task) {
|
if(!task.task) {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import MTProtoWorker from 'worker-loader!./mtproto.worker';
|
import MTProtoWorker from 'worker-loader!./mtproto.worker';
|
||||||
import SocketWorker from 'worker-loader!./transports/websocket';
|
|
||||||
//import './mtproto.worker';
|
//import './mtproto.worker';
|
||||||
import { isObject } from '../../helpers/object';
|
import { isObject } from '../../helpers/object';
|
||||||
import type { MethodDeclMap } from '../../layer';
|
import type { MethodDeclMap } from '../../layer';
|
||||||
@ -16,6 +15,7 @@ import type { MTMessage } from './networker';
|
|||||||
import referenceDatabase from './referenceDatabase';
|
import referenceDatabase from './referenceDatabase';
|
||||||
import appDocsManager from '../appManagers/appDocsManager';
|
import appDocsManager from '../appManagers/appDocsManager';
|
||||||
import DEBUG, { MOUNT_CLASS_TO } from '../../config/debug';
|
import DEBUG, { MOUNT_CLASS_TO } from '../../config/debug';
|
||||||
|
import Socket from './transports/websocket';
|
||||||
|
|
||||||
type Task = {
|
type Task = {
|
||||||
taskId: number,
|
taskId: number,
|
||||||
@ -59,7 +59,7 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
|
|||||||
|
|
||||||
private debug = DEBUG;
|
private debug = DEBUG;
|
||||||
|
|
||||||
private socketsWorkers: Map<number, SocketWorker> = new Map();
|
private sockets: Map<number, Socket> = new Map();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -193,20 +193,53 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
|
|||||||
} else if(task.type === 'socketProxy') {
|
} else if(task.type === 'socketProxy') {
|
||||||
const socketTask = task.payload;
|
const socketTask = task.payload;
|
||||||
const id = socketTask.id;
|
const id = socketTask.id;
|
||||||
console.log('socketProxy', socketTask, id);
|
//console.log('socketProxy', socketTask, id);
|
||||||
|
|
||||||
if(socketTask.type === 'send') {
|
if(socketTask.type === 'send') {
|
||||||
const socketWorker = this.socketsWorkers.get(id);
|
const socket = this.sockets.get(id);
|
||||||
socketWorker.postMessage(socketTask);
|
socket.send(socketTask.payload);
|
||||||
} else if(socketTask.type === 'setup') {
|
} else if(socketTask.type === 'setup') {
|
||||||
const socketWorker = new SocketWorker();
|
const socket = new Socket(socketTask.payload.dcId, socketTask.payload.url, socketTask.payload.logSuffix);
|
||||||
socketWorker.postMessage(socketTask);
|
|
||||||
socketWorker.addEventListener('message', (e) => {
|
|
||||||
const task = e.data;
|
|
||||||
|
|
||||||
|
|
||||||
|
const onOpen = () => {
|
||||||
|
//console.log('socketProxy onOpen');
|
||||||
|
this.postMessage({
|
||||||
|
type: 'socketProxy',
|
||||||
|
payload: {
|
||||||
|
type: 'open',
|
||||||
|
id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const onClose = () => {
|
||||||
|
this.postMessage({
|
||||||
|
type: 'socketProxy',
|
||||||
|
payload: {
|
||||||
|
type: 'close',
|
||||||
|
id
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socketsWorkers.set(id, socketWorker);
|
socket.removeListener('open', onOpen);
|
||||||
|
socket.removeListener('close', onClose);
|
||||||
|
socket.removeListener('message', onMessage);
|
||||||
|
this.sockets.delete(id);
|
||||||
|
};
|
||||||
|
const onMessage = (buffer: ArrayBuffer) => {
|
||||||
|
this.postMessage({
|
||||||
|
type: 'socketProxy',
|
||||||
|
payload: {
|
||||||
|
type: 'message',
|
||||||
|
id,
|
||||||
|
payload: buffer
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.addListener('open', onOpen);
|
||||||
|
socket.addListener('close', onClose);
|
||||||
|
socket.addListener('message', onMessage);
|
||||||
|
this.sockets.set(id, socket);
|
||||||
}
|
}
|
||||||
} else if(task.hasOwnProperty('result') || task.hasOwnProperty('error')) {
|
} else if(task.hasOwnProperty('result') || task.hasOwnProperty('error')) {
|
||||||
this.finalizeTask(task.taskId, task.result, task.error);
|
this.finalizeTask(task.taskId, task.result, task.error);
|
||||||
|
@ -1013,7 +1013,7 @@ export default class MTPNetworker {
|
|||||||
|
|
||||||
public sendEncryptedRequest(message: MTMessage) {
|
public sendEncryptedRequest(message: MTMessage) {
|
||||||
return this.getEncryptedOutput(message).then(requestData => {
|
return this.getEncryptedOutput(message).then(requestData => {
|
||||||
const promise = this.transport.send(requestData);
|
const promise: Promise<Uint8Array> = this.transport.send(requestData) as any;
|
||||||
/// #if !MTPROTO_HTTP && !MTPROTO_HTTP_UPLOAD
|
/// #if !MTPROTO_HTTP && !MTPROTO_HTTP_UPLOAD
|
||||||
return promise;
|
return promise;
|
||||||
/// #else
|
/// #else
|
||||||
|
@ -2,8 +2,7 @@ import Modes from "../../../config/modes";
|
|||||||
import { logger, LogLevels } from "../../logger";
|
import { logger, LogLevels } from "../../logger";
|
||||||
import MTPNetworker from "../networker";
|
import MTPNetworker from "../networker";
|
||||||
import Obfuscation from "./obfuscation";
|
import Obfuscation from "./obfuscation";
|
||||||
import MTTransport from "./transport";
|
import MTTransport, { MTConnection, MTConnectionConstructable } from "./transport";
|
||||||
import Socket from "./websocket";
|
|
||||||
import intermediatePacketCodec from './intermediate';
|
import intermediatePacketCodec from './intermediate';
|
||||||
|
|
||||||
export default class TcpObfuscated implements MTTransport {
|
export default class TcpObfuscated implements MTTransport {
|
||||||
@ -27,11 +26,11 @@ export default class TcpObfuscated implements MTTransport {
|
|||||||
|
|
||||||
private lastCloseTime: number;
|
private lastCloseTime: number;
|
||||||
|
|
||||||
private socket: Socket;
|
private connection: MTConnection;
|
||||||
|
|
||||||
//private debugPayloads: MTPNetworker['debugRequests'] = [];
|
//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;
|
let logLevel = LogLevels.error | LogLevels.log;
|
||||||
if(this.debug) logLevel |= LogLevels.debug;
|
if(this.debug) logLevel |= LogLevels.debug;
|
||||||
this.log = logger(`WS-${dcId}` + logSuffix, logLevel);
|
this.log = logger(`WS-${dcId}` + logSuffix, logLevel);
|
||||||
@ -40,10 +39,7 @@ export default class TcpObfuscated implements MTTransport {
|
|||||||
this.connect();
|
this.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
private connect() {
|
private onOpen = () => {
|
||||||
this.socket = new Socket(this.dcId, this.url, this.logSuffix);
|
|
||||||
|
|
||||||
this.socket.addListener('open', () => {
|
|
||||||
this.connected = true;
|
this.connected = true;
|
||||||
|
|
||||||
const initPayload = this.obfuscation.init(this.codec);
|
const initPayload = this.obfuscation.init(this.codec);
|
||||||
@ -61,10 +57,10 @@ export default class TcpObfuscated implements MTTransport {
|
|||||||
this.releasePending();
|
this.releasePending();
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
this.socket.send(initPayload);
|
this.connection.send(initPayload);
|
||||||
});
|
};
|
||||||
|
|
||||||
this.socket.addListener('message', (buffer) => {
|
private onMessage = (buffer: ArrayBuffer) => {
|
||||||
let data = this.obfuscation.decode(new Uint8Array(buffer));
|
let data = this.obfuscation.decode(new Uint8Array(buffer));
|
||||||
data = this.codec.readPacket(data);
|
data = this.codec.readPacket(data);
|
||||||
|
|
||||||
@ -98,11 +94,10 @@ export default class TcpObfuscated implements MTTransport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pending.resolve(data);
|
pending.resolve(data);
|
||||||
});
|
};
|
||||||
|
|
||||||
this.socket.addListener('close', () => {
|
private onClose = () => {
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
this.socket = undefined;
|
|
||||||
|
|
||||||
const time = Date.now();
|
const time = Date.now();
|
||||||
const diff = time - this.lastCloseTime;
|
const diff = time - this.lastCloseTime;
|
||||||
@ -125,7 +120,19 @@ export default class TcpObfuscated implements MTTransport {
|
|||||||
|
|
||||||
this.connect();
|
this.connect();
|
||||||
}, needTimeout);
|
}, needTimeout);
|
||||||
});
|
|
||||||
|
this.connection.removeListener('open', this.onOpen);
|
||||||
|
this.connection.removeListener('close', this.onClose);
|
||||||
|
this.connection.removeListener('message', this.onMessage);
|
||||||
|
this.connection = undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
private connect() {
|
||||||
|
this.connection = new this.Connection(this.dcId, this.url, this.logSuffix);
|
||||||
|
|
||||||
|
this.connection.addListener('open', this.onOpen);
|
||||||
|
this.connection.addListener('close', this.onClose);
|
||||||
|
this.connection.addListener('message', this.onMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private encodeBody = (body: Uint8Array) => {
|
private encodeBody = (body: Uint8Array) => {
|
||||||
@ -202,7 +209,7 @@ export default class TcpObfuscated implements MTTransport {
|
|||||||
|
|
||||||
//this.lol.push(body);
|
//this.lol.push(body);
|
||||||
//setTimeout(() => {
|
//setTimeout(() => {
|
||||||
this.socket.send(encoded);
|
this.connection.send(encoded);
|
||||||
//}, 100);
|
//}, 100);
|
||||||
//this.dd();
|
//this.dd();
|
||||||
|
|
||||||
|
@ -1,3 +1,17 @@
|
|||||||
export default abstract class MTTransport {
|
import type EventListenerBase from "../../../helpers/eventListenerBase";
|
||||||
abstract send: (data: Uint8Array) => Promise<Uint8Array>;
|
|
||||||
|
export default interface MTTransport {
|
||||||
|
send: (data: Uint8Array) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MTConnection extends EventListenerBase<{
|
||||||
|
open: () => void,
|
||||||
|
message: (buffer: ArrayBuffer) => any,
|
||||||
|
close: () => void,
|
||||||
|
}> {
|
||||||
|
send: (data: Uint8Array) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MTConnectionConstructable {
|
||||||
|
new(dcId: number, url: string, logSuffix: string): MTConnection;
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import { logger, LogLevels } from '../../logger';
|
import { logger, LogLevels } from '../../logger';
|
||||||
import Modes from '../../../config/modes';
|
import Modes from '../../../config/modes';
|
||||||
import EventListenerBase from '../../../helpers/eventListenerBase';
|
import EventListenerBase from '../../../helpers/eventListenerBase';
|
||||||
|
import { MTConnection } from './transport';
|
||||||
|
|
||||||
export default class Socket extends EventListenerBase<{
|
export default class Socket extends EventListenerBase<{
|
||||||
open: () => void,
|
open: () => void,
|
||||||
message: (buffer: ArrayBuffer) => any,
|
message: (buffer: ArrayBuffer) => any,
|
||||||
close: () => void,
|
close: () => void,
|
||||||
}> {
|
}> implements MTConnection {
|
||||||
public ws: WebSocket;
|
private ws: WebSocket;
|
||||||
private log: ReturnType<typeof logger>;
|
private log: ReturnType<typeof logger>;
|
||||||
private debug = Modes.debug && false;
|
private debug = Modes.debug && false;
|
||||||
|
|
||||||
@ -19,6 +20,8 @@ export default class Socket extends EventListenerBase<{
|
|||||||
this.log = logger(`WS-${dcId}` + logSuffix, logLevel);
|
this.log = logger(`WS-${dcId}` + logSuffix, logLevel);
|
||||||
this.log('constructor');
|
this.log('constructor');
|
||||||
this.connect();
|
this.connect();
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeListeners() {
|
private removeListeners() {
|
||||||
|
Loading…
Reference in New Issue
Block a user