From e9c73ae99804c1766230bda94f9f732f4492f0a1 Mon Sep 17 00:00:00 2001 From: Tangent Wantwight Date: Sun, 17 May 2020 23:47:50 -0400 Subject: [PATCH] Implement connection to websocket server --- package-lock.json | 8 +++++++ package.json | 1 + plan.txt | 3 +++ src/ecs/Data.ts | 11 ++++++++++ src/index.ts | 10 +++++---- src/net/Connection.ts | 50 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 src/net/Connection.ts diff --git a/package-lock.json b/package-lock.json index c062a76..5d0cb22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2685,6 +2685,14 @@ "callbag-share": "^1.1.1" } }, + "callbag-create": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/callbag-create/-/callbag-create-2.1.0.tgz", + "integrity": "sha512-ypHk+Pdqq0Cmgb7+kszctTHWuqLEX1dTNL0BMWld68ARtEtbGMnikzTY5A4oWc1tgZGixtjCx5cpc3l5aUyUAg==", + "requires": { + "callbag": "1.2.0" + } + }, "callbag-map": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/callbag-map/-/callbag-map-1.1.0.tgz", diff --git a/package.json b/package.json index d40d993..937fceb 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "dependencies": { "callbag": "^1.2.0", "callbag-animation-frames": "^2.1.0", + "callbag-create": "^2.1.0", "callbag-map": "^1.1.0", "callbag-pipe": "^1.2.0", "callbag-share": "^1.2.0", diff --git a/plan.txt b/plan.txt index b2b7e26..f671e17 100644 --- a/plan.txt +++ b/plan.txt @@ -1,5 +1,8 @@ Open: - Insecured websocket server implementation + - desynced on join + - reset on join + - sync to op on join - Cloneable RNG that goes in state (use MurmurHash3 finalizer in counter mode?) - remove all random() calls diff --git a/src/ecs/Data.ts b/src/ecs/Data.ts index 40ec0ab..1ac8265 100644 --- a/src/ecs/Data.ts +++ b/src/ecs/Data.ts @@ -1,4 +1,15 @@ +export type Jsonified = { + [K in keyof T]: JsonEncoded; +}; +export type JsonEncoded = + T extends Function ? never + : T extends Date ? string + : T extends (infer U)[] ? JsonEncoded[] + : T extends Record ? Jsonified + : T + ; + export type Store> = Record; export interface Clone { clone(): T; diff --git a/src/index.ts b/src/index.ts index 484caab..22eff75 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,8 @@ import { KeyName } from "./applet/Keyboard"; import { BindTests } from "./ecs/test"; import { Data } from "./game/GameComponents"; import { Main } from "./game/Main"; -import { LoopbackServer } from "./net/LoopbackServer"; +import { Connection } from "./net/Connection"; +import {} from "./net/LoopbackServer"; /* // Hot Module Reloading stub, if that's viable * declare const module: any; @@ -16,8 +17,9 @@ import { LoopbackServer } from "./net/LoopbackServer"; * } */ -const server = new LoopbackServer(); - -Select(".GameCanvas").forEachCanvas((c, cx, keys) => new Main(c, cx, keys, server.socket)); +Select(".GameCanvas").forEachCanvas((c, cx, keys) => { + const connection = new Connection("ws://localhost:9090/"); + new Main(c, cx, keys, connection.socket); +}); BindTests(); diff --git a/src/net/Connection.ts b/src/net/Connection.ts new file mode 100644 index 0000000..cae44c9 --- /dev/null +++ b/src/net/Connection.ts @@ -0,0 +1,50 @@ +import { Callbag, Source } from "callbag"; +import create from "callbag-create"; +import pipe from "callbag-pipe"; +import share from "callbag-share"; + +import { Jsonified } from "../ecs/Data"; +import { catchTalkback, defer, interval, makeSubject, map, merge } from "../utilities/Callbag"; +import { ClientMessage, MessageTypes, ServerMessage } from "./LockstepClient"; + +type Server = Callbag, ServerMessage>; + +/** Connection to a websocket server that handles multiple clients, for schemes where GlobalInput = LocalInput[] */ +export class Connection { + + public constructor( + private url: string + ) { } + + public readonly socket = defer(() => { + const ws = new WebSocket(this.url); + + const source: Source> = create((data, { }, close) => { + ws.onopen = () => { + // fake a HELO message & set state message until the server actually sends them + data({ t: MessageTypes.META, helo: "Websocket Server" }); + data({ t: MessageTypes.SET_STATE, u: 0, s: {} }); + }; + ws.onmessage = msg => { + const decoded: Jsonified> = JSON.parse(msg.data); + data(decoded as ServerMessage); + }; + ws.onclose = () => { + close(); + }; + + return () => { + // cleanup + ws.close(); + }; + }); + + return pipe( + source, + catchTalkback((message: ClientMessage) => { + const encoded = JSON.stringify(message); + ws.send(encoded); + }) + ); + }); +}