1 | import * as http from 'http';
|
2 | import {
|
3 | Clients,
|
4 | CompiledFiles,
|
5 | FileContentsResult,
|
6 | CustomHTTPHeaders,
|
7 | HTTPHeaders
|
8 | } from '../index.d.ts';
|
9 | import { getJavaScriptFileContents } from './languages/javascript.ts';
|
10 | import { getTypeScriptFileContents } from './languages/typescript.ts';
|
11 | import { getAssemblyScriptFileContents } from './languages/assemblyscript.ts';
|
12 | import { getWasmFileContents } from './languages/wasm.ts';
|
13 | import { getWatFileContents } from './languages/wat.ts';
|
14 | import {
|
15 | getFileContents,
|
16 | getCustomHTTPHeadersFromFile,
|
17 | getCustomHTTPHeadersForURL
|
18 | } from './utilities.ts';
|
19 | import * as mime from 'mime';
|
20 |
|
21 | export async function createHTTPServer(params: {
|
22 | wsPort: number;
|
23 | watchFiles: boolean;
|
24 | jsTarget: string;
|
25 | clients: Clients;
|
26 | compiledFiles: CompiledFiles;
|
27 | disableSpa: boolean;
|
28 | customHTTPHeadersFilePath: string | undefined;
|
29 | }): Promise<Readonly<http.Server>> {
|
30 |
|
31 | const customHTTPHeaders: Readonly<CustomHTTPHeaders> = params.customHTTPHeadersFilePath === undefined ? {} : await getCustomHTTPHeadersFromFile(params.customHTTPHeadersFilePath);
|
32 |
|
33 | return http.createServer(async (req: Readonly<http.IncomingMessage>, res: http.ServerResponse) => {
|
34 |
|
35 | try {
|
36 | if (req.url === undefined) {
|
37 | throw new Error('The URL of the request is not defined');
|
38 | }
|
39 |
|
40 | const fileExtension: string = req.url.slice(req.url.lastIndexOf('.') + 1);
|
41 |
|
42 | if (fileExtension === '/') {
|
43 |
|
44 | await handleIndex({
|
45 | compiledFiles: params.compiledFiles,
|
46 | watchFiles: params.watchFiles,
|
47 | clients: params.clients,
|
48 | disableSpa: params.disableSpa,
|
49 | res,
|
50 | customHTTPHeaders
|
51 | });
|
52 |
|
53 | return;
|
54 | }
|
55 |
|
56 | if (fileExtension === 'js') {
|
57 |
|
58 | await handleJavaScript({
|
59 | url: `.${req.url}`,
|
60 | compiledFiles: params.compiledFiles,
|
61 | watchFiles: params.watchFiles,
|
62 | clients: params.clients,
|
63 | jsTarget: params.jsTarget,
|
64 | wsPort: params.wsPort,
|
65 | disableSpa: params.disableSpa,
|
66 | res,
|
67 | customHTTPHeaders
|
68 | });
|
69 |
|
70 | return;
|
71 | }
|
72 |
|
73 | if (fileExtension === 'mjs') {
|
74 |
|
75 | await handleJavaScript({
|
76 | url: `.${req.url}`,
|
77 | compiledFiles: params.compiledFiles,
|
78 | watchFiles: params.watchFiles,
|
79 | clients: params.clients,
|
80 | jsTarget: params.jsTarget,
|
81 | wsPort: params.wsPort,
|
82 | disableSpa: params.disableSpa,
|
83 | res,
|
84 | customHTTPHeaders
|
85 | });
|
86 |
|
87 | return;
|
88 | }
|
89 |
|
90 | if (fileExtension === 'ts') {
|
91 |
|
92 | await handleTypeScript({
|
93 | url: `.${req.url}`,
|
94 | compiledFiles: params.compiledFiles,
|
95 | watchFiles: params.watchFiles,
|
96 | clients: params.clients,
|
97 | jsTarget: params.jsTarget,
|
98 | wsPort: params.wsPort,
|
99 | disableSpa: params.disableSpa,
|
100 | res,
|
101 | customHTTPHeaders
|
102 | });
|
103 |
|
104 | return;
|
105 | }
|
106 |
|
107 | if (fileExtension === 'as') {
|
108 |
|
109 | await handleAssemblyScript({
|
110 | url: `.${req.url}`,
|
111 | compiledFiles: params.compiledFiles,
|
112 | watchFiles: params.watchFiles,
|
113 | clients: params.clients,
|
114 | jsTarget: params.jsTarget,
|
115 | wsPort: params.wsPort,
|
116 | disableSpa: params.disableSpa,
|
117 | res,
|
118 | customHTTPHeaders
|
119 | });
|
120 |
|
121 | return;
|
122 | }
|
123 |
|
124 | if (fileExtension === 'wasm') {
|
125 | await handleWasm({
|
126 | url: `.${req.url}`,
|
127 | compiledFiles: params.compiledFiles,
|
128 | watchFiles: params.watchFiles,
|
129 | clients: params.clients,
|
130 | jsTarget: params.jsTarget,
|
131 | wsPort: params.wsPort,
|
132 | disableSpa: params.disableSpa,
|
133 | res,
|
134 | customHTTPHeaders
|
135 | });
|
136 |
|
137 | return;
|
138 | }
|
139 |
|
140 | if (fileExtension === 'wat') {
|
141 | await handleWat({
|
142 | url: `.${req.url}`,
|
143 | compiledFiles: params.compiledFiles,
|
144 | watchFiles: params.watchFiles,
|
145 | clients: params.clients,
|
146 | jsTarget: params.jsTarget,
|
147 | wsPort: params.wsPort,
|
148 | disableSpa: params.disableSpa,
|
149 | res,
|
150 | customHTTPHeaders
|
151 | });
|
152 |
|
153 | return;
|
154 | }
|
155 |
|
156 | await handleGeneric({
|
157 | url: `.${req.url}`,
|
158 | compiledFiles: params.compiledFiles,
|
159 | watchFiles: params.watchFiles,
|
160 | clients: params.clients,
|
161 | disableSpa: params.disableSpa,
|
162 | res,
|
163 | customHTTPHeaders
|
164 | });
|
165 | }
|
166 | catch(error) {
|
167 | console.log(error);
|
168 | }
|
169 | });
|
170 | }
|
171 |
|
172 | async function handleIndex(params: {
|
173 | compiledFiles: CompiledFiles;
|
174 | watchFiles: boolean;
|
175 | clients: Clients;
|
176 | disableSpa: boolean;
|
177 | res: http.ServerResponse;
|
178 | customHTTPHeaders: Readonly<CustomHTTPHeaders>;
|
179 | }): Promise<void> {
|
180 |
|
181 | const url: string = './index.html';
|
182 |
|
183 | const indexFileContentsResult: Readonly<FileContentsResult> = await getFileContents({
|
184 | url,
|
185 | compiledFiles: params.compiledFiles,
|
186 | watchFiles: params.watchFiles,
|
187 | clients: params.clients,
|
188 | disableSpa: params.disableSpa,
|
189 | transformer: 'NOT_SET'
|
190 | });
|
191 |
|
192 | const httpHeaders: Readonly<HTTPHeaders> = getCustomHTTPHeadersForURL({
|
193 | customHTTPHeaders: params.customHTTPHeaders,
|
194 | defaultHTTPHeaders: {
|
195 | 'Content-Type': 'text/html'
|
196 | },
|
197 | url
|
198 | });
|
199 |
|
200 | await sendResponse({
|
201 | res: params.res,
|
202 | fileContentsResult: indexFileContentsResult,
|
203 | headers: httpHeaders
|
204 | });
|
205 | }
|
206 |
|
207 | async function handleGeneric(params: {
|
208 | url: string;
|
209 | compiledFiles: CompiledFiles;
|
210 | watchFiles: boolean;
|
211 | clients: Clients;
|
212 | disableSpa: boolean;
|
213 | res: http.ServerResponse;
|
214 | customHTTPHeaders: Readonly<CustomHTTPHeaders>;
|
215 | }): Promise<void> {
|
216 |
|
217 | const genericFileContentsResult: Readonly<FileContentsResult> = await getFileContents({
|
218 | url: params.url,
|
219 | compiledFiles: params.compiledFiles,
|
220 | watchFiles: params.watchFiles,
|
221 | clients: params.clients,
|
222 | disableSpa: params.disableSpa,
|
223 | transformer: 'NOT_SET'
|
224 | });
|
225 |
|
226 | const mimeType: string | null = mime.getType(params.url);
|
227 |
|
228 | const httpHeaders: Readonly<HTTPHeaders> = getCustomHTTPHeadersForURL({
|
229 | customHTTPHeaders: params.customHTTPHeaders,
|
230 | defaultHTTPHeaders: mimeType ? {
|
231 | 'Content-Type': mimeType
|
232 | } : {},
|
233 | url: params.url
|
234 | });
|
235 |
|
236 | await sendResponse({
|
237 | res: params.res,
|
238 | fileContentsResult: genericFileContentsResult,
|
239 | headers: httpHeaders
|
240 | });
|
241 | }
|
242 |
|
243 | async function handleJavaScript(params: {
|
244 | url: string;
|
245 | compiledFiles: CompiledFiles;
|
246 | watchFiles: boolean;
|
247 | clients: Clients;
|
248 | jsTarget: string;
|
249 | wsPort: number;
|
250 | disableSpa: boolean;
|
251 | res: http.ServerResponse;
|
252 | customHTTPHeaders: Readonly<CustomHTTPHeaders>;
|
253 | }): Promise<void> {
|
254 | const javaScriptFileContentsResult: Readonly<FileContentsResult> = await getJavaScriptFileContents({
|
255 | url: params.url,
|
256 | compiledFiles: params.compiledFiles,
|
257 | watchFiles: params.watchFiles,
|
258 | clients: params.clients,
|
259 | jsTarget: params.jsTarget,
|
260 | wsPort: params.wsPort,
|
261 | disableSpa: params.disableSpa
|
262 | });
|
263 |
|
264 | const httpHeaders: Readonly<HTTPHeaders> = getCustomHTTPHeadersForURL({
|
265 | customHTTPHeaders: params.customHTTPHeaders,
|
266 | defaultHTTPHeaders: {
|
267 | 'Content-Type': 'application/javascript'
|
268 | },
|
269 | url: params.url
|
270 | });
|
271 |
|
272 | await sendResponse({
|
273 | res: params.res,
|
274 | fileContentsResult: javaScriptFileContentsResult,
|
275 | headers: httpHeaders
|
276 | });
|
277 | }
|
278 |
|
279 | async function handleTypeScript(params: {
|
280 | url: string;
|
281 | compiledFiles: CompiledFiles;
|
282 | watchFiles: boolean;
|
283 | clients: Clients;
|
284 | jsTarget: string;
|
285 | wsPort: number;
|
286 | disableSpa: boolean;
|
287 | res: http.ServerResponse;
|
288 | customHTTPHeaders: Readonly<CustomHTTPHeaders>;
|
289 | }): Promise<void> {
|
290 | const typeScriptFileContentsResult: Readonly<FileContentsResult> = await getTypeScriptFileContents({
|
291 | url: params.url,
|
292 | compiledFiles: params.compiledFiles,
|
293 | watchFiles: params.watchFiles,
|
294 | clients: params.clients,
|
295 | jsTarget: params.jsTarget,
|
296 | wsPort: params.wsPort,
|
297 | disableSpa: params.disableSpa
|
298 | });
|
299 |
|
300 | const httpHeaders: Readonly<HTTPHeaders> = getCustomHTTPHeadersForURL({
|
301 | customHTTPHeaders: params.customHTTPHeaders,
|
302 | defaultHTTPHeaders: {
|
303 | 'Content-Type': 'application/javascript'
|
304 | },
|
305 | url: params.url
|
306 | });
|
307 |
|
308 | await sendResponse({
|
309 | res: params.res,
|
310 | fileContentsResult: typeScriptFileContentsResult,
|
311 | headers: httpHeaders
|
312 | });
|
313 | }
|
314 |
|
315 | async function handleAssemblyScript(params: {
|
316 | url: string;
|
317 | compiledFiles: CompiledFiles;
|
318 | watchFiles: boolean;
|
319 | clients: Clients;
|
320 | jsTarget: string;
|
321 | wsPort: number;
|
322 | disableSpa: boolean;
|
323 | res: http.ServerResponse;
|
324 | customHTTPHeaders: Readonly<CustomHTTPHeaders>;
|
325 | }): Promise<void> {
|
326 | const assemblyScriptFileContentsResult: Readonly<FileContentsResult> = await getAssemblyScriptFileContents({
|
327 | url: params.url,
|
328 | compiledFiles: params.compiledFiles,
|
329 | watchFiles: params.watchFiles,
|
330 | clients: params.clients,
|
331 | jsTarget: params.jsTarget,
|
332 | wsPort: params.wsPort,
|
333 | disableSpa: params.disableSpa
|
334 | });
|
335 |
|
336 | const httpHeaders: Readonly<HTTPHeaders> = getCustomHTTPHeadersForURL({
|
337 | customHTTPHeaders: params.customHTTPHeaders,
|
338 | defaultHTTPHeaders: {
|
339 | 'Content-Type': 'application/javascript'
|
340 | },
|
341 | url: params.url
|
342 | });
|
343 |
|
344 | await sendResponse({
|
345 | res: params.res,
|
346 | fileContentsResult: assemblyScriptFileContentsResult,
|
347 | headers: httpHeaders
|
348 | });
|
349 | }
|
350 |
|
351 | async function handleWasm(params: {
|
352 | url: string;
|
353 | compiledFiles: CompiledFiles;
|
354 | watchFiles: boolean;
|
355 | clients: Clients;
|
356 | jsTarget: string;
|
357 | wsPort: number;
|
358 | disableSpa: boolean;
|
359 | res: http.ServerResponse;
|
360 | customHTTPHeaders: Readonly<CustomHTTPHeaders>;
|
361 | }): Promise<void> {
|
362 | const wasmFileContentsResult: Readonly<FileContentsResult> = await getWasmFileContents({
|
363 | url: params.url,
|
364 | compiledFiles: params.compiledFiles,
|
365 | watchFiles: params.watchFiles,
|
366 | clients: params.clients,
|
367 | jsTarget: params.jsTarget,
|
368 | wsPort: params.wsPort,
|
369 | disableSpa: params.disableSpa
|
370 | });
|
371 |
|
372 | const httpHeaders: Readonly<HTTPHeaders> = getCustomHTTPHeadersForURL({
|
373 | customHTTPHeaders: params.customHTTPHeaders,
|
374 | defaultHTTPHeaders: {
|
375 | 'Content-Type': 'application/javascript'
|
376 | },
|
377 | url: params.url
|
378 | });
|
379 |
|
380 | await sendResponse({
|
381 | res: params.res,
|
382 | fileContentsResult: wasmFileContentsResult,
|
383 | headers: httpHeaders
|
384 | });
|
385 | }
|
386 |
|
387 | async function handleWat(params: {
|
388 | url: string;
|
389 | compiledFiles: CompiledFiles;
|
390 | watchFiles: boolean;
|
391 | clients: Clients;
|
392 | jsTarget: string;
|
393 | wsPort: number;
|
394 | disableSpa: boolean;
|
395 | res: http.ServerResponse;
|
396 | customHTTPHeaders: Readonly<CustomHTTPHeaders>;
|
397 | }): Promise<void> {
|
398 | const watFileContentsResult: Readonly<FileContentsResult> = await getWatFileContents({
|
399 | url: params.url,
|
400 | compiledFiles: params.compiledFiles,
|
401 | watchFiles: params.watchFiles,
|
402 | clients: params.clients,
|
403 | jsTarget: params.jsTarget,
|
404 | wsPort: params.wsPort,
|
405 | disableSpa: params.disableSpa
|
406 | });
|
407 |
|
408 | const httpHeaders: Readonly<HTTPHeaders> = getCustomHTTPHeadersForURL({
|
409 | customHTTPHeaders: params.customHTTPHeaders,
|
410 | defaultHTTPHeaders: {
|
411 | 'Content-Type': 'application/javascript'
|
412 | },
|
413 | url: params.url
|
414 | });
|
415 |
|
416 | await sendResponse({
|
417 | res: params.res,
|
418 | fileContentsResult: watFileContentsResult,
|
419 | headers: httpHeaders
|
420 | });
|
421 | }
|
422 |
|
423 | async function sendResponse(params: {
|
424 | res: http.ServerResponse;
|
425 | fileContentsResult: Readonly<FileContentsResult>;
|
426 | headers: {
|
427 | [key: string]: string;
|
428 | };
|
429 | }): Promise<void> {
|
430 | if (params.fileContentsResult === 'FILE_NOT_FOUND') {
|
431 | params.res.statusCode = 404;
|
432 | params.res.end();
|
433 | }
|
434 | else {
|
435 | Object.entries(params.headers).forEach((headerEntry) => {
|
436 | const key: string = headerEntry[0];
|
437 | const value: string = headerEntry[1];
|
438 |
|
439 | params.res.setHeader(key, value);
|
440 | });
|
441 |
|
442 | params.res.end(params.fileContentsResult.fileContents);
|
443 | }
|
444 | } |
\ | No newline at end of file |