tunli 0.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +595 -0
- package/README.md +135 -0
- package/bin/tunli +11 -0
- package/client.js +31 -0
- package/package.json +51 -0
- package/src/cli-app/Dashboard.js +146 -0
- package/src/cli-app/Screen.js +135 -0
- package/src/cli-app/elements/ElementNode.js +97 -0
- package/src/cli-app/elements/Line.js +21 -0
- package/src/cli-app/elements/List/List.js +227 -0
- package/src/cli-app/elements/List/ListCell.js +83 -0
- package/src/cli-app/elements/List/ListColumn.js +52 -0
- package/src/cli-app/elements/List/ListRow.js +118 -0
- package/src/cli-app/elements/Row.js +38 -0
- package/src/cli-app/helper/utils.js +42 -0
- package/src/commands/Action/addDelValuesAction.js +56 -0
- package/src/commands/CommandAuth.js +32 -0
- package/src/commands/CommandClearAll.js +27 -0
- package/src/commands/CommandConfig.js +57 -0
- package/src/commands/CommandHTTP.js +131 -0
- package/src/commands/CommandInvite.js +38 -0
- package/src/commands/CommandRefresh.js +35 -0
- package/src/commands/CommandRegister.js +48 -0
- package/src/commands/Option/DeleteOption.js +6 -0
- package/src/commands/Option/SelectConfigOption.js +52 -0
- package/src/commands/SubCommand/AllowDenyCidrCommand.js +28 -0
- package/src/commands/SubCommand/HostCommand.js +22 -0
- package/src/commands/SubCommand/PortCommand.js +20 -0
- package/src/commands/helper/AliasResolver.js +13 -0
- package/src/commands/helper/BindArgs.js +53 -0
- package/src/commands/helper/SharedArg.js +32 -0
- package/src/commands/utils.js +96 -0
- package/src/config/ConfigAbstract.js +318 -0
- package/src/config/ConfigManager.js +70 -0
- package/src/config/GlobalConfig.js +14 -0
- package/src/config/GlobalLocalShardConfigAbstract.js +76 -0
- package/src/config/LocalConfig.js +7 -0
- package/src/config/PropertyConfig.js +122 -0
- package/src/config/SystemConfig.js +31 -0
- package/src/core/FS/utils.js +60 -0
- package/src/core/Ref.js +70 -0
- package/src/lib/Flow/getCurrentIp.js +18 -0
- package/src/lib/Flow/getLatestVersion.js +13 -0
- package/src/lib/Flow/proxyUrl.js +32 -0
- package/src/lib/Flow/validateAuthToken.js +19 -0
- package/src/lib/HttpClient.js +61 -0
- package/src/lib/defs.js +10 -0
- package/src/net/IPV4.js +139 -0
- package/src/net/http/IncomingMessage.js +92 -0
- package/src/net/http/ServerResponse.js +126 -0
- package/src/net/http/TunliRequest.js +1 -0
- package/src/net/http/TunliResponse.js +1 -0
- package/src/net/http/TunnelRequest.js +177 -0
- package/src/net/http/TunnelResponse.js +119 -0
- package/src/tunnel-client/TunnelClient.js +136 -0
- package/src/utils/arrayFunctions.js +45 -0
- package/src/utils/checkFunctions.js +161 -0
- package/src/utils/cliFunctions.js +62 -0
- package/src/utils/createRequest.js +12 -0
- package/src/utils/httpFunction.js +23 -0
- package/src/utils/npmFunctions.js +27 -0
- package/src/utils/stringFunctions.js +34 -0
- package/types/index.d.ts +112 -0
package/src/core/Ref.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import EventEmitter from 'node:events'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A class representing a reference to a value.
|
|
5
|
+
* This class is useful for creating mutable references to values,
|
|
6
|
+
* allowing for controlled access and modification.
|
|
7
|
+
*/
|
|
8
|
+
export class Ref extends EventEmitter {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @type {any}
|
|
12
|
+
* Private field to store the value.
|
|
13
|
+
*/
|
|
14
|
+
#value
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Constructor for the Ref class.
|
|
18
|
+
* If the provided value is an instance of Ref, it uses its value.
|
|
19
|
+
* Otherwise, it stores the provided value.
|
|
20
|
+
* @param {any} value - The value to store.
|
|
21
|
+
*/
|
|
22
|
+
constructor(value) {
|
|
23
|
+
super()
|
|
24
|
+
if (value instanceof Ref) {
|
|
25
|
+
this.#value = value.#value
|
|
26
|
+
} else {
|
|
27
|
+
this.#value = { value }
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Getter for the stored value.
|
|
33
|
+
* @returns {any} - The stored value.
|
|
34
|
+
*/
|
|
35
|
+
get value() {
|
|
36
|
+
return this.#value.value
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Setter for the stored value.
|
|
41
|
+
* @param {any} value - The new value.
|
|
42
|
+
*/
|
|
43
|
+
set value(value) {
|
|
44
|
+
const oldValue = this.#value.value
|
|
45
|
+
this.#value.value = value
|
|
46
|
+
// Emit an event if the value has changed
|
|
47
|
+
if (oldValue !== value) {
|
|
48
|
+
this.emit('update', value, oldValue)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @template T
|
|
55
|
+
* Creates a new Ref instance.
|
|
56
|
+
* @param {T} [value] - The value to store.
|
|
57
|
+
* @returns {Ref} - A new Ref instance.
|
|
58
|
+
*/
|
|
59
|
+
export const ref = (value) => {
|
|
60
|
+
return new Ref(value)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Checks if the value is an instance of Ref.
|
|
65
|
+
* @param {any} value - The value to check.
|
|
66
|
+
* @returns {boolean} - True if the value is an instance of Ref, otherwise false.
|
|
67
|
+
*/
|
|
68
|
+
export const isRef = (value) => {
|
|
69
|
+
return value instanceof Ref
|
|
70
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {httpClient} from "#lib/HttpClient";
|
|
2
|
+
import {checkIpV4Cidr} from "#src/utils/checkFunctions";
|
|
3
|
+
|
|
4
|
+
export const getCurrentIp = async () => {
|
|
5
|
+
const {data, error} = await httpClient.get(`/ip`);
|
|
6
|
+
|
|
7
|
+
if (error) {
|
|
8
|
+
console.error(error)
|
|
9
|
+
process.exit(1)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
return checkIpV4Cidr(data)
|
|
14
|
+
} catch {
|
|
15
|
+
console.log(`invalid ip v4 address "${data}"`)
|
|
16
|
+
process.exit(1)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {npmApiClient} from "#lib/HttpClient";
|
|
2
|
+
|
|
3
|
+
export const getLatestVersion = async () => {
|
|
4
|
+
|
|
5
|
+
await new Promise(resolve => setTimeout(resolve, 2000))
|
|
6
|
+
const {data, error} = await npmApiClient.get('/-/package/tunli/dist-tags')
|
|
7
|
+
|
|
8
|
+
if (error) {
|
|
9
|
+
return false
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return data.latest
|
|
13
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {securedHttpClient} from "#lib/HttpClient";
|
|
2
|
+
import {SERVER_HOST} from "#lib/defs";
|
|
3
|
+
|
|
4
|
+
export const requestNewProxyUrl = async (token) => {
|
|
5
|
+
|
|
6
|
+
const {data, error} = await securedHttpClient(token).get('/create');
|
|
7
|
+
|
|
8
|
+
if (error) {
|
|
9
|
+
console.error('Auth failed as server response error, status: ', error);
|
|
10
|
+
process.exit(1)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return `https://${data}.${SERVER_HOST}`
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const renewProxyUrlRegistration = async (proxyUrl, token) => {
|
|
17
|
+
|
|
18
|
+
const subDomain = new URL(proxyUrl).hostname.split('.', 1)[0]
|
|
19
|
+
|
|
20
|
+
const {data, error} = await securedHttpClient(token).get(`/renew/${subDomain}`);
|
|
21
|
+
|
|
22
|
+
if (data === false) {
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!data) {
|
|
27
|
+
console.error('Renew failed, request a new URL', error);
|
|
28
|
+
process.exit(1)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return proxyUrl
|
|
32
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {Command} from "commander";
|
|
2
|
+
import {Ref} from "#src/core/Ref";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {Ref} configRef
|
|
7
|
+
* @param {Command} cmd
|
|
8
|
+
*/
|
|
9
|
+
export const validateAuthToken = (cmd, configRef) => {
|
|
10
|
+
cmd.hook('preAction', (thisCommand, actionCommand) => {
|
|
11
|
+
|
|
12
|
+
/** @type {LocalConfig|GlobalConfig} */
|
|
13
|
+
const config = configRef.value
|
|
14
|
+
|
|
15
|
+
if (!config.authToken) {
|
|
16
|
+
actionCommand.error("error: Missing authToken. Please run register firstly");
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import {AUTH_SERVER_URL} from "#lib/defs";
|
|
3
|
+
|
|
4
|
+
const createClient = (options = {}) => {
|
|
5
|
+
|
|
6
|
+
const defaultOptions = {
|
|
7
|
+
baseURL: AUTH_SERVER_URL,
|
|
8
|
+
headers: {
|
|
9
|
+
'user-agent': 'tunli/1.0'
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const headers = {...defaultOptions.headers, ...options.headers ?? {}};
|
|
14
|
+
options = {...defaultOptions, ...options, headers};
|
|
15
|
+
|
|
16
|
+
const httpClient = axios.create(options)
|
|
17
|
+
httpClient.interceptors.response.use((response) => {
|
|
18
|
+
return {
|
|
19
|
+
data: response.data
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
(error) => {
|
|
23
|
+
if (error.code === 'ECONNREFUSED') {
|
|
24
|
+
console.error('Connection refused to', error.config.url);
|
|
25
|
+
}
|
|
26
|
+
const message = error.response?.data ? error.response?.data : null
|
|
27
|
+
return Promise.resolve({
|
|
28
|
+
error: message ?? {
|
|
29
|
+
code: error.code,
|
|
30
|
+
message: error.message
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return httpClient
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @type {AxiosInstance}
|
|
41
|
+
*/
|
|
42
|
+
export const httpClient = createClient();
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @type {AxiosInstance}
|
|
46
|
+
*/
|
|
47
|
+
export const npmApiClient = createClient({
|
|
48
|
+
baseURL: 'https://registry.npmjs.org/'
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {string} token - Der Authentifizierungs-Token.
|
|
53
|
+
* @returns {AxiosInstance} - Eine konfigurierte Axios-Instanz mit Authentifizierung.
|
|
54
|
+
*/
|
|
55
|
+
export const securedHttpClient = (token) => {
|
|
56
|
+
return createClient({
|
|
57
|
+
headers: {
|
|
58
|
+
authorization: `Bearer ${token}`,
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
}
|
package/src/lib/defs.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {resolve} from "path";
|
|
2
|
+
import {homedir} from "os";
|
|
3
|
+
|
|
4
|
+
export const SERVER_HOST = 'tunli.app'
|
|
5
|
+
export const CONFIG_DIR_NAME = '.tunli'
|
|
6
|
+
|
|
7
|
+
export const AUTH_SERVER_URL = 'https://api.tunli.app'
|
|
8
|
+
|
|
9
|
+
export const GLOBAL_CONFIG_DIR = resolve(homedir(), CONFIG_DIR_NAME);
|
|
10
|
+
export const CONFIG_FILENAME = 'default.json'
|
package/src/net/IPV4.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
export const ipV4 = (address) => {
|
|
2
|
+
|
|
3
|
+
if (address instanceof IPV4) {
|
|
4
|
+
return address
|
|
5
|
+
}
|
|
6
|
+
return new IPV4(address)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class IPV4 {
|
|
10
|
+
|
|
11
|
+
#ipv4Address
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @type {IPV4}
|
|
15
|
+
*/
|
|
16
|
+
#subnet
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @type {boolean}
|
|
20
|
+
*/
|
|
21
|
+
#isValid
|
|
22
|
+
|
|
23
|
+
constructor(ipv4Address) {
|
|
24
|
+
|
|
25
|
+
this._ipv4Address = this.#ipv4Address = this.#prepare(ipv4Address)
|
|
26
|
+
this.#isValid = this.#ipv4Address !== null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @returns {boolean}
|
|
31
|
+
*/
|
|
32
|
+
get isValid() {
|
|
33
|
+
return this.#isValid
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @return {number|null}
|
|
38
|
+
*/
|
|
39
|
+
get cidrSuffix() {
|
|
40
|
+
return this.#ipv4Address?.cidrSuffix ?? null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get subnetAddress() {
|
|
44
|
+
this.#subnet ??= this.#calculateSubnet()
|
|
45
|
+
return this.#subnet
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#calculateSubnet() {
|
|
49
|
+
|
|
50
|
+
const mask = ipV4(~((1 << (32 - this.cidrSuffix)) - 1) >>> 0)
|
|
51
|
+
const octets = []
|
|
52
|
+
|
|
53
|
+
for (let i = 0; i < 4; i++) {
|
|
54
|
+
const maskPart = mask.#ipv4Address.octetsAsIntegers[i]
|
|
55
|
+
const ipPart = this.#ipv4Address.octetsAsIntegers[i]
|
|
56
|
+
octets.push(maskPart & ipPart)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return ipV4(octets.join('.'))
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
#prepare(ipv4Address) {
|
|
63
|
+
|
|
64
|
+
const typeOfAddress = typeof ipv4Address
|
|
65
|
+
let octets = []
|
|
66
|
+
let octetsAsIntegers = []
|
|
67
|
+
let octetsAsBinaryString = []
|
|
68
|
+
let ipv4AddressAsInt;
|
|
69
|
+
let ipv4AddressAsString;
|
|
70
|
+
let cidrSuffix = 32;
|
|
71
|
+
|
|
72
|
+
if (typeOfAddress === 'number') {
|
|
73
|
+
ipv4AddressAsInt = ipv4Address
|
|
74
|
+
const binaryRepresentation = ipv4Address.toString(2)
|
|
75
|
+
const chunkSize = 8
|
|
76
|
+
for (let i = binaryRepresentation.length; i > 0; i -= chunkSize) {
|
|
77
|
+
const octetAsBin = binaryRepresentation.substring(i - chunkSize, i).padStart(8, '0')
|
|
78
|
+
const octetAsInt = parseInt(octetAsBin, 2)
|
|
79
|
+
|
|
80
|
+
octetsAsBinaryString.unshift(octetAsBin);
|
|
81
|
+
octetsAsIntegers.unshift(octetAsInt);
|
|
82
|
+
octets.unshift(octetAsInt.toString());
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
ipv4AddressAsString = octets.join('.')
|
|
86
|
+
} else if (typeOfAddress === 'string') {
|
|
87
|
+
|
|
88
|
+
const parts = ipv4Address.split('/')
|
|
89
|
+
if (parts.length > 2) {
|
|
90
|
+
return null
|
|
91
|
+
} else if (parts.length === 2) {
|
|
92
|
+
cidrSuffix = parseInt(parts[1])
|
|
93
|
+
if (isNaN(cidrSuffix)) {
|
|
94
|
+
return null
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
octetsAsIntegers = parts[0].split('.').map(Number)
|
|
99
|
+
octets = octetsAsIntegers.map(x => x.toString())
|
|
100
|
+
ipv4AddressAsString = octets.join('.')
|
|
101
|
+
octetsAsBinaryString = octetsAsIntegers.map(x => x.toString(2).padStart(8, '0'))
|
|
102
|
+
} else {
|
|
103
|
+
return null
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (octetsAsIntegers.filter(x => x <= 255).length !== 4) {
|
|
107
|
+
return null
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
asString: ipv4AddressAsString,
|
|
112
|
+
octets,
|
|
113
|
+
octetsAsIntegers,
|
|
114
|
+
octetsAsBinaryString,
|
|
115
|
+
asInt: ipv4AddressAsInt,
|
|
116
|
+
cidrSuffix
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
isInSubnet(subnet) {
|
|
121
|
+
subnet = ipV4(subnet)
|
|
122
|
+
const mask = ~((1 << (32 - subnet.cidrSuffix)) - 1) >>> 0;
|
|
123
|
+
return (this.toInteger() & mask) === (subnet.toInteger() & mask)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
toString() {
|
|
127
|
+
return this.#ipv4Address?.asString ?? null
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
toInteger() {
|
|
131
|
+
if (!this.#ipv4Address) {
|
|
132
|
+
return null
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
this.#ipv4Address.asInt ??= parseInt(this.#ipv4Address.octetsAsBinaryString.join(''), 2)
|
|
136
|
+
return this.#ipv4Address.asInt
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {ServerResponse} from "#src/net/http/ServerResponse"
|
|
2
|
+
import {Socket} from "socket.io-client"
|
|
3
|
+
import {getRemoteAddress} from "#src/utils/httpFunction"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* IncomingMessage class represents an HTTP request received by the server.
|
|
7
|
+
*/
|
|
8
|
+
export class IncomingMessage {
|
|
9
|
+
/**
|
|
10
|
+
* @type {ServerResponse}
|
|
11
|
+
* @private
|
|
12
|
+
*/
|
|
13
|
+
#res
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @type {string}
|
|
17
|
+
* @private
|
|
18
|
+
*/
|
|
19
|
+
#id
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @type {Socket}
|
|
23
|
+
* @private
|
|
24
|
+
*/
|
|
25
|
+
#socket
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @type {string}
|
|
29
|
+
* @private
|
|
30
|
+
*/
|
|
31
|
+
#remoteAddress
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @type {string}
|
|
35
|
+
* @private
|
|
36
|
+
*/
|
|
37
|
+
#url
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Creates an instance of IncomingMessage.
|
|
41
|
+
* @param {SocketIoRawRequestObject} request - The raw request object.
|
|
42
|
+
* @param {string} requestId - The unique request identifier.
|
|
43
|
+
* @param {Socket} socket - The socket to communicate over.
|
|
44
|
+
*/
|
|
45
|
+
constructor(request, requestId, socket) {
|
|
46
|
+
this.#url = request.path
|
|
47
|
+
this.#id = requestId
|
|
48
|
+
this.#socket = socket
|
|
49
|
+
this.#remoteAddress = getRemoteAddress(request)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Returns the URL path.
|
|
54
|
+
* @return {string}
|
|
55
|
+
*/
|
|
56
|
+
get url() {
|
|
57
|
+
return this.#url
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Returns the remote address.
|
|
62
|
+
* @return {string}
|
|
63
|
+
*/
|
|
64
|
+
get remoteAddress() {
|
|
65
|
+
return this.#remoteAddress
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns the unique request identifier.
|
|
70
|
+
* @return {string}
|
|
71
|
+
*/
|
|
72
|
+
get id() {
|
|
73
|
+
return this.#id
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Returns the socket associated with the request.
|
|
78
|
+
* @return {Socket}
|
|
79
|
+
*/
|
|
80
|
+
get socket() {
|
|
81
|
+
return this.#socket
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Returns the ServerResponse instance, creating it if necessary.
|
|
86
|
+
* @return {ServerResponse}
|
|
87
|
+
*/
|
|
88
|
+
get res() {
|
|
89
|
+
this.#res ??= new ServerResponse(this)
|
|
90
|
+
return this.#res
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import {IncomingMessage} from "#src/net/http/IncomingMessage"
|
|
2
|
+
import {TunnelResponse} from "#src/net/http/TunnelResponse"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ServerResponse class represents an HTTP response to be sent back to the client.
|
|
6
|
+
*/
|
|
7
|
+
export class ServerResponse {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @type {IncomingMessage}
|
|
11
|
+
* @private
|
|
12
|
+
*/
|
|
13
|
+
#req
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @type {Object}
|
|
17
|
+
* @private
|
|
18
|
+
*/
|
|
19
|
+
#headers = {}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @type {string}
|
|
23
|
+
* @private
|
|
24
|
+
*/
|
|
25
|
+
#httpVersion = '1.1'
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @type {TunnelResponse}
|
|
29
|
+
* @private
|
|
30
|
+
*/
|
|
31
|
+
#res
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @type {string}
|
|
35
|
+
* @private
|
|
36
|
+
*/
|
|
37
|
+
#statusMessage = 'OK'
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @type {number}
|
|
41
|
+
* @private
|
|
42
|
+
*/
|
|
43
|
+
#statusCode = 200
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Creates an instance of ServerResponse.
|
|
47
|
+
* @param {IncomingMessage} incomingMessage - The incoming message object.
|
|
48
|
+
*/
|
|
49
|
+
constructor(incomingMessage) {
|
|
50
|
+
this.#req = incomingMessage
|
|
51
|
+
this.#res = new TunnelResponse({
|
|
52
|
+
responseId: incomingMessage.id,
|
|
53
|
+
socket: incomingMessage.socket,
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns the associated IncomingMessage instance.
|
|
59
|
+
* @return {IncomingMessage}
|
|
60
|
+
*/
|
|
61
|
+
get req() {
|
|
62
|
+
return this.#req
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Sets the status code and message.
|
|
67
|
+
* @param {number} statusCode - The HTTP status code.
|
|
68
|
+
* @param {string} [statusMessage] - The HTTP status message.
|
|
69
|
+
* @return {ServerResponse}
|
|
70
|
+
*/
|
|
71
|
+
status(statusCode, statusMessage) {
|
|
72
|
+
this.#statusMessage = statusMessage ?? {
|
|
73
|
+
200: 'OK',
|
|
74
|
+
201: 'Created',
|
|
75
|
+
202: 'Accepted',
|
|
76
|
+
204: 'No Content',
|
|
77
|
+
301: 'Moved Permanently',
|
|
78
|
+
302: 'Found',
|
|
79
|
+
304: 'Not Modified',
|
|
80
|
+
400: 'Bad Request',
|
|
81
|
+
401: 'Unauthorized',
|
|
82
|
+
403: 'Forbidden',
|
|
83
|
+
404: 'Not Found',
|
|
84
|
+
405: 'Method Not Allowed',
|
|
85
|
+
500: 'Internal Server Error',
|
|
86
|
+
501: 'Not Implemented',
|
|
87
|
+
502: 'Bad Gateway',
|
|
88
|
+
503: 'Service Unavailable',
|
|
89
|
+
504: 'Gateway Timeout'
|
|
90
|
+
}[statusCode] ?? 'Unknown Status'
|
|
91
|
+
this.#statusCode = statusCode
|
|
92
|
+
return this
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Sends the response with the provided body.
|
|
97
|
+
* @param {string|Buffer} body - The body of the response.
|
|
98
|
+
* @return {ServerResponse}
|
|
99
|
+
*/
|
|
100
|
+
send(body) {
|
|
101
|
+
this.#res.writeHead(this.#statusCode, this.#statusMessage, this.#headers, this.#httpVersion)
|
|
102
|
+
this.#res.write(body)
|
|
103
|
+
this.#res.end()
|
|
104
|
+
return this
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Sets the headers for the response.
|
|
109
|
+
* @param {Object} headers - The headers to set.
|
|
110
|
+
* @return {ServerResponse}
|
|
111
|
+
*/
|
|
112
|
+
headers(headers) {
|
|
113
|
+
this.#headers = headers
|
|
114
|
+
return this
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Sets the HTTP version for the response.
|
|
119
|
+
* @param {string} httpVersion - The HTTP version to set.
|
|
120
|
+
* @return {ServerResponse}
|
|
121
|
+
*/
|
|
122
|
+
httpVersion(httpVersion) {
|
|
123
|
+
this.#httpVersion = httpVersion
|
|
124
|
+
return this
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export class TunliRequest {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export class TunliResponse {}
|