summaryrefslogtreecommitdiff
path: root/tools/portraits/server.ts
blob: 8af80f59aca46e9e9b8860ae9ef754166c842e97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Renders avatar portraits for the lobby. Serves render.html plus the project's
// public files, and saves the PNGs the page POSTs back into ./out.
//
//   deno run --allow-net=127.0.0.1:8097 --allow-read --allow-write=tools/portraits tools/portraits/server.ts
//   then open http://localhost:8097/ (or ?slugs=name1,name2) and wait for the title "done".
const HERE = new URL('.', import.meta.url).pathname;
const PUBLIC = new URL('../../public', import.meta.url).pathname;
await Deno.mkdir(`${HERE}out`, { recursive: true });

const TYPES: Record<string, string> = { html: 'text/html', js: 'text/javascript', vrm: 'application/octet-stream' };

Deno.serve({ port: 8097, hostname: '127.0.0.1' }, async (req) => {
  const url = new URL(req.url);
  if (url.pathname.includes('..')) return new Response('no', { status: 400 });
  if (req.method === 'POST' && url.pathname.startsWith('/save/')) {
    const slug = url.pathname.slice(6).replace(/[^a-z0-9-]/g, '');
    await Deno.writeFile(`${HERE}out/${slug}.png`, new Uint8Array(await req.arrayBuffer()));
    return new Response('ok');
  }
  const file = url.pathname === '/' ? `${HERE}render.html` : PUBLIC + url.pathname;
  try {
    const ext = file.split('.').pop() || '';
    return new Response(await Deno.readFile(file), { headers: { 'content-type': TYPES[ext] || 'application/octet-stream' } });
  } catch {
    return new Response('not found', { status: 404 });
  }
});