import http from "http"; import { readdir } from "fs/promises"; import { stat } from "fs/promises"; import { readFile } from "fs/promises"; import { join } from "path"; import { dirname } from "path"; import { fileURLToPath } from "url"; class App { constructor( ) { const selfPath = fileURLToPath( import.meta.url ); this.rootPath = dirname( selfPath ); this.httpServer = null; } async start( ) { this.httpServer = http.createServer( this.handleRequest.bind( this ) ); this.httpServer.listen( 2020 ); console.log("Server started on port http://localhost:2020/"); } async handleRequest( req, res ) { const requestedPath = decodeURI( req.url ); const fullPath = join( this.rootPath, requestedPath ); const exists = await this.checkFileExists( fullPath ); if ( !exists ) { res.statusCode = 404; res.end( "Not Found" ); return; } const stats = await stat( fullPath ); if ( stats.isDirectory( ) ) { const indexPath = join( fullPath, "index.html" ); const indexExists = await this.checkFileExists( indexPath ); if ( indexExists ) { await this.sendFile( indexPath, res ); return; } await this.sendDirectoryListing( fullPath, requestedPath, res ); return; } await this.sendFile( fullPath, res ); } async sendFile( path, res ) { const contentType = this.getContentType( path ); const fileData = await readFile( path ); res.setHeader( "Content-Type", contentType ); res.statusCode = 200; res.end( fileData ); } async sendDirectoryListing( dirPath, urlPath, res ) { const entries = await readdir( dirPath, { withFileTypes : true } ); let html = "

Index of " + urlPath + "

"; res.setHeader( "Content-Type", "text/html" ); res.statusCode = 200; res.end( html ); } async checkFileExists( path ) { const exists = await stat( path ) .then( function( ) { return true; } ) .catch( function( ) { return false; } ); return exists; } getContentType( path ) { const lower = path.toLowerCase( ); if ( lower.endsWith( ".html" ) ) return "text/html"; if ( lower.endsWith( ".css" ) ) return "text/css"; if ( lower.endsWith( ".js" ) ) return "text/javascript"; if ( lower.endsWith( ".json" ) ) return "application/json"; if ( lower.endsWith( ".wasm" ) ) return "application/wasm"; if ( lower.endsWith( ".png" ) ) return "image/png"; if ( lower.endsWith( ".jpg" ) ) return "image/jpeg"; if ( lower.endsWith( ".jpeg" ) ) return "image/jpeg"; if ( lower.endsWith( ".gif" ) ) return "image/gif"; if ( lower.endsWith( ".svg" ) ) return "image/svg+xml"; if ( lower.endsWith( ".wgsl" ) ) return "text/plain"; if ( lower.endsWith( ".txt" ) ) return "text/plain"; return "application/octet-stream"; } } const app = new App( ); await app.start( );