unplugin-https-reverse-proxy 1.0.0-beta.9 → 2.0.0
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/README.md +17 -3
- package/dist/chunk-2P7SUCQ3.js +63 -0
- package/dist/{chunk-ZSHTX2B6.js → chunk-SO2FMQ2Q.js} +324 -135
- package/dist/esbuild.cjs +352 -160
- package/dist/esbuild.js +2 -2
- package/dist/index.cjs +352 -160
- package/dist/index.js +2 -2
- package/dist/nuxt.cjs +325 -142
- package/dist/nuxt.d.cts +1 -1
- package/dist/nuxt.d.ts +1 -1
- package/dist/nuxt.js +7 -7
- package/dist/rollup.cjs +352 -160
- package/dist/rollup.js +2 -2
- package/dist/rspack.cjs +352 -160
- package/dist/rspack.js +2 -2
- package/dist/types.cjs +1 -1
- package/dist/utils.cjs +26 -6
- package/dist/utils.d.cts +6 -4
- package/dist/utils.d.ts +6 -4
- package/dist/utils.js +5 -1
- package/dist/vite.cjs +352 -160
- package/dist/vite.d.cts +2 -1
- package/dist/vite.d.ts +2 -1
- package/dist/vite.js +2 -2
- package/dist/webpack.cjs +352 -160
- package/dist/webpack.js +2 -2
- package/package.json +38 -32
- package/scripts/postinstall.cjs +314 -0
- package/src/caddy/constants.ts +3 -2
- package/src/caddy/index.ts +254 -102
- package/src/caddy/utils.ts +24 -6
- package/src/host/index.ts +18 -23
- package/src/index.ts +68 -25
- package/src/nuxt.ts +10 -8
- package/src/utils.ts +33 -6
- package/dist/chunk-RUJE3YFB.js +0 -63
- package/scripts/postinstall.ts +0 -19
package/src/caddy/index.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
|
+
import { chmodSync, createWriteStream, existsSync, mkdirSync, unlinkSync, writeFileSync } from 'node:fs'
|
|
3
|
+
import { readFile, unlink, writeFile } from 'node:fs/promises'
|
|
1
4
|
import { platform } from 'node:os'
|
|
5
|
+
import { join } from 'node:path'
|
|
2
6
|
import process from 'node:process'
|
|
3
|
-
import { chmodSync, createWriteStream, existsSync, mkdirSync, unlinkSync } from 'node:fs'
|
|
4
|
-
import { spawn } from 'node:child_process'
|
|
5
7
|
import { got } from 'got-cjs'
|
|
6
8
|
import { HttpProxyAgent } from 'http-proxy-agent'
|
|
7
9
|
import { HttpsProxyAgent } from 'https-proxy-agent'
|
|
8
|
-
import
|
|
9
|
-
import { chmodRecursive, consola, once } from '../utils'
|
|
10
|
+
import * as lockfile from 'proper-lockfile'
|
|
10
11
|
import { addHost, removeHost } from '../host'
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
12
|
+
import { chmodRecursive, consola, once } from '../utils'
|
|
13
|
+
import { caddyFilePath, caddyLockFilePath, caddyPath, supportList, TEMP_DIR } from './constants'
|
|
14
|
+
import { kill, logProgress, logProgressOver, tryPort } from './utils'
|
|
13
15
|
|
|
14
|
-
export async function download() {
|
|
16
|
+
export async function download(): Promise<string> {
|
|
15
17
|
if (await testCaddy())
|
|
16
18
|
return caddyPath
|
|
17
19
|
|
|
@@ -37,7 +39,7 @@ export async function download() {
|
|
|
37
39
|
if (!support)
|
|
38
40
|
return reject(new Error('not support'))
|
|
39
41
|
|
|
40
|
-
const dowmloadLink = `https://caddyserver.com/api/download?os=${support.platform}&arch=${support.arch}`
|
|
42
|
+
const dowmloadLink = `https://caddyserver.com/api/download?os=${support.platform}&arch=${support.arch}&p=github.com%2Fcaddyserver%2Fforwardproxy`
|
|
41
43
|
|
|
42
44
|
existsSync(caddyPath) && unlinkSync(caddyPath)
|
|
43
45
|
|
|
@@ -74,7 +76,7 @@ export async function download() {
|
|
|
74
76
|
})
|
|
75
77
|
}
|
|
76
78
|
|
|
77
|
-
function testCaddy() {
|
|
79
|
+
function testCaddy(): Promise<boolean> {
|
|
78
80
|
return new Promise((resolve, reject) => {
|
|
79
81
|
if (!existsSync(caddyPath))
|
|
80
82
|
return resolve(false)
|
|
@@ -103,13 +105,82 @@ export class CaddyInstant {
|
|
|
103
105
|
private inited = false
|
|
104
106
|
private stoped = false
|
|
105
107
|
|
|
108
|
+
/** has locked */
|
|
109
|
+
private locked = false
|
|
110
|
+
private caddyfile: string | undefined
|
|
111
|
+
|
|
112
|
+
private _caddyChild: ReturnType<typeof spawn> | undefined
|
|
113
|
+
|
|
114
|
+
private _source: string | undefined
|
|
115
|
+
private _target: string | undefined
|
|
116
|
+
|
|
106
117
|
constructor() {
|
|
107
|
-
testCaddy().then(() => {
|
|
118
|
+
testCaddy().then(async () => {
|
|
119
|
+
await this.getCaddyfile()
|
|
120
|
+
|
|
108
121
|
this.inited = true
|
|
109
122
|
})
|
|
123
|
+
|
|
124
|
+
this.locked = this.checkLock()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
checkLock(): boolean {
|
|
128
|
+
if (!existsSync(caddyLockFilePath))
|
|
129
|
+
writeFileSync(caddyLockFilePath, '')
|
|
130
|
+
return lockfile.checkSync(caddyLockFilePath)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async getCaddyfile(): Promise<string> {
|
|
134
|
+
if (!existsSync(caddyFilePath))
|
|
135
|
+
await this.initCaddyfile()
|
|
136
|
+
|
|
137
|
+
this.caddyfile = await readFile(caddyFilePath, 'utf-8')
|
|
138
|
+
return this.caddyfile
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async initCaddyfile(): Promise<void> {
|
|
142
|
+
const contet = `
|
|
143
|
+
{
|
|
144
|
+
debug
|
|
145
|
+
auto_https disable_redirects
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
:7601 {
|
|
149
|
+
root * "${join(
|
|
150
|
+
process.platform === 'win32'
|
|
151
|
+
? `${process.env.AppData!}/Caddy`
|
|
152
|
+
: `${process.env.HOME!}/Library/Application Support/Caddy`,
|
|
153
|
+
'./pki/authorities/local',
|
|
154
|
+
)}"
|
|
155
|
+
file_server browse
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# 正向代理配置
|
|
159
|
+
:7600 {
|
|
160
|
+
bind 0.0.0.0
|
|
161
|
+
|
|
162
|
+
forward_proxy {
|
|
163
|
+
hide_ip
|
|
164
|
+
hide_via
|
|
165
|
+
acl {
|
|
166
|
+
allow all
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
`
|
|
171
|
+
await writeFile(caddyFilePath, contet)
|
|
172
|
+
this.caddyfile = contet
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async writeCaddyfile(): Promise<void> {
|
|
176
|
+
return await writeFile(caddyFilePath, this.caddyfile || '')
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async deleteCaddyfile(): Promise<void> {
|
|
180
|
+
return await unlink(caddyFilePath)
|
|
110
181
|
}
|
|
111
182
|
|
|
112
|
-
async init() {
|
|
183
|
+
async init(): Promise<void> {
|
|
113
184
|
await download()
|
|
114
185
|
this.inited = true
|
|
115
186
|
}
|
|
@@ -117,9 +188,8 @@ export class CaddyInstant {
|
|
|
117
188
|
/**
|
|
118
189
|
* @param source like `127.0.0.1:8080`
|
|
119
190
|
* @param target like `test.abc.com`. And if you provide a port ,it will be ignore.
|
|
120
|
-
* @returns
|
|
121
191
|
*/
|
|
122
|
-
async run(source: string, target: string, options?: Partial<RunOptions>) {
|
|
192
|
+
async run(source: string, target: string, options?: Partial<RunOptions>): Promise<void> {
|
|
123
193
|
source = source.replace('0.0.0.0', '127.0.0.1')
|
|
124
194
|
const {
|
|
125
195
|
restore = true,
|
|
@@ -128,111 +198,193 @@ export class CaddyInstant {
|
|
|
128
198
|
https = false,
|
|
129
199
|
} = options || {}
|
|
130
200
|
|
|
201
|
+
this._source = source
|
|
202
|
+
this._target = target
|
|
203
|
+
|
|
131
204
|
if (!this.inited)
|
|
132
205
|
await this.init()
|
|
133
206
|
|
|
134
|
-
if (https && await tryPort(443))
|
|
135
|
-
await kill(443, 'tcp')
|
|
136
|
-
if ((process.platform === 'win32' || !https) && await tryPort(80))
|
|
137
|
-
await kill(80, 'tcp')
|
|
138
|
-
|
|
139
207
|
if (!await addHost(source.split(':')[0], target.split(':')[0]))
|
|
140
208
|
throw new Error('update host failed')
|
|
141
209
|
consola.success('update host success\n')
|
|
142
210
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
211
|
+
await this.getCaddyfile()
|
|
212
|
+
if (!(this.caddyfile || '').includes(`${target.split(':')[0]}${https ? '' : ':80'}`)) {
|
|
213
|
+
this.caddyfile = `${this.caddyfile}
|
|
214
|
+
${target.split(':')[0]}${https ? '' : ':80'} {
|
|
215
|
+
${https ? 'tls internal' : ''}
|
|
216
|
+
reverse_proxy http://${source} {
|
|
217
|
+
health_uri ${base}
|
|
218
|
+
health_interval 2s
|
|
219
|
+
health_timeout 5s
|
|
220
|
+
fail_duration 2s
|
|
221
|
+
unhealthy_status 502 503 504 404
|
|
222
|
+
lb_try_duration 3s
|
|
223
|
+
lb_try_interval 300ms
|
|
224
|
+
health_headers {
|
|
225
|
+
Accept text/html
|
|
226
|
+
Accept-Encoding gzip, deflate, br
|
|
227
|
+
User-Agent Caddy-Health-Check
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
@error status 502 503 504 404
|
|
231
|
+
handle_response @error {
|
|
232
|
+
respond * 503 {
|
|
233
|
+
body "Service Unavailable"
|
|
234
|
+
close
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
`
|
|
148
240
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
241
|
+
await this.writeCaddyfile()
|
|
242
|
+
}
|
|
243
|
+
if (!existsSync(caddyLockFilePath))
|
|
244
|
+
writeFileSync(caddyLockFilePath, '')
|
|
245
|
+
|
|
246
|
+
if (!this.locked) {
|
|
247
|
+
if (await tryPort(443))
|
|
248
|
+
await kill(443)
|
|
249
|
+
if ((process.platform === 'win32' || !https) && await tryPort(80))
|
|
250
|
+
await kill(80)
|
|
251
|
+
}
|
|
152
252
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
253
|
+
return new Promise<void>((resolve, reject) => {
|
|
254
|
+
const setupCleanup = (): void => {
|
|
255
|
+
process.on('SIGINT', async () => {
|
|
256
|
+
if (this.stoped)
|
|
257
|
+
return
|
|
156
258
|
|
|
157
|
-
|
|
158
|
-
if (await removeHost(source.split(':')[0], target.split(':')[0]))
|
|
159
|
-
consola.success('restore host success\n')
|
|
259
|
+
process.stdin.resume()
|
|
160
260
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
consola.error(e)
|
|
208
|
-
consola.fail('restore host failed\n')
|
|
209
|
-
}
|
|
210
|
-
finally {
|
|
211
|
-
this.stoped = true
|
|
212
|
-
process.nextTick(() => {
|
|
213
|
-
originalExit(code)
|
|
214
|
-
})
|
|
261
|
+
try {
|
|
262
|
+
await this.baseCleanup(restore)
|
|
263
|
+
}
|
|
264
|
+
finally {
|
|
265
|
+
this.stoped = true
|
|
266
|
+
process.nextTick(() => {
|
|
267
|
+
process.exit()
|
|
268
|
+
})
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
const originalExit = process.exit.bind(process)
|
|
273
|
+
|
|
274
|
+
// @ts-expect-error override
|
|
275
|
+
process.exit = async (code?: number) => {
|
|
276
|
+
const port = Number(source.split(':')[1])
|
|
277
|
+
if (!Number.isNaN(port) && await tryPort(port))
|
|
278
|
+
await kill(port)
|
|
279
|
+
|
|
280
|
+
// fix `Error: EPERM: operation not permitted`
|
|
281
|
+
const pwd = process.cwd()
|
|
282
|
+
const viteCacheDir = `${pwd}/node_modules/.vite`
|
|
283
|
+
if (existsSync(viteCacheDir))
|
|
284
|
+
await chmodRecursive(viteCacheDir, 0o777).catch(() => { })
|
|
285
|
+
const nuxtCacheDir = `${pwd}/.nuxt`
|
|
286
|
+
if (existsSync(nuxtCacheDir))
|
|
287
|
+
await chmodRecursive(nuxtCacheDir, 0o777).catch(() => { })
|
|
288
|
+
const webpackCacheDir = `${pwd}/node_modules/.cache`
|
|
289
|
+
if (existsSync(webpackCacheDir))
|
|
290
|
+
await chmodRecursive(webpackCacheDir, 0o777).catch(() => { })
|
|
291
|
+
|
|
292
|
+
if (this.stoped)
|
|
293
|
+
return originalExit(code)
|
|
294
|
+
|
|
295
|
+
process.stdin.resume()
|
|
296
|
+
|
|
297
|
+
try {
|
|
298
|
+
await this.baseCleanup()
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
finally {
|
|
302
|
+
this.stoped = true
|
|
303
|
+
process.nextTick(() => {
|
|
304
|
+
originalExit(code)
|
|
305
|
+
})
|
|
306
|
+
}
|
|
215
307
|
}
|
|
216
308
|
}
|
|
217
309
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
310
|
+
if (!this.locked) {
|
|
311
|
+
this._caddyChild = process.platform !== 'win32'
|
|
312
|
+
? spawn('sudo', ['-E', caddyPath, 'run', '--config', caddyFilePath, '--watch'])
|
|
313
|
+
: spawn(caddyPath, ['run', '--config', caddyFilePath, '--watch'])
|
|
314
|
+
|
|
315
|
+
lockfile.lockSync(caddyLockFilePath)
|
|
316
|
+
|
|
317
|
+
this._caddyChild!.on('error', (err) => {
|
|
318
|
+
return reject(err)
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
this._caddyChild!.stderr?.on('data', async (data) => {
|
|
322
|
+
const lines = (data.toString() as string).split('\n').map(line => line.trim())
|
|
323
|
+
for (const line of lines) {
|
|
324
|
+
// caddy log
|
|
325
|
+
// eslint-disable-next-line no-console
|
|
326
|
+
showCaddyLog && line && console.info(line)
|
|
327
|
+
if (line.includes('Error:') || (line && JSON.parse(line).level === 'error')) {
|
|
328
|
+
if (line.includes('parsing caddyfile tokens')) {
|
|
329
|
+
consola.error('Caddyfile syntax error, please contact the author:\n', `${this.caddyfile}\n\n${line}\n`)
|
|
330
|
+
await this.baseCleanup()
|
|
331
|
+
process.exit()
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
consola.error(`${line}\n`)
|
|
335
|
+
// child.kill()
|
|
336
|
+
return reject(line)
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (line.includes('config file changed'))
|
|
340
|
+
consola.success('Detect added a new reverse proxy config, restarted.\n')
|
|
341
|
+
|
|
342
|
+
if (line.includes('caddy proxying') || line.includes('serving initial'))
|
|
343
|
+
return resolve()
|
|
228
344
|
}
|
|
229
|
-
}
|
|
230
|
-
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
this._caddyChild!.stdout?.on('data', (_data) => {
|
|
348
|
+
consola.info(_data.toString())
|
|
349
|
+
resolve()
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
setupCleanup()
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
consola.info('Caddy is running in another process.')
|
|
356
|
+
|
|
357
|
+
setupCleanup()
|
|
231
358
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
resolve()
|
|
235
|
-
})
|
|
359
|
+
return resolve()
|
|
360
|
+
}
|
|
236
361
|
})
|
|
237
362
|
}
|
|
363
|
+
|
|
364
|
+
async baseCleanup(restore: boolean = true): Promise<void> {
|
|
365
|
+
try {
|
|
366
|
+
if (restore && this._source && this._target) {
|
|
367
|
+
if (await removeHost(this._source.split(':')[0], this._target.split(':')[0]))
|
|
368
|
+
consola.success('Restore host success.\n')
|
|
369
|
+
|
|
370
|
+
else
|
|
371
|
+
consola.fail('Restore host failed.\n')
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
catch (e) {
|
|
375
|
+
consola.error(e)
|
|
376
|
+
consola.fail('Restore host failed.\n')
|
|
377
|
+
}
|
|
378
|
+
if (!this.locked && !this.stoped) {
|
|
379
|
+
this._caddyChild?.kill()
|
|
380
|
+
try {
|
|
381
|
+
await lockfile.unlock(caddyLockFilePath).catch(() => { })
|
|
382
|
+
await unlink(caddyFilePath).catch(() => { })
|
|
383
|
+
await unlink(caddyLockFilePath).catch(() => { })
|
|
384
|
+
}
|
|
385
|
+
catch (e) {
|
|
386
|
+
consola.error(e)
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
238
390
|
}
|
package/src/caddy/utils.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { exec } from 'node:child_process'
|
|
1
2
|
import { createServer } from 'node:net'
|
|
2
3
|
import ora from 'ora'
|
|
3
4
|
import { consola } from '../utils'
|
|
@@ -7,8 +8,8 @@ let spinner: ora.Ora
|
|
|
7
8
|
/**
|
|
8
9
|
* @returns whether the port is in use
|
|
9
10
|
*/
|
|
10
|
-
export function tryPort(port: number) {
|
|
11
|
-
return new Promise<boolean>((resolve,
|
|
11
|
+
export function tryPort(port: number): Promise<boolean> {
|
|
12
|
+
return new Promise<boolean>((resolve, _reject) => {
|
|
12
13
|
try {
|
|
13
14
|
const server = createServer().listen(port)
|
|
14
15
|
server.on('listening', () => {
|
|
@@ -22,13 +23,30 @@ export function tryPort(port: number) {
|
|
|
22
23
|
server.close()
|
|
23
24
|
})
|
|
24
25
|
}
|
|
25
|
-
catch
|
|
26
|
+
catch {
|
|
26
27
|
resolve(true)
|
|
27
28
|
}
|
|
28
29
|
})
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
/**
|
|
33
|
+
* npx free-port :port
|
|
34
|
+
*/
|
|
35
|
+
export async function kill(port: number): Promise<void> {
|
|
36
|
+
return new Promise<void>((resolve, reject) => {
|
|
37
|
+
exec(`npx @maxbo/free-port ${port} -s`, (err, stdout, _stderr) => {
|
|
38
|
+
if (err) {
|
|
39
|
+
reject(err)
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
consola.log(stdout)
|
|
43
|
+
resolve()
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getNumber(number: number): string {
|
|
32
50
|
if (number <= 0)
|
|
33
51
|
return '0%'
|
|
34
52
|
else if (number < 100)
|
|
@@ -37,7 +55,7 @@ function getNumber(number: number) {
|
|
|
37
55
|
return '100%'
|
|
38
56
|
}
|
|
39
57
|
|
|
40
|
-
export function logProgress(percent: number | string) {
|
|
58
|
+
export function logProgress(percent: number | string): void {
|
|
41
59
|
if (!spinner) {
|
|
42
60
|
// empty a line before start
|
|
43
61
|
consola.log('')
|
|
@@ -50,7 +68,7 @@ export function logProgress(percent: number | string) {
|
|
|
50
68
|
else { spinner.text = `Download Caddy: ${getNumber(Number(percent) * 100)}` }
|
|
51
69
|
}
|
|
52
70
|
|
|
53
|
-
export function logProgressOver() {
|
|
71
|
+
export function logProgressOver(): void {
|
|
54
72
|
if (!spinner) {
|
|
55
73
|
spinner = ora({
|
|
56
74
|
text: 'Start Download Caddy: 100%',
|
package/src/host/index.ts
CHANGED
|
@@ -1,57 +1,52 @@
|
|
|
1
|
-
import process from 'node:process'
|
|
2
1
|
import { exec } from 'node:child_process'
|
|
3
2
|
import { chmodSync } from 'node:fs'
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
import { promisify } from 'node:util'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
import _Hosts from 'hosts-so-easy'
|
|
6
|
+
import hostile from 'hostile'
|
|
7
7
|
import { consola } from '../utils'
|
|
8
8
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const hostInstance = new Hosts({
|
|
12
|
-
debounceTime: 50,
|
|
13
|
-
hostsFile: getPathOfSystemHostsPath(),
|
|
14
|
-
})
|
|
9
|
+
const _setHost = promisify(hostile.set)
|
|
10
|
+
const _removeHost = promisify(hostile.remove)
|
|
15
11
|
|
|
16
|
-
function getPathOfSystemHostsPath() {
|
|
12
|
+
function getPathOfSystemHostsPath(): string {
|
|
17
13
|
return process.platform === 'win32'
|
|
18
14
|
? `${process.env.windir || 'C:\\WINDOWS'}\\system32\\drivers\\etc\\hosts`
|
|
19
15
|
: '/etc/hosts'
|
|
20
16
|
}
|
|
21
17
|
|
|
22
|
-
async function syncHost() {
|
|
23
|
-
return new Promise<boolean>((resolve,
|
|
18
|
+
async function syncHost(): Promise<boolean> {
|
|
19
|
+
return new Promise<boolean>((resolve, _reject) => {
|
|
24
20
|
exec(
|
|
25
21
|
process.platform === 'win32'
|
|
26
22
|
? 'ipconfig /flushdns'
|
|
27
23
|
: 'sudo -E killall -HUP mDNSResponder',
|
|
28
|
-
(error,
|
|
24
|
+
(error, _stdout, _stderr) => {
|
|
29
25
|
if (error) {
|
|
30
26
|
consola.error(`exec error: ${error}`)
|
|
31
27
|
return resolve(false)
|
|
32
28
|
}
|
|
33
29
|
return resolve(true)
|
|
34
|
-
}
|
|
30
|
+
},
|
|
31
|
+
)
|
|
35
32
|
})
|
|
36
33
|
}
|
|
37
34
|
|
|
38
|
-
export async function addHost(ip: string, host: string) {
|
|
35
|
+
export async function addHost(ip: string, host: string): Promise<boolean> {
|
|
39
36
|
if (process.platform !== 'win32')
|
|
40
37
|
chmodSync(getPathOfSystemHostsPath(), 0o777)
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
await _setHost('127.0.0.1', 'localhost')
|
|
39
|
+
await _setHost(ip, host)
|
|
43
40
|
if (ip === 'localhost')
|
|
44
|
-
|
|
45
|
-
await hostInstance.updateFinish()
|
|
41
|
+
await _setHost('127.0.0.1', host)
|
|
46
42
|
return await syncHost()
|
|
47
43
|
}
|
|
48
44
|
|
|
49
|
-
export async function removeHost(ip: string, host: string) {
|
|
45
|
+
export async function removeHost(ip: string, host: string): Promise<boolean> {
|
|
50
46
|
if (process.platform !== 'win32')
|
|
51
47
|
chmodSync(getPathOfSystemHostsPath(), 0o777)
|
|
52
|
-
|
|
48
|
+
await _removeHost(ip, host)
|
|
53
49
|
if (ip === 'localhost')
|
|
54
|
-
|
|
55
|
-
await hostInstance.updateFinish()
|
|
50
|
+
await _removeHost('127.0.0.1', host)
|
|
56
51
|
return await syncHost()
|
|
57
52
|
}
|