-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathpreview_server_main.js
More file actions
109 lines (85 loc) · 2.31 KB
/
Copy pathpreview_server_main.js
File metadata and controls
109 lines (85 loc) · 2.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
const express = require("express");
const net = require("net");
const path = require("path");
const PREVIEW_HOST = "127.0.0.1";
const MIN_PORT = 40000;
const MAX_PORT = 65000;
const MAX_ATTEMPTS = 100;
let previewPort = null;
let staticServer = null;
let currentRootDir = null;
function randomPort() {
return Math.floor(Math.random() * (MAX_PORT - MIN_PORT + 1)) + MIN_PORT;
}
function canListenOnPort(port) {
return new Promise((resolve) => {
const tester = net.createServer();
tester.once("error", () => {
resolve(false);
});
tester.once("listening", () => {
tester.close(() => resolve(true));
});
tester.listen(port, PREVIEW_HOST);
});
}
async function initPreviewPort() {
if (previewPort !== null) {
return previewPort;
}
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt += 1) {
const candidatePort = randomPort();
if (await canListenOnPort(candidatePort)) {
previewPort = candidatePort;
return previewPort;
}
}
throw new Error("Unable to find an available preview port.");
}
function getPreviewServerInfo() {
return {
host: PREVIEW_HOST,
port: previewPort,
rootDir: currentRootDir,
url: previewPort === null ? null : `http://${PREVIEW_HOST}:${previewPort}`,
};
}
function closeStaticServer() {
if (staticServer === null) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
staticServer.close((error) => {
if (error) {
reject(error);
return;
}
staticServer = null;
resolve();
});
});
}
function listenStaticServer(serverApp, port) {
return new Promise((resolve, reject) => {
const server = serverApp.listen(port, PREVIEW_HOST, () => resolve(server));
server.once("error", reject);
});
}
async function serveDirectory(rootDir) {
const resolvedRootDir = path.resolve(rootDir);
await initPreviewPort();
if (staticServer !== null && currentRootDir === resolvedRootDir) {
return getPreviewServerInfo();
}
await closeStaticServer();
const serverApp = express();
serverApp.use(express.static(resolvedRootDir));
staticServer = await listenStaticServer(serverApp, previewPort);
currentRootDir = resolvedRootDir;
return getPreviewServerInfo();
}
module.exports = {
getPreviewServerInfo,
initPreviewPort,
serveDirectory,
};