1 | #!/usr/bin/env node
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | import express from "express";
|
13 | import expressHBS from "express-handlebars";
|
14 | import chalk from "chalk";
|
15 | import fs from "fs";
|
16 | import path from "path";
|
17 | import os from "os";
|
18 | import program from "commander";
|
19 | import mimetype from "mimetype";
|
20 | import humanSize from "human-size";
|
21 | import moment from "moment";
|
22 | import opn from "opn";
|
23 |
|
24 | let pkg = require("../package.json"),
|
25 | server = express(),
|
26 | sServerRoot = process.cwd(),
|
27 | iPort;
|
28 |
|
29 | program
|
30 | .version(pkg.version)
|
31 | .arguments("[folder]")
|
32 | .usage("[options] [folder]")
|
33 | .description(
|
34 | "Run a tiny & simple server (like, for tests & stuffs) from a given folder (or the current).",
|
35 | )
|
36 | .option("-p, --port <port>", "port used by the server (default to 12345)")
|
37 | .option("-q, --quiet", "don't show the logs")
|
38 | .option("-i, --index", "enable autoindex")
|
39 | .option("-N, --no-open", "don't browse to the URL at startup")
|
40 | .action(sFolder => {
|
41 | if (!fs.existsSync(sFolder)) {
|
42 | return console.log(
|
43 | chalk.bold.red(
|
44 | "✘ given folder doesn't exists, use current path instead.",
|
45 | ),
|
46 | );
|
47 | }
|
48 | if (!fs.statSync(sFolder).isDirectory()) {
|
49 | return console.log(
|
50 | chalk.bold.red(
|
51 | "✘ given folder isn't a folder, use current path instead.",
|
52 | ),
|
53 | );
|
54 | }
|
55 | sServerRoot = sFolder;
|
56 | })
|
57 | .parse(process.argv);
|
58 |
|
59 | if (isNaN((iPort = +(program.port || 12345)))) {
|
60 | console.log(chalk.bold.red(`✘ port must be a number, '${iPort}' given.`));
|
61 | process.exit(1);
|
62 | }
|
63 |
|
64 | if (iPort <= 1024 && process.getuid() !== 0) {
|
65 | console.log(
|
66 | chalk.bold.yellow(
|
67 | `⚠ seve needs to be run as sudo to use port '${iPort}'.`,
|
68 | ),
|
69 | );
|
70 | process.exit(1);
|
71 | }
|
72 |
|
73 | if (program.index) {
|
74 | server
|
75 | .engine("hbs", expressHBS({extname: "hbs"}))
|
76 | .set("view engine", "hbs")
|
77 | .set("views", `${__dirname}/../views`)
|
78 | .use("/__seve", express.static(`${__dirname}/../autoindexes`))
|
79 | .use((oRequest, oResponse, fNext) => {
|
80 | if (oRequest.url.substr(-1) === "/") {
|
81 | let sPath = path.join(sServerRoot, oRequest.url);
|
82 |
|
83 | if (fs.existsSync(`${sPath}/index.html`)) {
|
84 | return oResponse.sendFile("./index.html", {
|
85 | root: path.resolve(process.cwd(), sPath),
|
86 | });
|
87 | }
|
88 | if (fs.existsSync(`${sPath}/index.htm`)) {
|
89 | return oResponse.sendFile("index.htm", {
|
90 | root: path.resolve(process.cwd(), sPath),
|
91 | });
|
92 | }
|
93 |
|
94 | return oResponse.render("autoindex.hbs", {
|
95 | files: fs
|
96 | .readdirSync(sPath)
|
97 | .map(sFile => {
|
98 | if (sFile.substr(0, 1) !== ".") {
|
99 | let oFile = fs.statSync(`${sPath}/${sFile}`),
|
100 | sMimeType = mimetype.lookup(sFile);
|
101 |
|
102 | sMimeType = sMimeType
|
103 | ? sMimeType.split("/")[0]
|
104 | : "unknown";
|
105 |
|
106 | return {
|
107 | isFolder: oFile.isDirectory(),
|
108 | mime: oFile.isDirectory()
|
109 | ? "folder"
|
110 | : sMimeType,
|
111 | name: sFile,
|
112 | size: humanSize(oFile.size),
|
113 | time: {
|
114 | raw: oFile.mtime,
|
115 | human: moment(oFile.mtime).format(
|
116 | "YYYY-MM-DD HH:mm:SS",
|
117 | ),
|
118 | },
|
119 | };
|
120 | }
|
121 |
|
122 | return false;
|
123 | })
|
124 | .sort(),
|
125 | folder: oRequest.url,
|
126 | hasParent: oRequest.url !== "/",
|
127 | port: iPort,
|
128 | root: sServerRoot.replace(os.homedir(), "~"),
|
129 | version: pkg.version,
|
130 | });
|
131 | }
|
132 | fNext();
|
133 | });
|
134 | }
|
135 |
|
136 | if (!program.quiet) {
|
137 | server.use((oRequest, oResponse, fNext) => {
|
138 | let sHour = new Date().toTimeString().split(" ")[0];
|
139 |
|
140 | console.log(
|
141 | chalk.cyan(`[${sHour}]`),
|
142 | chalk.magenta(`(${oRequest.method})`),
|
143 | oRequest.url,
|
144 | );
|
145 | fNext();
|
146 | });
|
147 | }
|
148 |
|
149 | server.use(express.static(sServerRoot));
|
150 | server.listen(iPort);
|
151 |
|
152 | if (program.open) {
|
153 | opn(`http://localhost:${iPort}`);
|
154 | }
|
155 |
|
156 | console.log(
|
157 | chalk.underline(
|
158 | `Serving folder ${chalk.bold.cyan(
|
159 | sServerRoot,
|
160 | )} listening on port ${chalk.bold.yellow(iPort)}.`,
|
161 | ),
|
162 | );
|
163 | console.log(`Quit with (${chalk.cyan("^+C")}).\n`);
|