1 |
|
2 |
|
3 | const http = require('http');
|
4 | const mime = require('mime');
|
5 | const pify = require('pify');
|
6 | const EventEmitter = require('events').EventEmitter;
|
7 | const liveReload = require('tiny-lr');
|
8 | const sep = require('path').sep;
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | class Server extends EventEmitter {
|
20 | constructor(port, disableLiveReload) {
|
21 | super();
|
22 | if (typeof port !== 'number') {
|
23 | throw new Error('port argument required to initialize a server');
|
24 | }
|
25 | this._port = port;
|
26 | this._files = [];
|
27 | this._disableLiveReload = !!disableLiveReload;
|
28 | }
|
29 |
|
30 | |
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | setFiles(files) {
|
38 | this._files = files;
|
39 | if (this._lr) {
|
40 | this._lr.changed({ body: { files: '*' } });
|
41 | }
|
42 | return this;
|
43 | }
|
44 |
|
45 | |
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 | handler(request, response) {
|
56 | let path = request.url.substring(1);
|
57 | if (path === '') {
|
58 | path = 'index.html';
|
59 | }
|
60 |
|
61 | for (let i = 0; i < this._files.length; i++) {
|
62 | const file = this._files[i];
|
63 | const filePath = file.relative.split(sep).join('/');
|
64 | if (filePath === path) {
|
65 | response.writeHead(200, { 'Content-Type': mime.getType(path) });
|
66 | response.end(file.contents);
|
67 | return;
|
68 | }
|
69 | }
|
70 | response.writeHead(404, { 'Content-Type': 'text/plain' });
|
71 | response.end('Not found');
|
72 | }
|
73 |
|
74 | start() {
|
75 | |
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 | return new Promise(resolve => {
|
82 |
|
83 | if (this._http) {
|
84 | return resolve(this);
|
85 | }
|
86 |
|
87 | if (!this._disableLiveReload) {
|
88 | this._lr = liveReload();
|
89 | }
|
90 | this._http = http.createServer(this.handler.bind(this));
|
91 |
|
92 | return Promise.all([
|
93 | this._lr && pify(this._lr.listen.bind(this._lr))(35729),
|
94 | pify(this._http.listen.bind(this._http))(this._port)
|
95 | ]).then(() => {
|
96 | this.emit('listening');
|
97 | return resolve(this);
|
98 | });
|
99 | });
|
100 | }
|
101 |
|
102 | stop() {
|
103 | |
104 |
|
105 |
|
106 |
|
107 | return Promise.all([
|
108 | this._http && this._http.close(),
|
109 | this._lr && this._lr.close()
|
110 | ]).then(() => {
|
111 | delete this._http;
|
112 | delete this._lr;
|
113 | return this;
|
114 | });
|
115 | }
|
116 | }
|
117 |
|
118 | module.exports = Server;
|