💾 Archived View for iich.space › src › modules › mission-control › files.ts captured on 2022-03-01 at 16:04:45.

View Raw

More Information

⬅️ Previous capture (2021-12-03)

🚧 View Differences

-=-=-=-=-=-=-

import { existsSync, readdirSync } from 'fs';
import { lstat, readFile, readdir } from 'fs/promises';
import { extname, join } from 'path';

import { Status } from '@/gemini';

import { createLogger } from '../log';

import { Handler } from './application';
import { getMimeType } from './mime';

const log = createLogger();

export const staticFiles = (directory: string): Handler => {
  const baseDirectory = join(process.cwd(), directory);
  const entries = readdirSync(baseDirectory, {
    withFileTypes: true,
  });

  const files = entries
    .filter((entry) => entry.isFile())
    .reduce(
      (entries, { name }) => ({
        ...entries,
        [name]: getMimeType(extname(name)),
      }),
      {} as Record<string, string>,
    );

  return async (_, res, { params }) => {
    const fileName = params.match;
    const absolutePath = join(baseDirectory, fileName);

    if (files[fileName] !== undefined) {
      res.sendStatus(Status.SUCCESS, files[fileName]);
      res.send(await readFile(absolutePath));

      return res.end();
    }
  };
};

export const files = (directory: string, listFiles = false): Handler => {
  const baseDirectory = join(process.cwd(), directory);

  if (existsSync(baseDirectory) === false) {
    return (_, res) => {
      log.error('bad path');

      res.sendStatus(Status.NOT_FOUND);
      res.end();
    };
  }

  return async (_, res, { params }) => {
    const relativePath = (params.match || '').replaceAll(/\.\./g, '');
    const absolutePath = join(baseDirectory, relativePath);

    try {
      const stat = await lstat(absolutePath);

      if (stat.isFile()) {
        res.sendStatus(Status.SUCCESS, getMimeType(extname(absolutePath)));
        res.send(await readFile(absolutePath));
      } else if (stat.isDirectory() && listFiles) {
        const entries = await readdir(absolutePath, { withFileTypes: true });

        res.send('=> ../\n');
        res.send(
          entries
            .map((entry) => ({
              isDirectory: entry.isDirectory(),
              name: entry.name,
            }))
            .sort((a, b) =>
              a.isDirectory === b.isDirectory
                ? a.name.localeCompare(b.name)
                : a.isDirectory
                ? -1
                : 1,
            )
            .map(({ isDirectory, name }) =>
              isDirectory ? `=> ${name}/` : `=> ${name}`,
            )
            .join('\n'),
        );
      }
    } catch {
      res.sendStatus(Status.NOT_FOUND);
    }

    res.end();
  };
};