Compare commits
150 Commits
hlt-api
...
56c278d84e
| Author | SHA1 | Date | |
|---|---|---|---|
|
56c278d84e
|
|||
|
20932e3b12
|
|||
|
62db7f8145
|
|||
|
|
10ce27ecac | ||
|
|
43c383c84b | ||
|
|
d5724f5c46 | ||
|
|
0a48c548db | ||
|
|
07b75a0298 | ||
|
|
d60c6fe57f | ||
|
775c5da038
|
|||
|
87339a97d5
|
|||
|
0f115da19b
|
|||
|
656c8e0ef7
|
|||
|
98929a1e0f
|
|||
| 967d06ed1e | |||
|
a30c05e942
|
|||
|
92312f465f
|
|||
|
74fded00f2
|
|||
|
|
1cce221630 | ||
|
|
db3b669882 | ||
|
|
c07dd4d48a | ||
|
|
1aa300e92c | ||
|
|
c39997f583 | ||
|
|
cb8f18c9a5 | ||
|
|
825cc3e5ff | ||
|
|
7c86f58c88 | ||
|
|
9a9f6d4e16 | ||
|
|
0644f565fc | ||
|
|
265e778663 | ||
|
|
d03216ce63 | ||
|
|
3fd3048de1 | ||
|
|
1e86d7a57e | ||
|
|
a5ff011d28 | ||
|
|
07e11b67f2 | ||
|
|
19dea09433 | ||
|
|
488b48a086 | ||
|
|
303dac4ead | ||
|
|
5a3e66b089 | ||
|
|
05889acf5d | ||
|
|
858c21ccdb | ||
|
|
43c05a14f5 | ||
|
|
e46ac94fcc | ||
|
|
f65f6c2c23 | ||
|
|
10e5d62a63 | ||
|
|
566c768cdc | ||
|
|
4080c8c3f0 | ||
|
|
f0780a408c | ||
|
|
4570c20d1d | ||
|
|
b08259b047 | ||
|
|
4621840c38 | ||
|
|
c9ef13bb7f | ||
|
|
eb7bcc7eaf | ||
|
|
746ac54e13 | ||
|
|
378e2e1673 | ||
|
|
2fadb7fa87 | ||
|
|
260150e380 | ||
|
|
c589591fff | ||
|
|
4712b7067b | ||
|
|
b7f9ac1c43 | ||
|
|
9a53420382 | ||
|
|
791a19121e | ||
|
|
0befacfc6e | ||
|
|
c60e5aaec6 | ||
|
|
4e4eda3e7d | ||
|
|
dc26f0e8fb | ||
|
|
40bd8e11b7 | ||
|
|
7fb294dba6 | ||
|
|
7a764ecbb9 | ||
|
|
528e4ed678 | ||
|
|
19f98343e5 | ||
|
|
987c7c4ac3 | ||
|
|
ec27f032a8 | ||
|
|
ee8a5ef1d1 | ||
|
|
d0233ef8fa | ||
|
|
1c03199973 | ||
|
|
b5a0bb6344 | ||
|
|
b628a6f812 | ||
|
|
28d998e361 | ||
|
|
14042edb7f | ||
|
|
c85b388cb7 | ||
|
|
96da8ae1b7 | ||
|
|
5d28e1c949 | ||
|
|
53a6095cad | ||
|
|
44e9e01180 | ||
|
|
6fc25fd080 | ||
|
|
e27db703a6 | ||
|
|
eef52f4e58 | ||
|
|
8968992b43 | ||
|
|
80c6800253 | ||
|
|
243824564a | ||
|
|
f714c0e0d2 | ||
|
|
962976a194 | ||
|
|
629928c926 | ||
|
|
1850bf870d | ||
|
|
fb053bde16 | ||
|
|
8df565c222 | ||
|
|
50965ee594 | ||
|
|
eedbcce77a | ||
|
|
814d94f8f6 | ||
|
|
ffb004f7cb | ||
|
|
fc369fbd94 | ||
|
|
882859b2c5 | ||
|
|
ac55743129 | ||
|
|
bab60efd10 | ||
|
|
b191f9fd96 | ||
|
|
4daaebb71f | ||
|
|
db673b20f0 | ||
|
|
96f72024ff | ||
|
|
d79386fd3b | ||
|
|
418c1b8149 | ||
|
|
1585f920b3 | ||
|
|
74c1b461a1 | ||
|
|
3e3840a6f5 | ||
|
|
f42397c0a6 | ||
|
|
1fa82cbb05 | ||
|
|
f2bf0b64e8 | ||
|
|
31e137db6c | ||
|
|
83b408d233 | ||
|
|
d2e9ec5e21 | ||
|
|
1d6bc41d62 | ||
|
|
6b32c06dcf | ||
|
|
91e144bcc0 | ||
|
|
200ec2477e | ||
|
|
36954101c0 | ||
|
|
d043ebdeff | ||
|
|
50dbe48149 | ||
|
|
d8ab247d2c | ||
|
|
1ff1d13f2a | ||
|
|
189874d9f5 | ||
|
|
d23557f71b | ||
|
|
801213c5ae | ||
|
|
b663d979f5 | ||
|
|
5ee8c71afb | ||
|
|
b220899d42 | ||
|
|
9db8de64df | ||
|
|
30a61a8069 | ||
|
|
5be16bb4ca | ||
|
|
3cd4f12e4e | ||
|
|
0793ae7d27 | ||
|
|
cec0ec844f | ||
|
|
f7cab88087 | ||
|
|
0e619a172e | ||
|
|
f9d0e706ee | ||
|
|
d89e754d7c | ||
|
|
542d5a54aa | ||
|
|
cbcc925818 | ||
|
|
a636069a3f | ||
|
|
c053c5d88a | ||
|
|
ae14c7c5e7 | ||
|
|
7c22abc048 |
4
.github/workflows/node.js.yml
vendored
4
.github/workflows/node.js.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [12.x, 14.x, 16.x]
|
node-version: [14.x, 16.x, 18.x, 20.x]
|
||||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -26,5 +26,5 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
- run: npm ci
|
- run: npm i && npm ci
|
||||||
- run: npm run build --if-present
|
- run: npm run build --if-present
|
||||||
|
|||||||
23
CHANGELOG.md
23
CHANGELOG.md
@@ -1,8 +1,29 @@
|
|||||||
### 11/07/2023
|
### 14/07/2023 (1.0.8)
|
||||||
|
|
||||||
|
- Fixed the start with port unable to start
|
||||||
|
|
||||||
|
### 11/07/2023 (1.0.8)
|
||||||
|
|
||||||
|
- Support tunnel with host with port
|
||||||
|
|
||||||
|
* Prev
|
||||||
|
|
||||||
|
```
|
||||||
|
hlt start 8080 -h 192.168.1.1
|
||||||
|
```
|
||||||
|
|
||||||
|
- New
|
||||||
|
|
||||||
|
```
|
||||||
|
hlt start 192.168.1.1:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11/07/2023 (1.0.7)
|
||||||
|
|
||||||
- Support Client API
|
- Support Client API
|
||||||
- Support Proxy (HTTP/HTTPS) and TCP
|
- Support Proxy (HTTP/HTTPS) and TCP
|
||||||
- Improvements and Bugs fixed
|
- Improvements and Bugs fixed
|
||||||
|
- Support auto proxy with hlt client
|
||||||
|
|
||||||
### 30/11/2022
|
### 30/11/2022
|
||||||
|
|
||||||
|
|||||||
1903
package-lock.json
generated
1903
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@cubetiq/hlt",
|
"name": "@cubetiq/hlt",
|
||||||
"version": "0.1.6",
|
"version": "0.1.9",
|
||||||
"description": "A lightweight http tunnel client using nodejs and socket.io client",
|
"description": "A lightweight http tunnel client using nodejs and socket.io client",
|
||||||
"main": "dist/cli.js",
|
"main": "dist/cli.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -8,9 +8,9 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "ts-node-dev --respawn --transpile-only src/cli.ts",
|
"start": "ts-node-dev --respawn --transpile-only src/cli.ts",
|
||||||
"test": "ts-node-dev --respawn --transpile-only src/test.ts",
|
"test": "ts-node-dev --respawn --transpile-only test/test.ts",
|
||||||
"local": "ts-node-dev --respawn --transpile-only src/cli.ts start -p local",
|
"local": "ts-node-dev --respawn --transpile-only src/cli.ts start -p local",
|
||||||
"build": "tsc"
|
"build": "rimraf dist && tsc"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -24,10 +24,10 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.2.0",
|
"axios": "^1.2.0",
|
||||||
"commander": "^9.3.0",
|
"commander": "^11.0.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"http-proxy-middleware": "^2.0.6",
|
"http-proxy-middleware": "^2.0.6",
|
||||||
"https-proxy-agent": "^5.0.1",
|
"https-proxy-agent": "^7.0.0",
|
||||||
"socket.io-client": "^4.5.1"
|
"socket.io-client": "^4.5.1"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
@@ -35,8 +35,9 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.15",
|
"@types/express": "^4.17.15",
|
||||||
"@types/node": "^18.0.3",
|
"@types/node": "^20.0.0",
|
||||||
|
"rimraf": "^5.0.1",
|
||||||
"ts-node-dev": "^2.0.0",
|
"ts-node-dev": "^2.0.0",
|
||||||
"typescript": "^4.7.4"
|
"typescript": "^5.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
renovate.json
Normal file
6
renovate.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": [
|
||||||
|
"config:base"
|
||||||
|
]
|
||||||
|
}
|
||||||
64
src/api.ts
64
src/api.ts
@@ -11,15 +11,17 @@ import { PROFILE_DEFAULT, PROFILE_PATH, SERVER_DEFAULT_URL, TOKEN_FREE } from ".
|
|||||||
import { ClientOptions, Options } from "./interface";
|
import { ClientOptions, Options } from "./interface";
|
||||||
import { getTokenFree } from './sdk';
|
import { getTokenFree } from './sdk';
|
||||||
|
|
||||||
interface Stoppable {
|
interface Client {
|
||||||
|
getEndpoint(): string | null;
|
||||||
stop(): void;
|
stop(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
class HttpTunnelClient implements Stoppable {
|
class HttpTunnelClient implements Client {
|
||||||
// create socket instance
|
// create socket instance
|
||||||
private socket: Socket | null = null;
|
private socket: Socket | null = null;
|
||||||
private keepAliveTimer: NodeJS.Timeout | null = null;
|
private keepAliveTimer: NodeJS.Timeout | null = null;
|
||||||
private keepAliveTimeout: number | null = null;
|
private keepAliveTimeout: number | null = null;
|
||||||
|
private endpoint: string | null = null;
|
||||||
|
|
||||||
private keepAlive() {
|
private keepAlive() {
|
||||||
if (!this.socket) {
|
if (!this.socket) {
|
||||||
@@ -119,6 +121,7 @@ class HttpTunnelClient implements Stoppable {
|
|||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.trim();
|
.trim();
|
||||||
const serverUrl = addPrefixOnHttpSchema(options.server || SERVER_DEFAULT_URL, clientEndpoint);
|
const serverUrl = addPrefixOnHttpSchema(options.server || SERVER_DEFAULT_URL, clientEndpoint);
|
||||||
|
this.endpoint = serverUrl
|
||||||
|
|
||||||
// extra options for socket to identify the client (authentication and options of tunnel)
|
// extra options for socket to identify the client (authentication and options of tunnel)
|
||||||
const defaultParams = {
|
const defaultParams = {
|
||||||
@@ -278,8 +281,50 @@ class HttpTunnelClient implements Stoppable {
|
|||||||
this.keepAlive();
|
this.keepAlive();
|
||||||
};
|
};
|
||||||
|
|
||||||
public start = async (clientOptions: ClientOptions): Promise<Stoppable | undefined> => {
|
public start = async (clientOptions: Partial<ClientOptions>): Promise<Client | undefined> => {
|
||||||
const { port, options = {} } = clientOptions;
|
const { port, address, options = {} } = clientOptions;
|
||||||
|
|
||||||
|
// Load host and port check
|
||||||
|
if (!port) {
|
||||||
|
if (!address) {
|
||||||
|
console.error("port or address is required!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [host, portStr] = address.split(":");
|
||||||
|
if (!host || !portStr) {
|
||||||
|
console.error("invalid address!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
options.host = host;
|
||||||
|
try {
|
||||||
|
options.port = parseInt(portStr);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("invalid port!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (typeof address !== "number" && address && address.includes(":")) {
|
||||||
|
const [host, portStr] = address.split(":");
|
||||||
|
if (host) {
|
||||||
|
options.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (portStr) {
|
||||||
|
try {
|
||||||
|
options.port = parseInt(portStr);
|
||||||
|
console.log(`default port: ${port} will be ignored and override by port: ${options.port}`);
|
||||||
|
} catch (e) {
|
||||||
|
options.port = port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
options.port = port;
|
||||||
|
console.log(`default port: ${port} will be forwared`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const configDir = path.resolve(os.homedir(), PROFILE_PATH);
|
const configDir = path.resolve(os.homedir(), PROFILE_PATH);
|
||||||
|
|
||||||
if (!fs.existsSync(configDir)) {
|
if (!fs.existsSync(configDir)) {
|
||||||
@@ -289,7 +334,6 @@ class HttpTunnelClient implements Stoppable {
|
|||||||
let config: any = {};
|
let config: any = {};
|
||||||
const configFilename = `${options.profile || PROFILE_DEFAULT}.json`;
|
const configFilename = `${options.profile || PROFILE_DEFAULT}.json`;
|
||||||
const configFilePath = path.resolve(configDir, configFilename);
|
const configFilePath = path.resolve(configDir, configFilename);
|
||||||
console.log(`config file: ${configFilePath}`);
|
|
||||||
|
|
||||||
if (fs.existsSync(configFilePath)) {
|
if (fs.existsSync(configFilePath)) {
|
||||||
config = JSON.parse(fs.readFileSync(configFilePath, "utf8"));
|
config = JSON.parse(fs.readFileSync(configFilePath, "utf8"));
|
||||||
@@ -313,7 +357,7 @@ class HttpTunnelClient implements Stoppable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
options.port = port;
|
// options.port = port;
|
||||||
options.token = config.token;
|
options.token = config.token;
|
||||||
options.access = config.access;
|
options.access = config.access;
|
||||||
options.server = config.server;
|
options.server = config.server;
|
||||||
@@ -329,8 +373,6 @@ class HttpTunnelClient implements Stoppable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await this.initStartClient(options);
|
await this.initStartClient(options);
|
||||||
console.log("client started!");
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -341,9 +383,13 @@ class HttpTunnelClient implements Stoppable {
|
|||||||
this.socket = null;
|
this.socket = null;
|
||||||
this.keepAliveTimer && clearInterval(this.keepAliveTimer);
|
this.keepAliveTimer && clearInterval(this.keepAliveTimer);
|
||||||
|
|
||||||
console.log("client stopped!");
|
console.log("client stopped from server:", this.endpoint);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public getEndpoint = () => {
|
||||||
|
return this.endpoint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const client = new HttpTunnelClient();
|
export const client = new HttpTunnelClient();
|
||||||
|
|||||||
31
src/cli.ts
31
src/cli.ts
@@ -44,10 +44,14 @@ program
|
|||||||
program
|
program
|
||||||
.command("start")
|
.command("start")
|
||||||
.description("start a connection with specific port")
|
.description("start a connection with specific port")
|
||||||
.argument("<port>", "local server port number", (value) => {
|
.argument("<port> | <address>", "local server port number or address", (value) => {
|
||||||
|
if (isValidHost(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
const port = parseInt(value, 10);
|
const port = parseInt(value, 10);
|
||||||
if (isNaN(port)) {
|
if (isNaN(port)) {
|
||||||
throw new InvalidArgumentError("Not a number.");
|
throw new InvalidArgumentError("Not a number or valid address.");
|
||||||
}
|
}
|
||||||
return port;
|
return port;
|
||||||
})
|
})
|
||||||
@@ -65,9 +69,10 @@ program
|
|||||||
.option("-p, --profile <string>", "profile name", PROFILE_DEFAULT)
|
.option("-p, --profile <string>", "profile name", PROFILE_DEFAULT)
|
||||||
.option("-h, --host <string>", "local host value", "localhost")
|
.option("-h, --host <string>", "local host value", "localhost")
|
||||||
.option("-o, --origin <string>", "change request origin")
|
.option("-o, --origin <string>", "change request origin")
|
||||||
.action((port, options) => {
|
.action((portOrAddress, options) => {
|
||||||
startClient({
|
startClient({
|
||||||
port,
|
port: portOrAddress,
|
||||||
|
address: portOrAddress,
|
||||||
options,
|
options,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -266,7 +271,8 @@ program
|
|||||||
|
|
||||||
throw new InvalidArgumentError("Target is not a url or host with port.");
|
throw new InvalidArgumentError("Target is not a url or host with port.");
|
||||||
})
|
})
|
||||||
.action((port, target) => {
|
.option("-p --profile <string>", "setting profile name for connect with hlt server (proxy with current local port)")
|
||||||
|
.action((port, target, options) => {
|
||||||
const isTcp = target.indexOf("tcp") === 0;
|
const isTcp = target.indexOf("tcp") === 0;
|
||||||
if (isTcp) {
|
if (isTcp) {
|
||||||
console.log("[TCP] Start proxy server with port:", port, "and target:", target);
|
console.log("[TCP] Start proxy server with port:", port, "and target:", target);
|
||||||
@@ -277,6 +283,8 @@ program
|
|||||||
proxyPort: port,
|
proxyPort: port,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onConnectProxy(port, options);
|
||||||
|
|
||||||
proxy.on("error", (err) => {
|
proxy.on("error", (err) => {
|
||||||
console.error("Proxy server error:", err);
|
console.error("Proxy server error:", err);
|
||||||
});
|
});
|
||||||
@@ -284,12 +292,15 @@ program
|
|||||||
proxy.on("close", () => {
|
proxy.on("close", () => {
|
||||||
console.log("Proxy server closed");
|
console.log("Proxy server closed");
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.log("[HTTP/HTTPS] Start proxy server with port:", port, "and target:", target);
|
console.log("[HTTP/HTTPS] Start proxy server with port:", port, "and target:", target);
|
||||||
const proxy = createProxyServer(target, {
|
const proxy = createProxyServer(target, {
|
||||||
proxyPort: port,
|
proxyPort: port,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onConnectProxy(port, options);
|
||||||
|
|
||||||
proxy.on("error", (err) => {
|
proxy.on("error", (err) => {
|
||||||
console.error("Proxy server error:", err);
|
console.error("Proxy server error:", err);
|
||||||
});
|
});
|
||||||
@@ -301,4 +312,14 @@ program
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const onConnectProxy = (port: number, options: any) => {
|
||||||
|
if (options?.profile) {
|
||||||
|
console.log(`Start proxy: ${port} via hlt client with profile: ${options.profile}`);
|
||||||
|
startClient({
|
||||||
|
port,
|
||||||
|
options,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
program.parse();
|
program.parse();
|
||||||
|
|||||||
@@ -17,5 +17,6 @@ export interface Options {
|
|||||||
|
|
||||||
export interface ClientOptions {
|
export interface ClientOptions {
|
||||||
port: number;
|
port: number;
|
||||||
|
address?: string; // e.g. localhost:8081 (take if port is not set)
|
||||||
options?: Options;
|
options?: Options;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
const axios = require("axios");
|
import axios from "axios";
|
||||||
|
|
||||||
const getTokenFree = async (baseUrl: string, data: any = {}) => {
|
const getTokenFree = async (baseUrl: string, data: any = {}) => {
|
||||||
const url = `${baseUrl}/__free__/api/get_token`;
|
const url = `${baseUrl}/__free__/api/get_token`;
|
||||||
|
|||||||
@@ -2,15 +2,18 @@ import { startClient } from '../src/api';
|
|||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const client = await startClient({
|
const client = await startClient({
|
||||||
port: 3000,
|
// port: 8081,
|
||||||
|
address: '172.17.0.2:8222',
|
||||||
options: {
|
options: {
|
||||||
profile: 'mytest',
|
profile: 'mytest',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('Client started:', client?.getEndpoint());
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
client?.stop();
|
client?.stop();
|
||||||
}, 5000);
|
}, 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((err) => {
|
main().catch((err) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user