1const http = require('http');
2const fs = require('fs').promises;
3const path = require('path');
4
5// This file is used for testing wasm build from emscripten
6// Example build command:
7// emcmake cmake -B build-wasm -DGGML_WEBGPU=ON -DLLAMA_OPENSSL=OFF
8// cmake --build build-wasm --target test-backend-ops -j
9
10const PORT = 8080;
11const STATIC_DIR = path.join(__dirname, '../build-wasm/bin');
12console.log(`Serving static files from: ${STATIC_DIR}`);
13
14const mimeTypes = {
15 '.html': 'text/html',
16 '.js': 'text/javascript',
17 '.css': 'text/css',
18 '.png': 'image/png',
19 '.jpg': 'image/jpeg',
20 '.gif': 'image/gif',
21 '.svg': 'image/svg+xml',
22 '.json': 'application/json',
23 '.woff': 'font/woff',
24 '.woff2': 'font/woff2',
25};
26
27async function generateDirListing(dirPath, reqUrl) {
28 const files = await fs.readdir(dirPath);
29 let html = `
30 <!DOCTYPE html>
31 <html>
32 <head>
33 <title>Directory Listing</title>
34 <style>
35 body { font-family: Arial, sans-serif; padding: 20px; }
36 ul { list-style: none; padding: 0; }
37 li { margin: 5px 0; }
38 a { text-decoration: none; color: #0066cc; }
39 a:hover { text-decoration: underline; }
40 </style>
41 </head>
42 <body>
43 <h1>Directory: ${reqUrl}</h1>
44 <ul>
45 `;
46
47 if (reqUrl !== '/') {
48 html += `<li><a href="../">../ (Parent Directory)</a></li>`;
49 }
50
51 for (const file of files) {
52 const filePath = path.join(dirPath, file);
53 const stats = await fs.stat(filePath);
54 const link = encodeURIComponent(file) + (stats.isDirectory() ? '/' : '');
55 html += `<li><a href="${link}">${file}${stats.isDirectory() ? '/' : ''}</a></li>`;
56 }
57
58 html += `
59 </ul>
60 </body>
61 </html>
62 `;
63 return html;
64}
65
66const server = http.createServer(async (req, res) => {
67 try {
68 // Set COOP and COEP headers
69 res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
70 res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
71 res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
72 res.setHeader('Pragma', 'no-cache');
73 res.setHeader('Expires', '0');
74
75 const filePath = path.join(STATIC_DIR, decodeURIComponent(req.url));
76 const stats = await fs.stat(filePath);
77
78 if (stats.isDirectory()) {
79 const indexPath = path.join(filePath, 'index.html');
80 try {
81 const indexData = await fs.readFile(indexPath);
82 res.writeHeader(200, { 'Content-Type': 'text/html' });
83 res.end(indexData);
84 } catch {
85 // No index.html, generate directory listing
86 const dirListing = await generateDirListing(filePath, req.url);
87 res.writeHeader(200, { 'Content-Type': 'text/html' });
88 res.end(dirListing);
89 }
90 } else {
91 const ext = path.extname(filePath).toLowerCase();
92 const contentType = mimeTypes[ext] || 'application/octet-stream';
93 const data = await fs.readFile(filePath);
94 res.writeHeader(200, { 'Content-Type': contentType });
95 res.end(data);
96 }
97 } catch (err) {
98 if (err.code === 'ENOENT') {
99 res.writeHeader(404, { 'Content-Type': 'text/plain' });
100 res.end('404 Not Found');
101 } else {
102 res.writeHeader(500, { 'Content-Type': 'text/plain' });
103 res.end('500 Internal Server Error');
104 }
105 }
106});
107
108server.listen(PORT, () => {
109 console.log(`Server running at http://localhost:${PORT}/`);
110});