no db
This commit is contained in:
@@ -4,9 +4,9 @@ import dayjs from "dayjs";
|
||||
import { Elysia, t } from "elysia";
|
||||
import { combine } from "kefir";
|
||||
import Bus from "kefir-bus";
|
||||
import db from "./db";
|
||||
import { liveTable, WsIn, WsOut } from "./table";
|
||||
import { err } from "./logging";
|
||||
import { generateTokenAndKey, resolveToken, tokenExists } from "./human";
|
||||
|
||||
export const WS = Bus<
|
||||
{
|
||||
@@ -19,63 +19,23 @@ export const WS = Bus<
|
||||
|
||||
const api = new Elysia({ prefix: "/api" })
|
||||
.post("/whoami", async ({ cookie: { token } }) => {
|
||||
let human: Human | null;
|
||||
if (
|
||||
token.value == null ||
|
||||
(human = await db.human.findUnique({
|
||||
where: {
|
||||
token: token.value,
|
||||
},
|
||||
})) == null
|
||||
) {
|
||||
human = await db.human.create({
|
||||
data: {},
|
||||
});
|
||||
console.log("WHOAMI");
|
||||
let key: string | undefined;
|
||||
if (token.value == null || (key = resolveToken(token.value)) == null) {
|
||||
const [newToken, newKey] = generateTokenAndKey();
|
||||
token.set({
|
||||
value: human.token,
|
||||
value: newToken,
|
||||
expires: dayjs().add(1, "year").toDate(),
|
||||
httpOnly: true,
|
||||
});
|
||||
return newKey;
|
||||
}
|
||||
|
||||
return human.key;
|
||||
return key;
|
||||
})
|
||||
.derive(async ({ cookie: { token }, status }) => {
|
||||
const humanKey = await db.human
|
||||
.findUnique({
|
||||
where: { token: token.value },
|
||||
})
|
||||
.then((human) => human?.key);
|
||||
const humanKey = token.value && resolveToken(token.value);
|
||||
return humanKey != null ? { humanKey } : status(401);
|
||||
})
|
||||
.post(
|
||||
"/setName",
|
||||
({ body: { name }, humanKey }) =>
|
||||
db.human.update({
|
||||
where: {
|
||||
key: humanKey,
|
||||
},
|
||||
data: {
|
||||
name,
|
||||
},
|
||||
}),
|
||||
{
|
||||
body: t.Object({
|
||||
name: t.String(),
|
||||
}),
|
||||
}
|
||||
)
|
||||
.get("/profile", ({ humanKey, query: { otherHumanKey } }) =>
|
||||
db.human
|
||||
.findFirst({ where: { key: otherHumanKey ?? humanKey } })
|
||||
.then((human) => {
|
||||
if (human == null) {
|
||||
return null;
|
||||
}
|
||||
const { token, ...safeProfile } = human;
|
||||
return safeProfile;
|
||||
})
|
||||
)
|
||||
.ws("/ws/:tableKey", {
|
||||
body: WsIn,
|
||||
response: WsOut,
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
"use server";
|
||||
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
export default new PrismaClient();
|
||||
17
pkg/server/src/human.ts
Normal file
17
pkg/server/src/human.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
const tokenToHumanKey: { [token: string]: string } = {};
|
||||
const playerKeys: Set<string> = new Set();
|
||||
|
||||
export const generateTokenAndKey = () => {
|
||||
let token: string, key: string;
|
||||
do {
|
||||
[token, key] = [crypto.randomUUID(), crypto.randomUUID()];
|
||||
tokenToHumanKey[token] = key;
|
||||
playerKeys.add(key);
|
||||
} while (!(token in tokenToHumanKey || playerKeys.has(key)));
|
||||
return [token, key];
|
||||
};
|
||||
|
||||
export const resolveToken = (token: string) =>
|
||||
tokenToHumanKey[token] as string | undefined;
|
||||
export const tokenExists = (token: string) => token in tokenToHumanKey;
|
||||
export const keyExists = (key: string) => playerKeys.has(key);
|
||||
@@ -15,6 +15,7 @@ import { log } from "./logging";
|
||||
|
||||
export const WsOut = t.Object({
|
||||
playersPresent: t.Optional(t.Array(t.String())),
|
||||
playerNames: t.Optional(t.Record(t.String(), t.String())),
|
||||
playersReady: t.Optional(t.Nullable(t.Record(t.String(), t.Boolean()))),
|
||||
gameConfig: t.Optional(t.Any()),
|
||||
view: t.Optional(t.Any()),
|
||||
@@ -22,6 +23,7 @@ export const WsOut = t.Object({
|
||||
});
|
||||
export type TWsOut = typeof WsOut.static;
|
||||
export const WsIn = t.Union([
|
||||
t.Object({ name: t.String() }),
|
||||
t.Object({ ready: t.Boolean() }),
|
||||
t.Object({ action: t.Any() }),
|
||||
t.Object({ quit: t.Literal(true) }),
|
||||
@@ -55,6 +57,7 @@ type TablePayload<
|
||||
>;
|
||||
gameConfig: Property<GameConfig | null, any>;
|
||||
results: Property<GameResult, any>;
|
||||
playerNames: Property<{ [key: string]: string }, any>;
|
||||
};
|
||||
player: {
|
||||
[key: string]: {
|
||||
@@ -133,11 +136,12 @@ export const liveTable = <
|
||||
});
|
||||
});
|
||||
|
||||
const { ready, action, quit } = partition(
|
||||
["ready", "action", "quit"],
|
||||
const { name, ready, action, quit } = partition(
|
||||
["name", "ready", "action", "quit"],
|
||||
messages
|
||||
) as unknown as {
|
||||
// yuck
|
||||
name: Observable<Attributed & { name: string }, any>;
|
||||
ready: Observable<Attributed & { ready: boolean }, any>;
|
||||
action: Observable<Attributed & { action: GameAction }, any>;
|
||||
quit: Observable<Attributed, any>;
|
||||
@@ -145,17 +149,23 @@ export const liveTable = <
|
||||
|
||||
const gameEnds = quit.map((_) => null);
|
||||
|
||||
const gameIsActivePool = pool<boolean, any>();
|
||||
const gameIsActive = merge([
|
||||
constant(false),
|
||||
gameIsActivePool,
|
||||
]).toProperty();
|
||||
|
||||
const playersReady = multiScan(
|
||||
null as {
|
||||
[key: string]: boolean;
|
||||
} | null,
|
||||
[
|
||||
playersPresent, // TODO: filter to only outside active games
|
||||
playersPresent.filterBy(invert(gameIsActive)),
|
||||
(prev, players: ValueWithin<typeof playersPresent>) =>
|
||||
Object.fromEntries(players.map((p) => [p, prev?.[p] ?? false])),
|
||||
],
|
||||
[
|
||||
ready, // TODO: filter to only outside active games
|
||||
ready.filterBy(invert(gameIsActive)),
|
||||
(prev, evt: ValueWithin<typeof ready>) =>
|
||||
prev?.[evt.humanKey] != null
|
||||
? {
|
||||
@@ -172,6 +182,13 @@ export const liveTable = <
|
||||
]
|
||||
).toProperty();
|
||||
|
||||
const playerNames = name
|
||||
.scan(
|
||||
(prev, n) => ({ ...prev, [n.humanKey]: n.name }),
|
||||
{} as { [key: string]: string }
|
||||
)
|
||||
.toProperty();
|
||||
|
||||
const gameStarts = playersReady
|
||||
.filter(
|
||||
(pr) =>
|
||||
@@ -194,12 +211,6 @@ export const liveTable = <
|
||||
const resultsPool = pool<GameResult | null, any>();
|
||||
const results = merge([constant(null), resultsPool]).toProperty();
|
||||
|
||||
const gameIsActivePool = pool<boolean, any>();
|
||||
const gameIsActive = merge([
|
||||
constant(false),
|
||||
gameIsActivePool,
|
||||
]).toProperty();
|
||||
|
||||
const gameState = multiScan(
|
||||
null as GameState | null,
|
||||
[
|
||||
@@ -270,6 +281,7 @@ export const liveTable = <
|
||||
playersReady,
|
||||
gameConfig,
|
||||
results,
|
||||
playerNames,
|
||||
},
|
||||
player: playerStreams,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user