diff --git a/packages/client/src/components/Table.tsx b/packages/client/src/components/Table.tsx index eefa1e2..223d6a8 100644 --- a/packages/client/src/components/Table.tsx +++ b/packages/client/src/components/Table.tsx @@ -1,10 +1,20 @@ -import { Accessor, createContext, For, onCleanup, Show } from "solid-js"; +import { + Accessor, + createContext, + createEffect, + createResource, + createSignal, + For, + onCleanup, + Show, +} from "solid-js"; import { TWsIn, TWsOut } from "../../../server/src/table"; import api, { fromWebsocket } from "../api"; import { createObservable, createObservableWithInit, cx } from "../fn"; import { me } from "../profile"; import Game from "./Game"; import Player from "./Player"; +import { fromPromise } from "kefir"; export const TableContext = createContext<{ players: Accessor; @@ -13,9 +23,20 @@ export const TableContext = createContext<{ }>(); export default (props: { tableKey: string }) => { - const ws = api.ws(props).subscribe(); - const wsEvents = fromWebsocket(ws); - onCleanup(() => ws.close()); + const wsPromise = new Promise< + ReturnType["subscribe"]> + >((res) => { + const ws = api.ws(props).subscribe(); + ws.on("open", () => res(ws)); + ws.on("error", () => res(ws)); + ws.on("close", () => res(ws)); + }); + + const sendWs = (msg: TWsIn) => wsPromise.then((ws) => ws.send(msg)); + const wsEvents = fromPromise(wsPromise).flatMap((ws) => + fromWebsocket(ws) + ); + onCleanup(() => wsPromise.then((ws) => ws.close())); const presenceEvents = wsEvents.filter((evt) => evt.players != null); @@ -26,12 +47,14 @@ export default (props: { tableKey: string }) => { [] ); + const [ready, setReady] = createSignal(false); + createEffect(() => sendWs({ ready: ready() })); const view = createObservable(gameEvents.map((evt) => evt.view)); return ( ws.send(evt), + sendWs, view, players, }} @@ -83,10 +106,10 @@ export default (props: { tableKey: string }) => {
diff --git a/packages/client/src/routes/[table].tsx b/packages/client/src/routes/[table].tsx index 1b8981d..b434785 100644 --- a/packages/client/src/routes/[table].tsx +++ b/packages/client/src/routes/[table].tsx @@ -1,16 +1,18 @@ import { A, useParams } from "@solidjs/router"; import Table from "../components/Table"; +import { Show } from "solid-js"; +import { me } from "../profile"; export default () => { const { tableKey } = useParams(); return ( - <> + Back - + ); }; diff --git a/packages/server/src/api.ts b/packages/server/src/api.ts index 6fea2cb..fc08eaf 100644 --- a/packages/server/src/api.ts +++ b/packages/server/src/api.ts @@ -74,33 +74,38 @@ const api = new Elysia({ prefix: "/api" }) }, send, }) { - const table = liveTable< - SimpleConfiguration, - SimpleGameState, - SimpleAction - >(tableKey); + console.log(humanKey, "connected"); + try { + const table = liveTable< + SimpleConfiguration, + SimpleGameState, + SimpleAction + >(tableKey); - table.outputs.playersPresent.onValue((players) => - send({ players }) - ); + table.outputs.playersPresent.onValue((players) => + send({ players }) + ); - table.outputs.playersReady.onValue((readys) => - send({ playersReady: readys }) - ); + table.outputs.playersReady.onValue((readys) => + send({ playersReady: readys }) + ); - combine( - [table.outputs.gameState], - [table.outputs.gameConfig], - (state, config) => - state && - config && - getSimplePlayerView(config, state, humanKey) - ).onValue((view) => send({ view })); + combine( + [table.outputs.gameState], + [table.outputs.gameConfig], + (state, config) => + state && + config && + getSimplePlayerView(config, state, humanKey) + ).onValue((view) => send({ view })); - table.inputs.connectionChanges.emit({ - humanKey, - presence: "joined", - }); + table.inputs.connectionChanges.emit({ + humanKey, + presence: "joined", + }); + } catch (err) { + console.error(err); + } }, response: WsOut, @@ -139,6 +144,10 @@ const api = new Elysia({ prefix: "/api" }) presence: "left", }); }, + + // error(err) { + // console.error("ERROR IN WEBSOCKET", JSON.stringify(err, null, 2)); + // }, }); export default api; diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 9a9d5a3..3a4e879 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -11,9 +11,9 @@ const app = new Elysia() origin: ["http://localhost:3000", "https://games.drm.dev"], }) ) - .onRequest(({ request }) => { - console.log(request.method, request.url); - }) + // .onRequest(({ request }) => { + // console.log(request.method, request.url); + // }) .onError(({ error }) => { console.error(error); return error; diff --git a/packages/server/src/table.ts b/packages/server/src/table.ts index 38e097d..a6044a9 100644 --- a/packages/server/src/table.ts +++ b/packages/server/src/table.ts @@ -12,7 +12,7 @@ import { transform } from "./kefir-extension"; export const WsOut = t.Object({ players: t.Optional(t.Array(t.String())), - playersReady: t.Optional(t.Record(t.String(), t.String())), + playersReady: t.Optional(t.Record(t.String(), t.Boolean())), view: t.Optional(t.Any()), }); export type TWsOut = typeof WsOut.static; @@ -60,7 +60,6 @@ export const liveTable = (key: string) => { quits: Bus(), }; const { connectionChanges, readys, actions, quits } = inputs; - // ======= const playersPresent = connectionChanges @@ -97,7 +96,11 @@ export const liveTable = (key: string) => { ); const gameStarts = playersReady - .filter((pr) => Object.values(pr).every((ready) => ready)) + .filter( + (pr) => + Object.values(pr).length > 0 && + Object.values(pr).every((ready) => ready) + ) .map((_) => null); const gameConfig = playersPresent.map((players) => ({ @@ -147,9 +150,11 @@ export const liveTable = (key: string) => { // cleanup tables[key].outputs.playersPresent - .debounce(30000) + .debounce(30000, { immediate: false }) .filter((players) => players.length === 0) + .skip(1) .onValue((_) => { + console.log("DELETING LIVE TABLE"); delete tables[key]; }); }