84 lines
1.7 KiB
TypeScript
84 lines
1.7 KiB
TypeScript
import dayjs from "dayjs";
|
|
import { Elysia } from "elysia";
|
|
import { generateTokenAndKey, resolveToken } from "./human";
|
|
import { err } from "./logging";
|
|
import { liveTable, WsIn, WsOut } from "./table";
|
|
import type { ExtractPropertyType, UnionKeys } from "@games/shared/types";
|
|
|
|
const api = new Elysia({ prefix: "/api" })
|
|
.post("/whoami", async ({ cookie: { token } }) => {
|
|
let key: string | undefined;
|
|
if (token.value == null || (key = resolveToken(token.value)) == null) {
|
|
const [newToken, newKey] = generateTokenAndKey();
|
|
token.set({
|
|
value: newToken,
|
|
expires: dayjs().add(1, "year").toDate(),
|
|
httpOnly: true,
|
|
});
|
|
return newKey;
|
|
}
|
|
return key;
|
|
})
|
|
.derive(async ({ cookie: { token }, status }) => {
|
|
const humanKey = token.value && resolveToken(token.value);
|
|
return humanKey != null ? { humanKey } : status(401);
|
|
})
|
|
.ws("/ws/:tableKey", {
|
|
body: WsIn,
|
|
response: WsOut,
|
|
|
|
open({
|
|
data: {
|
|
params: { tableKey },
|
|
humanKey,
|
|
},
|
|
send,
|
|
}) {
|
|
const table = liveTable(tableKey);
|
|
|
|
table.inputs.connectionChanges.emit({
|
|
humanKey,
|
|
presence: "joined",
|
|
});
|
|
|
|
Object.entries({
|
|
...table.outputs.global,
|
|
...(table.outputs.player[humanKey] ?? {}),
|
|
}).forEach(([type, stream]) =>
|
|
// @ts-ignore
|
|
stream.onValue((v) => send({ [type]: v }))
|
|
);
|
|
},
|
|
|
|
message(
|
|
{
|
|
data: {
|
|
humanKey,
|
|
params: { tableKey },
|
|
},
|
|
},
|
|
body
|
|
) {
|
|
liveTable(tableKey).inputs.messages.emit({ ...body, humanKey });
|
|
},
|
|
|
|
close({
|
|
data: {
|
|
params: { tableKey },
|
|
humanKey,
|
|
},
|
|
}) {
|
|
liveTable(tableKey).inputs.connectionChanges.emit({
|
|
humanKey,
|
|
presence: "left",
|
|
});
|
|
},
|
|
|
|
error(error) {
|
|
err(error);
|
|
},
|
|
});
|
|
|
|
export default api;
|
|
export type Api = typeof api;
|