UNPKG

5.24 kBJavaScriptView Raw
1#!/usr/bin/env node
2/* leny/seve
3 *
4 * /src/seve.js - Main Entry point
5 *
6 * coded by leny@flatLand!
7 * refactored at 30/10/2018
8 */
9
10/* eslint-disable no-console */
11
12import express from "express";
13import expressHBS from "express-handlebars";
14import chalk from "chalk";
15import fs from "fs";
16import path from "path";
17import os from "os";
18import program from "commander";
19import mimetype from "mimetype";
20import humanSize from "human-size";
21import moment from "moment";
22import opn from "opn";
23
24let pkg = require("../package.json"),
25 server = express(),
26 sServerRoot = process.cwd(),
27 iPort;
28
29program
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
59if (isNaN((iPort = +(program.port || 12345)))) {
60 console.log(chalk.bold.red(`✘ port must be a number, '${iPort}' given.`));
61 process.exit(1);
62}
63
64if (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
73if (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
136if (!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
149server.use(express.static(sServerRoot));
150server.listen(iPort);
151
152if (program.open) {
153 opn(`http://localhost:${iPort}`);
154}
155
156console.log(
157 chalk.underline(
158 `Serving folder ${chalk.bold.cyan(
159 sServerRoot,
160 )} listening on port ${chalk.bold.yellow(iPort)}.`,
161 ),
162);
163console.log(`Quit with (${chalk.cyan("^+C")}).\n`);