decentralised message store

feat: websockets

serenity ad86b65a 27642877

Changed files
+81 -19
src
lib
routes
server
+4 -1
.example.env
···
# use ":memory:" if you want an in-memory store, or "file:path/to/file.db" for an embedded file on the server.
-
# if remote, it must point to a sqlite db (for now).
+
# if remote, it must point to a sqlite (libsql) db (for now).
# defaults to ":memory:"
DB_URL=":memory:"
···
# optional, for at-rest encryption of the contents of your shard. if omitted, no encryption at rest is performed.
ENC_PASSPHRASE=
+
+
# port for the shard server to run on. defaults to 7337.
+
SERVER_PORT="7337"
+41 -12
src/index.ts
···
+
import { setupDbWithMigrations } from "@/db";
+
import { DB_URL, SERVER_PORT } from "@/lib/env";
import { routes } from "@/routes";
-
import { server } from "@/server";
+
import { setupServer } from "@/server";
+
+
const main = async () => {
+
if (DB_URL === ":memory:") await setupDbWithMigrations("./drizzle");
+
+
const server = await setupServer();
+
for (const [url, route] of Object.entries(routes)) {
+
if (!route.wsHandler) {
+
const { handler, method } = route;
+
server.route({
+
url,
+
method,
+
handler,
+
});
+
} else {
+
const { wsHandler, method, handler } = route;
+
server.route({
+
url,
+
method: method ?? "GET",
+
handler: handler ?? (() => new Response()),
+
wsHandler,
+
});
+
}
+
}
-
for (const [url, route] of Object.entries(routes)) {
-
const { handler, method } = route;
-
server.route({
-
url,
-
method,
-
handler,
+
server.listen({ port: SERVER_PORT }).catch((err: unknown) => {
+
server.log.error(err);
+
process.exit(1);
});
-
}
+
};
-
server.listen({ port: 3000 }).catch((err: unknown) => {
-
server.log.error(err);
-
process.exit(1);
-
});
+
main()
+
.then(() => {
+
console.log("Exited gracefully.");
+
})
+
.catch((err: unknown) => {
+
console.error("Something went wrong :(");
+
console.error(
+
"=========================== FULL ERROR BELOW ===========================",
+
);
+
console.error(err);
+
});
+10 -1
src/lib/env.ts
···
const dbUrl = process.env.DB_URL;
if (!dbUrl)
-
console.warn("Environment DB_URL not set. Defaulting to `:memory:`");
+
console.warn(
+
"Environment variable DB_URL not set. Defaulting to `:memory:`",
+
);
export const DB_URL = dbUrl ?? ":memory:";
const authToken = process.env.AUTH_TOKEN;
···
console.warn("No PASSPHRASE set. Contents will NOT be encrypted at rest");
else console.log("PASSPHRASE is set. Contents will he encrypted at rest");
export const ENC_PASSPHRASE = encPassphrase;
+
+
const serverPort = process.env.SERVER_PORT;
+
if (!serverPort)
+
console.warn(
+
"Environment variable SERVER_PORT not set. Defaulting to 7337",
+
);
+
export const SERVER_PORT = Number.parseInt(serverPort ?? "7337");
+13
src/lib/types/routes.ts
···
import type { FastifyReply, FastifyRequest } from "fastify";
+
import type { WebSocket } from "ws";
export type RouteHandler = (
req: FastifyRequest | undefined,
···
export interface Route {
method: Method;
handler: RouteHandler;
+
wsHandler?: undefined;
+
}
+
+
export type WsRouteHandler = (
+
socket: WebSocket,
+
req: FastifyRequest | undefined,
+
) => void;
+
+
export interface WsRoute {
+
method?: Method;
+
handler?: RouteHandler;
+
wsHandler: WsRouteHandler;
}
+2 -2
src/routes/index.ts
···
-
import type { Route } from "@/lib/types/routes";
+
import type { Route, WsRoute } from "@/lib/types/routes";
import { indexRoute } from "@/routes/route";
-
export const routes: Record<string, Route> = {
+
export const routes: Record<string, Route | WsRoute> = {
"/": indexRoute,
};
+11 -3
src/server/index.ts
···
+
import websocket from "@fastify/websocket";
import Fastify from "fastify";
-
export const server = Fastify({
-
logger: true,
-
});
+
+
export const setupServer = async () => {
+
const fastify = Fastify({
+
logger: true,
+
});
+
+
await fastify.register(websocket);
+
+
return fastify;
+
};