Current section

Files

Jump to
smol src bun.ffi.mjs
Raw

src/bun.ffi.mjs

import { Result$Ok, Result$Error } from "./gleam.mjs";
import { Option$None } from "../gleam_stdlib/gleam/option.mjs";
import { adapt } from "./adapt.ffi.mjs";
import {
File$File,
FileError$IsDir,
FileError$NoAccess,
FileError$NoEntry,
FileError$UnknownFileError,
started,
} from "./smol.mjs";
import { upgrade } from "./smol.ffi.mjs";
import {
Builder$Builder$handler,
Builder$Builder$port,
Builder$Builder$interface,
Builder$Builder$on_error,
Builder$Builder$after_start,
} from "./smol/internal/builder.mjs";
export function start(builder) {
try {
const handler = adapt(Builder$Builder$handler(builder));
const server = Bun.serve({
port: Builder$Builder$port(builder),
hostname: Builder$Builder$interface(builder),
development: false,
async fetch(req, server) {
const res = await handler(req);
if (
res.body[upgrade] &&
server.upgrade(req, {
headers: res.headers,
data: res.body[upgrade],
})
) {
return;
} else {
return res;
}
},
error(error) {
Builder$Builder$on_error(builder)(error.stack, error);
return new Response("Internal Server Error", { status: 500 });
},
websocket: {
perMessageDeflate: true,
open(ws) {
const runtime = ws.data;
runtime.send = (message) => ws.send(message);
runtime.close = () => ws.close();
runtime.onOpen();
},
message(ws, message) {
ws.data.onMessage(message);
},
close(ws) {
ws.data.onClose();
},
},
});
let disposed = false;
const stop = async () => {
if (disposed) {
return;
}
disposed = true;
process.off("SIGINT", onExit);
process.off("SIGTERM", onExit);
process.off("exit", onExit);
await server.stop();
};
const onExit = async () => {
try {
await stop();
} finally {
process.exit();
}
};
process.on("SIGINT", onExit);
process.on("SIGTERM", onExit);
process.on("exit", onExit);
Builder$Builder$after_start(builder)(server.port, server.hostname);
return Promise.resolve(started(server.port, server.hostname, stop));
} catch (e) {
return Promise.resolve(Result$Error(undefined));
}
}
export async function from_file(path, offset, limit) {
try {
const file = Bun.file(path);
const fileInfo = await file.stat();
if (fileInfo.isDirectory()) {
return Result$Error(FileError$IsDir());
}
const body =
limit > 0
? file.slice(offset, offset + limit).stream()
: file.slice(offset).stream();
return Result$Ok(File$File(body, fileInfo.size, Option$None()));
} catch (e) {
if (e.code === "ENOENT") {
return Result$Error(FileError$NoEntry());
} else if (e.code === "EACCES" || e.code === "EPERM") {
return Result$Error(FileError$NoAccess());
} else if (e.code === "EISDIR") {
return Result$Error(FileError$IsDir());
} else {
return Result$Error(FileError$UnknownFileError());
}
}
}