Task: Upgrading the http tunnel client to typescript language and updated the response and request models and updated the types
This commit is contained in:
510
src/client.ts
Normal file
510
src/client.ts
Normal file
@@ -0,0 +1,510 @@
|
||||
import * as os from "os";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as http from "http";
|
||||
import { io } from "socket.io-client";
|
||||
import { HttpsProxyAgent } from "https-proxy-agent";
|
||||
import { program, InvalidArgumentError, Argument } from "commander";
|
||||
import { TunnelRequest, TunnelResponse } from "./lib";
|
||||
import { generateUUID, addPrefixOnHttpSchema } from "./util";
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
const sdk = require("../sdk");
|
||||
|
||||
const packageInfo = require("../package.json");
|
||||
|
||||
// constants
|
||||
const PROFILE_DEFAULT = "default";
|
||||
const PROFILE_PATH = ".hlt";
|
||||
const SERVER_DEFAULT_URL = "https://lt.ctdn.net";
|
||||
const TOKEN_FREE = "FREE";
|
||||
|
||||
// create socket instance
|
||||
let socket: Socket | null = null;
|
||||
|
||||
function keepAlive() {
|
||||
setTimeout(() => {
|
||||
if (socket && socket.connected) {
|
||||
socket.send("ping");
|
||||
}
|
||||
keepAlive();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function initClient(options: any) {
|
||||
// Please change this if your domain goes wrong here
|
||||
// Current style using sub-domain: https://{{clientId}}-tunnel.myhostingdomain.com
|
||||
// (Original server: https://tunnel.myhostingdomain.com)
|
||||
const profile = options.profile || PROFILE_DEFAULT;
|
||||
const clientId = `${options.apiKey || options.clientId || generateUUID()}`;
|
||||
const clientIdSub =
|
||||
profile === PROFILE_DEFAULT ? `${clientId}-` : `${clientId}-${profile}-`;
|
||||
const clientEndpoint = (
|
||||
options.suffix ? `${clientIdSub}${options.suffix}-` : clientIdSub
|
||||
)
|
||||
.toLowerCase()
|
||||
.trim();
|
||||
const serverUrl = addPrefixOnHttpSchema(options.server, clientEndpoint);
|
||||
|
||||
// extra options for socket to identify the client (authentication and options of tunnel)
|
||||
const defaultParams = {
|
||||
apiKey: options.apiKey,
|
||||
clientId: options.clientId,
|
||||
profile: options.profile,
|
||||
clientIdSub: clientIdSub,
|
||||
clientEndpoint: clientEndpoint,
|
||||
serverUrl: serverUrl,
|
||||
access: options.access,
|
||||
keep_connection: options.keep_connection || true,
|
||||
};
|
||||
|
||||
// extra info for notify about the running of the tunnel (it's private info, other platfom cannot access this)
|
||||
// this using for internal only (don't worry about this)
|
||||
const osInfo = {
|
||||
hostname: os.hostname(),
|
||||
platform: os.platform(),
|
||||
arch: os.arch(),
|
||||
release: os.release(),
|
||||
};
|
||||
|
||||
const initParams = {
|
||||
path: "/$cubetiq_http_tunnel",
|
||||
transports: ["websocket"],
|
||||
auth: {
|
||||
token: options.token,
|
||||
...defaultParams,
|
||||
},
|
||||
headers: {
|
||||
...defaultParams,
|
||||
os: osInfo,
|
||||
},
|
||||
// reconnection: true,
|
||||
};
|
||||
|
||||
const http_proxy = process.env.https_proxy || process.env.http_proxy;
|
||||
if (http_proxy) {
|
||||
initParams.agent = new HttpsProxyAgent(http_proxy);
|
||||
}
|
||||
|
||||
// Connecting to socket server and agent here...
|
||||
console.log(`client connecting to server: ${serverUrl}`);
|
||||
socket = io(serverUrl, initParams);
|
||||
|
||||
const clientLogPrefix = `client: ${clientId} on profile: ${profile}`;
|
||||
socket.on("connect", () => {
|
||||
if (socket.connected) {
|
||||
console.log(`${clientLogPrefix} is connected to server successfully!`);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("connect_error", (e) => {
|
||||
console.log(
|
||||
`${clientLogPrefix} connect error:`,
|
||||
(e && e.message) || "something wrong"
|
||||
);
|
||||
if (e && e.message && e.message.startsWith("[40")) {
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("disconnect", (reason) => {
|
||||
console.log(`${clientLogPrefix} disconnected: ${reason}!`);
|
||||
});
|
||||
|
||||
socket.on("disconnect_exit", (reason) => {
|
||||
console.log(`${clientLogPrefix} disconnected and exited ${reason}!`);
|
||||
socket.disconnect();
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
socket.on("request", (requestId, request) => {
|
||||
const isWebSocket = request.headers.upgrade === "websocket";
|
||||
console.log(`${isWebSocket ? "WS" : request.method}: `, request.path);
|
||||
request.port = options.port;
|
||||
request.hostname = options.host;
|
||||
|
||||
if (options.origin) {
|
||||
request.headers.host = options.origin;
|
||||
}
|
||||
|
||||
const tunnelRequest = new TunnelRequest({
|
||||
requestId,
|
||||
socket: socket,
|
||||
});
|
||||
|
||||
const localReq = http.request(request);
|
||||
tunnelRequest.pipe(localReq);
|
||||
|
||||
const onTunnelRequestError = (e) => {
|
||||
tunnelRequest.off("end", onTunnelRequestEnd);
|
||||
localReq.destroy(e);
|
||||
};
|
||||
|
||||
const onTunnelRequestEnd = () => {
|
||||
tunnelRequest.off("error", onTunnelRequestError);
|
||||
};
|
||||
|
||||
tunnelRequest.once("error", onTunnelRequestError);
|
||||
tunnelRequest.once("end", onTunnelRequestEnd);
|
||||
|
||||
const onLocalResponse = (localRes) => {
|
||||
localReq.off("error", onLocalError);
|
||||
|
||||
if (isWebSocket && localRes.upgrade) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tunnelResponse = new TunnelResponse({
|
||||
responseId: requestId,
|
||||
socket: socket,
|
||||
});
|
||||
|
||||
tunnelResponse.writeHead(
|
||||
localRes.statusCode,
|
||||
localRes.statusMessage,
|
||||
localRes.headers,
|
||||
localRes.httpVersion
|
||||
);
|
||||
|
||||
localRes.pipe(tunnelResponse);
|
||||
};
|
||||
|
||||
const onLocalError = (error) => {
|
||||
console.log(error);
|
||||
localReq.off("response", onLocalResponse);
|
||||
socket.emit("request-error", requestId, error && error.message);
|
||||
tunnelRequest.destroy(error);
|
||||
};
|
||||
|
||||
const onUpgrade = (localRes, localSocket, localHead) => {
|
||||
// localSocket.once('error', onTunnelRequestError);
|
||||
if (localHead && localHead.length) localSocket.unshift(localHead);
|
||||
|
||||
const tunnelResponse = new TunnelResponse({
|
||||
responseId: requestId,
|
||||
socket: socket,
|
||||
duplex: true,
|
||||
});
|
||||
|
||||
tunnelResponse.writeHead(null, null, localRes.headers);
|
||||
localSocket.pipe(tunnelResponse).pipe(localSocket);
|
||||
};
|
||||
|
||||
localReq.once("error", onLocalError);
|
||||
localReq.once("response", onLocalResponse);
|
||||
|
||||
if (isWebSocket) {
|
||||
localReq.on("upgrade", onUpgrade);
|
||||
}
|
||||
});
|
||||
|
||||
// reconnect manually
|
||||
const tryReconnect = () => {
|
||||
setTimeout(() => {
|
||||
socket.io.open((err) => {
|
||||
if (err) {
|
||||
tryReconnect();
|
||||
}
|
||||
});
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
// socket.io.on("close", tryReconnect);
|
||||
|
||||
keepAlive();
|
||||
}
|
||||
|
||||
program
|
||||
.name("hlt")
|
||||
.description(
|
||||
"CUBETIQ HTTP tunnel client with free access for local tunneling"
|
||||
)
|
||||
.version(`v${packageInfo.version}`);
|
||||
|
||||
// init
|
||||
program
|
||||
.command("init")
|
||||
.description("generate a new client and token with free access")
|
||||
.option("-s --server <string>", "setting server url", SERVER_DEFAULT_URL)
|
||||
.option(
|
||||
"-t --token <string>",
|
||||
"setting token (default generate FREE access token)",
|
||||
""
|
||||
)
|
||||
.option("-a --access <string>", "setting token access type", TOKEN_FREE)
|
||||
.option("-c --client <string>", "setting client (auto generate uuid)")
|
||||
.option(
|
||||
"-k --key <string>",
|
||||
"setting client api key for authentication access"
|
||||
)
|
||||
.option("-p --profile <string>", "setting profile name", PROFILE_DEFAULT)
|
||||
.action(async (options) => {
|
||||
const configDir = path.resolve(os.homedir(), PROFILE_PATH);
|
||||
|
||||
if (!fs.existsSync(configDir)) {
|
||||
fs.mkdirSync(configDir);
|
||||
console.log(`config file ${configDir} was created`);
|
||||
}
|
||||
|
||||
let config: any = {};
|
||||
const configFilename = `${options.profile}.json`;
|
||||
const configFilePath = path.resolve(configDir, configFilename);
|
||||
|
||||
if (fs.existsSync(configFilePath)) {
|
||||
config = JSON.parse(fs.readFileSync(configFilePath, "utf8"));
|
||||
}
|
||||
|
||||
if (!config.server) {
|
||||
config.server = options.server || SERVER_DEFAULT_URL;
|
||||
}
|
||||
|
||||
if (!config.token && options.token) {
|
||||
config.token = options.token;
|
||||
}
|
||||
|
||||
if (!config.access) {
|
||||
config.access = options.access || TOKEN_FREE;
|
||||
}
|
||||
|
||||
if (!config.clientId) {
|
||||
config.clientId = options.client || generateUUID();
|
||||
}
|
||||
|
||||
if (!config.apiKey && options.key) {
|
||||
config.apiKey = options.key;
|
||||
}
|
||||
|
||||
if (!config.token) {
|
||||
console.log("Generating token...");
|
||||
await sdk
|
||||
.getTokenFree(config.server)
|
||||
.then((resp) => {
|
||||
if (resp.data?.token) {
|
||||
config.token = resp.data?.token;
|
||||
} else {
|
||||
console.log("free token return with null or empty from server");
|
||||
return;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("cannot get free token from server", err);
|
||||
return;
|
||||
});
|
||||
}
|
||||
|
||||
fs.writeFileSync(configFilePath, JSON.stringify(config, null, 2));
|
||||
console.log(`initialized config saved successfully to: ${configFilePath}`);
|
||||
});
|
||||
|
||||
// start
|
||||
program
|
||||
.command("start")
|
||||
.description("start a connection with specific port")
|
||||
.argument("<port>", "local server port number", (value) => {
|
||||
const port = parseInt(value, 10);
|
||||
if (isNaN(port)) {
|
||||
throw new InvalidArgumentError("Not a number.");
|
||||
}
|
||||
return port;
|
||||
})
|
||||
.option("-s, --suffix <string>", "suffix for client name")
|
||||
.option(
|
||||
"-K, --keep_connection <boolean>",
|
||||
"keep connection for client and old connection will be closed (override connection)",
|
||||
true
|
||||
)
|
||||
.option(
|
||||
"-k --key <string>",
|
||||
"setting client api key for authentication access"
|
||||
)
|
||||
.option("-a, --access <string>", "access type (FREE)", TOKEN_FREE)
|
||||
.option("-p, --profile <string>", "profile name", PROFILE_DEFAULT)
|
||||
.option("-h, --host <string>", "local host value", "localhost")
|
||||
.option("-o, --origin <string>", "change request origin")
|
||||
.action((port, options) => {
|
||||
const configDir = path.resolve(os.homedir(), PROFILE_PATH);
|
||||
|
||||
if (!fs.existsSync(configDir)) {
|
||||
fs.mkdirSync(configDir);
|
||||
}
|
||||
|
||||
let config: any = {};
|
||||
const configFilename = `${options.profile}.json`;
|
||||
const configFilePath = path.resolve(configDir, configFilename);
|
||||
|
||||
if (fs.existsSync(configFilePath)) {
|
||||
config = JSON.parse(fs.readFileSync(configFilePath, "utf8"));
|
||||
}
|
||||
|
||||
if (!config.server) {
|
||||
config.server = SERVER_DEFAULT_URL;
|
||||
}
|
||||
|
||||
if (!config.token) {
|
||||
console.info(`please init or set token for ${config.server}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!config.clientId) {
|
||||
if (!config.apiKey) {
|
||||
console.info(`please init or create a client for ${config.server}`);
|
||||
} else {
|
||||
config.clientId = config.apiKey;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
options.port = port;
|
||||
options.token = config.token;
|
||||
options.access = config.access;
|
||||
options.server = config.server;
|
||||
options.clientId = config.clientId;
|
||||
options.apiKey = options.key || config.apiKey;
|
||||
|
||||
if (options.suffix === "port" || options.suffix === "true") {
|
||||
options.suffix = `${port}`;
|
||||
} else if (options.suffix === "false") {
|
||||
options.suffix = undefined;
|
||||
} else if (options.suffix === "gen" || options.suffix === "uuid") {
|
||||
options.suffix = generateUUID();
|
||||
}
|
||||
|
||||
initClient(options);
|
||||
});
|
||||
|
||||
// config
|
||||
program
|
||||
.command("config")
|
||||
.description("create and update config file for connection")
|
||||
.addArgument(
|
||||
new Argument("<type>", "config type").choices([
|
||||
"access",
|
||||
"token",
|
||||
"server",
|
||||
"client",
|
||||
"key",
|
||||
])
|
||||
)
|
||||
.argument("<value>", "config value")
|
||||
.option("-p --profile <string>", "setting profile name", PROFILE_DEFAULT)
|
||||
.action(async (type, value, options) => {
|
||||
if (!type) {
|
||||
console.error("type config is required!");
|
||||
return;
|
||||
}
|
||||
|
||||
const configDir = path.resolve(os.homedir(), PROFILE_PATH);
|
||||
|
||||
if (!fs.existsSync(configDir)) {
|
||||
fs.mkdirSync(configDir);
|
||||
console.log(`config file ${configDir} was created`);
|
||||
}
|
||||
|
||||
let config: any = {};
|
||||
const configFilename = `${options.profile}.json`;
|
||||
const configFilePath = path.resolve(configDir, configFilename);
|
||||
|
||||
if (fs.existsSync(configFilePath)) {
|
||||
config = JSON.parse(fs.readFileSync(configFilePath, "utf8"));
|
||||
}
|
||||
|
||||
if (!config.server) {
|
||||
config.server = SERVER_DEFAULT_URL;
|
||||
}
|
||||
|
||||
if (type === "token" || type === "jwt") {
|
||||
config.token = value;
|
||||
} else if (type === "server") {
|
||||
config.server = value;
|
||||
} else if (type === "clientId" || type === "client") {
|
||||
if (!value || value === "" || value === "new") {
|
||||
config.clientId = generateUUID();
|
||||
} else {
|
||||
config.clientId = value;
|
||||
}
|
||||
console.log(`client: ${config.clientId} was set to config`);
|
||||
} else if (type === "apiKey" || type === "key") {
|
||||
config.apiKey = value;
|
||||
} else if (type === "access") {
|
||||
config.access = (value && value.toUpperCase().trim()) || TOKEN_FREE;
|
||||
|
||||
// FREE
|
||||
if (config.access === TOKEN_FREE) {
|
||||
await sdk
|
||||
.getTokenFree(config.server)
|
||||
.then((resp) => {
|
||||
if (resp.data?.token) {
|
||||
config.token = resp.data?.token;
|
||||
} else {
|
||||
console.log("free token return with null or empty from server");
|
||||
return;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("cannot get free token from server", err);
|
||||
return;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.clientId && config.apiKey) {
|
||||
config.clientId = config.apiKey;
|
||||
}
|
||||
|
||||
fs.writeFileSync(configFilePath, JSON.stringify(config, null, 2));
|
||||
console.log(`${type} config saved successfully to: ${configFilePath}`);
|
||||
});
|
||||
|
||||
// config
|
||||
program
|
||||
.command("config-get")
|
||||
.description("get type from config file")
|
||||
.addArgument(
|
||||
new Argument("<type>", "config type").choices([
|
||||
"access",
|
||||
"token",
|
||||
"server",
|
||||
"client",
|
||||
"key",
|
||||
])
|
||||
)
|
||||
.option("-p --profile <string>", "setting profile name", PROFILE_DEFAULT)
|
||||
.action(async (type, options) => {
|
||||
if (!type) {
|
||||
console.error("type config is required!");
|
||||
return;
|
||||
}
|
||||
|
||||
const configDir = path.resolve(os.homedir(), PROFILE_PATH);
|
||||
if (!fs.existsSync(configDir)) {
|
||||
console.log(`config file ${configDir} not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
let config: any = {};
|
||||
const configFilename = `${options.profile}.json`;
|
||||
const configFilePath = path.resolve(configDir, configFilename);
|
||||
|
||||
if (fs.existsSync(configFilePath)) {
|
||||
config = JSON.parse(fs.readFileSync(configFilePath, "utf8"));
|
||||
} else {
|
||||
console.log(`config file ${configFilePath} not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "token" || type === "jwt") {
|
||||
console.log(config.token);
|
||||
} else if (type === "server") {
|
||||
console.log(config.server);
|
||||
} else if (type === "clientId" || type === "client") {
|
||||
console.log(config.clientId);
|
||||
} else if (type === "apiKey" || type === "key") {
|
||||
console.log(config.apiKey);
|
||||
} else if (type === "access") {
|
||||
console.log(config.access);
|
||||
} else {
|
||||
console.log('no config found for type: "' + type + '"');
|
||||
}
|
||||
});
|
||||
|
||||
program.parse();
|
||||
164
src/lib.ts
Normal file
164
src/lib.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
import * as stream from "stream";
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
class TunnelRequest extends stream.Readable {
|
||||
constructor(private socket: Socket, private requestId: string) {
|
||||
super();
|
||||
|
||||
const onRequestPipe = (requestId: string, data: any) => {
|
||||
if (this.requestId === requestId) {
|
||||
this.push(data);
|
||||
}
|
||||
};
|
||||
|
||||
const onRequestPipes = (requestId: string, data: any) => {
|
||||
if (!data) return;
|
||||
if (this.requestId === requestId) {
|
||||
data.forEach((chunk: any) => {
|
||||
this.push(chunk);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onRequestPipeError = (requestId: string, error?: any) => {
|
||||
if (this.requestId === requestId) {
|
||||
this.socket.off("request-pipe", onRequestPipe);
|
||||
this.socket.off("request-pipes", onRequestPipes);
|
||||
this.socket.off("request-pipe-error", onRequestPipeError);
|
||||
this.socket.off("request-pipe-end", onRequestPipeEnd);
|
||||
this.destroy(new Error(error));
|
||||
}
|
||||
};
|
||||
|
||||
const onRequestPipeEnd = (requestId: string, data: any) => {
|
||||
if (this.requestId === requestId) {
|
||||
this.socket.off("request-pipe", onRequestPipe);
|
||||
this.socket.off("request-pipes", onRequestPipes);
|
||||
this.socket.off("request-pipe-error", onRequestPipeError);
|
||||
this.socket.off("request-pipe-end", onRequestPipeEnd);
|
||||
if (data) {
|
||||
this.push(data);
|
||||
}
|
||||
this.push(null);
|
||||
}
|
||||
};
|
||||
|
||||
this.socket.on("request-pipe", onRequestPipe);
|
||||
this.socket.on("request-pipes", onRequestPipes);
|
||||
this.socket.on("request-pipe-error", onRequestPipeError);
|
||||
this.socket.on("request-pipe-end", onRequestPipeEnd);
|
||||
}
|
||||
|
||||
_read() { }
|
||||
}
|
||||
|
||||
class TunnelResponse extends stream.Duplex {
|
||||
constructor(private socket: Socket, private responseId: string, duplex?: boolean) {
|
||||
super();
|
||||
|
||||
if (duplex) {
|
||||
// for websocket request: bidirection
|
||||
const onResponsePipe = (responseId: string, data: any) => {
|
||||
if (this.responseId === responseId) {
|
||||
this.push(data);
|
||||
}
|
||||
};
|
||||
|
||||
const onResponsePipes = (responseId: string, data: any) => {
|
||||
if (this.responseId === responseId) {
|
||||
data.forEach((chunk: any) => {
|
||||
this.push(chunk);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onResponsePipeError = (responseId: string, error?: any) => {
|
||||
if (this.responseId === responseId) {
|
||||
this.socket.off("response-pipe", onResponsePipe);
|
||||
this.socket.off("response-pipes", onResponsePipes);
|
||||
this.socket.off("response-pipe-error", onResponsePipeError);
|
||||
this.socket.off("response-pipe-end", onResponsePipeEnd);
|
||||
this.destroy(new Error(error));
|
||||
}
|
||||
};
|
||||
|
||||
const onResponsePipeEnd = (responseId: string, data: any) => {
|
||||
if (this.responseId === responseId) {
|
||||
this.socket.off("response-pipe", onResponsePipe);
|
||||
this.socket.off("response-pipes", onResponsePipes);
|
||||
this.socket.off("response-pipe-error", onResponsePipeError);
|
||||
this.socket.off("response-pipe-end", onResponsePipeEnd);
|
||||
if (data) {
|
||||
this.push(data);
|
||||
}
|
||||
this.push(null);
|
||||
}
|
||||
};
|
||||
|
||||
this.socket.on("response-pipe", onResponsePipe);
|
||||
this.socket.on("response-pipes", onResponsePipes);
|
||||
this.socket.on("response-pipe-error", onResponsePipeError);
|
||||
this.socket.on("response-pipe-end", onResponsePipeEnd);
|
||||
}
|
||||
}
|
||||
|
||||
_write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void) {
|
||||
this.socket.emit("response-pipe", this.responseId, chunk);
|
||||
this.socket.io.engine.once("drain", () => {
|
||||
callback && callback();
|
||||
});
|
||||
}
|
||||
|
||||
_writev(
|
||||
chunks: Array<{
|
||||
chunk: any;
|
||||
encoding: BufferEncoding;
|
||||
}>,
|
||||
callback: (error?: Error | null) => void) {
|
||||
this.socket.emit("response-pipes", this.responseId, chunks);
|
||||
this.socket.io.engine.once("drain", () => {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
_final(callback: (error?: Error | null) => void) {
|
||||
this.socket.emit("response-pipe-end", this.responseId);
|
||||
this.socket.io.engine.once("drain", () => {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
_destroy(error: Error | null, callback: (error: Error | null) => void) {
|
||||
if (error) {
|
||||
this.socket.emit(
|
||||
"response-pipe-error",
|
||||
this.responseId,
|
||||
error && error.message
|
||||
);
|
||||
|
||||
this.socket.io.engine.once("drain", () => {
|
||||
callback(error);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
callback(null);
|
||||
}
|
||||
|
||||
writeHead(statusCode: any, statusMessage?: any, headers?: any, httpVersion?: any) {
|
||||
this.socket.emit("response", this.responseId, {
|
||||
statusCode,
|
||||
statusMessage,
|
||||
headers,
|
||||
httpVersion,
|
||||
});
|
||||
}
|
||||
|
||||
_read(size: number) { }
|
||||
}
|
||||
|
||||
export {
|
||||
TunnelRequest,
|
||||
TunnelResponse
|
||||
}
|
||||
19
src/sdk.ts
Normal file
19
src/sdk.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
const axios = require("axios").default;
|
||||
|
||||
const getTokenFree = async (baseUrl, data = {}) => {
|
||||
const url = `${baseUrl}/__free__/api/get_token`;
|
||||
return axios({
|
||||
method: "POST",
|
||||
url: url,
|
||||
data: {
|
||||
...data,
|
||||
},
|
||||
headers: {
|
||||
"x-access-type": "FREE",
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getTokenFree,
|
||||
};
|
||||
19
src/util.ts
Normal file
19
src/util.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import * as crypto from "crypto";
|
||||
|
||||
const addPrefixOnHttpSchema = (url: string, prefixDomain: string) => {
|
||||
let prefixSubDomain = prefixDomain;
|
||||
const prefixSchema = url.substring(0, url.indexOf("://") + 3);
|
||||
const splitDomain = url.substring(url.indexOf("://") + 3);
|
||||
|
||||
// if (!prefixSubDomain.endsWith(".")) {
|
||||
// prefixSubDomain = `${prefixSubDomain}.`;
|
||||
// }
|
||||
|
||||
return `${prefixSchema}${prefixSubDomain}${splitDomain}`;
|
||||
};
|
||||
|
||||
const generateUUID = () => {
|
||||
return crypto.randomUUID();
|
||||
};
|
||||
|
||||
export { addPrefixOnHttpSchema, generateUUID };
|
||||
Reference in New Issue
Block a user