| 7 | type HandlerFunc = (relativePathname: string, url: URL, req: http.IncomingMessage, res: http.ServerResponse) => any; |
| 8 | |
| 9 | export class FileServer { |
| 10 | server: http.Server; |
| 11 | private handlers: Map<string, HandlerFunc>; |
| 12 | private sockets = new Set<Socket>(); |
| 13 | |
| 14 | constructor() { |
| 15 | this.handlers = new Map(); |
| 16 | this.server = new http.Server(this.onHandleRequest); |
| 17 | // Track all sockets so we can kill them later |
| 18 | this.server.on('connection', socket => { |
| 19 | this.sockets.add(socket); |
| 20 | socket.once('close', () => this.sockets.delete(socket)); // Stop tracking closed sockets |
| 21 | }); |
| 22 | } |
| 23 | |
| 24 | public registerRequestHandler = (region: string, callback: HandlerFunc) => { |
| 25 | if (this.handlers.has(region)) { |
| 26 | log.error('Launcher', `FileServer region "${region}" trying to be re-registered, ignoring second registration...`); |
| 27 | return; |
| 28 | } |
| 29 | |
| 30 | this.handlers.set(region.toLowerCase(), callback); |
| 31 | }; |
| 32 | |
| 33 | public close = (onError?: (err?: Error) => void) => { |
| 34 | for (const socket of this.sockets) { socket.destroy();} |
| 35 | this.server.close(onError); |
| 36 | this.handlers.clear(); |
| 37 | }; |
| 38 | |
| 39 | private onHandleRequest = (req: http.IncomingMessage, res: http.ServerResponse) => { |
| 40 | const url = new URL(`http://example${req.url || ''}`); |
| 41 | |
| 42 | const parts = url.pathname.split('/'); |
| 43 | const region = parts.length > 1 ? parts[1].toLowerCase() : ''; |
| 44 | const pathname = decodeURIComponent(parts.length > 2 ? parts.slice(2).join('/') : ''); |
| 45 | |
| 46 | // Immediately slap on error handlers, see if we can find any disconnected errors |
| 47 | req.on('error', (err) => { |
| 48 | log.error('Launcher', `Generic fileserver request error: ${err}`); |
| 49 | }); |
| 50 | res.on('error', (err) => { |
| 51 | log.error('Launcher', `Generic fileserver response error: ${err}`); |
| 52 | }); |
| 53 | |
| 54 | // Pass to handler |
| 55 | const handler = this.handlers.get(region); |
| 56 | if (handler) { |
| 57 | Promise.resolve(handler(pathname, url, req, res)) |
| 58 | .catch((err) => { |
| 59 | console.log(`FS Handler Error: ${err}`); |
| 60 | res.writeHead(404); |
| 61 | res.end(); |
| 62 | }); |
| 63 | } else { |
| 64 | res.writeHead(404); |
| 65 | res.end(); |
| 66 | } |