-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add simple coffee machine example for TypeScript docs
- Loading branch information
Showing
2 changed files
with
300 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
/* eslint-disable no-console */ | ||
import { exit, stdin, stdout } from "process"; | ||
import { createInterface } from "readline/promises"; | ||
// eslint-disable-next-line import/no-extraneous-dependencies | ||
import { JSONParser } from "@streamparser/json-whatwg"; | ||
// eslint-disable-next-line import/no-extraneous-dependencies | ||
import { WebSocket } from "ws"; | ||
import { ILocalContext, IRemoteContext, Registry } from "../index"; | ||
|
||
class RemoteControl { | ||
// eslint-disable-next-line class-methods-use-this | ||
async SetCoffeeMachineBrewing(ctx: ILocalContext, brewing: boolean) { | ||
if (brewing) { | ||
console.log("Coffee machine is now brewing"); | ||
} else { | ||
console.log("Coffee machine has stopped brewing"); | ||
} | ||
} | ||
} | ||
|
||
class CoffeeMachine { | ||
// eslint-disable-next-line class-methods-use-this | ||
async BrewCoffee( | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
ctx: IRemoteContext, | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
variant: string, | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
size: number | ||
): Promise<number> { | ||
return 0; | ||
} | ||
} | ||
|
||
let clients = 0; | ||
|
||
const registry = new Registry( | ||
new RemoteControl(), | ||
new CoffeeMachine(), | ||
|
||
{ | ||
onClientConnect: () => { | ||
clients++; | ||
|
||
console.log(clients, "coffee machines connected"); | ||
}, | ||
onClientDisconnect: () => { | ||
clients--; | ||
|
||
console.log(clients, "coffee machines connected"); | ||
}, | ||
} | ||
); | ||
|
||
(async () => { | ||
console.log(`Enter one of the following numbers followed by <ENTER> to brew a coffee: | ||
- 1: Brew small Cafè Latte | ||
- 2: Brew large Cafè Latte | ||
- 3: Brew small Americano | ||
- 4: Brew large Americano`); | ||
|
||
const rl = createInterface({ input: stdin, output: stdout }); | ||
|
||
// eslint-disable-next-line no-constant-condition | ||
while (true) { | ||
const line = | ||
// eslint-disable-next-line no-await-in-loop | ||
await rl.question(""); | ||
|
||
// eslint-disable-next-line no-await-in-loop | ||
await registry.forRemotes(async (remoteID, remote) => { | ||
switch (line) { | ||
case "1": | ||
case "2": | ||
try { | ||
// eslint-disable-next-line no-await-in-loop | ||
const res = await remote.BrewCoffee( | ||
undefined, | ||
"latte", | ||
line === "1" ? 100 : 200 | ||
); | ||
|
||
console.log("Remaining water:", res, "ml"); | ||
} catch (e) { | ||
console.error(`Couldn't brew coffee: ${e}`); | ||
} | ||
|
||
break; | ||
|
||
case "3": | ||
case "4": | ||
try { | ||
// eslint-disable-next-line no-await-in-loop | ||
const res = await remote.BrewCoffee( | ||
undefined, | ||
"americano", | ||
line === "3" ? 100 : 200 | ||
); | ||
|
||
console.log("Remaining water:", res, "ml"); | ||
} catch (e) { | ||
console.error(`Couldn't brew coffee: ${e}`); | ||
} | ||
|
||
break; | ||
|
||
default: | ||
console.log(`Unknown letter ${line}, ignoring input`); | ||
} | ||
}); | ||
} | ||
})(); | ||
|
||
const socket = new WebSocket("ws://localhost:1337"); | ||
|
||
socket.addEventListener("error", (e) => { | ||
console.error("Disconnected with error:", e); | ||
|
||
exit(1); | ||
}); | ||
socket.addEventListener("close", () => exit(0)); | ||
|
||
await new Promise<void>((res, rej) => { | ||
socket.addEventListener("open", () => res()); | ||
socket.addEventListener("error", rej); | ||
}); | ||
|
||
const encoder = new WritableStream({ | ||
write(chunk) { | ||
socket.send(JSON.stringify(chunk)); | ||
}, | ||
}); | ||
|
||
const parser = new JSONParser({ | ||
paths: ["$"], | ||
separator: "", | ||
}); | ||
const parserWriter = parser.writable.getWriter(); | ||
const parserReader = parser.readable.getReader(); | ||
const decoder = new ReadableStream({ | ||
start(controller) { | ||
parserReader | ||
.read() | ||
.then(async function process({ done, value }) { | ||
if (done) { | ||
controller.close(); | ||
|
||
return; | ||
} | ||
|
||
controller.enqueue(value?.value); | ||
|
||
parserReader | ||
.read() | ||
.then(process) | ||
.catch((e) => controller.error(e)); | ||
}) | ||
.catch((e) => controller.error(e)); | ||
}, | ||
}); | ||
socket.addEventListener("message", (m) => parserWriter.write(m.data as string)); | ||
socket.addEventListener("close", () => { | ||
parserReader.cancel(); | ||
parserWriter.abort(); | ||
}); | ||
|
||
registry.linkStream( | ||
encoder, | ||
decoder, | ||
|
||
(v) => v, | ||
(v) => v | ||
); | ||
|
||
console.log("Connected to localhost:1337"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/* eslint-disable no-console */ | ||
// eslint-disable-next-line import/no-extraneous-dependencies | ||
import { JSONParser } from "@streamparser/json-whatwg"; | ||
// eslint-disable-next-line import/no-extraneous-dependencies | ||
import { WebSocketServer } from "ws"; | ||
import { ILocalContext, IRemoteContext, Registry } from "../index"; | ||
|
||
class CoffeeMachine { | ||
constructor(private supportedVariants: string[], private waterLevel: number) { | ||
this.BrewCoffee = this.BrewCoffee.bind(this); | ||
} | ||
|
||
async BrewCoffee( | ||
ctx: ILocalContext, | ||
variant: string, | ||
size: number | ||
): Promise<number> { | ||
if (!this.supportedVariants.includes(variant)) { | ||
throw new Error("unsupported variant"); | ||
} | ||
|
||
if (this.waterLevel - size < 0) { | ||
throw new Error("not enough water"); | ||
} | ||
|
||
console.log("Brewing coffee variant", variant, "in size", size, "ml"); | ||
|
||
await new Promise((r) => { | ||
setTimeout(r, 5000); | ||
}); | ||
|
||
this.waterLevel -= size; | ||
|
||
return this.waterLevel; | ||
} | ||
} | ||
|
||
class RemoteControl { | ||
// eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function | ||
async SetCoffeeMachineBrewing(ctx: IRemoteContext, brewing: boolean) {} | ||
} | ||
|
||
let clients = 0; | ||
|
||
const registry = new Registry( | ||
new CoffeeMachine(["latte", "americano"], 1000), | ||
new RemoteControl(), | ||
|
||
{ | ||
onClientConnect: () => { | ||
clients++; | ||
|
||
console.log(clients, "remote controls connected"); | ||
}, | ||
onClientDisconnect: () => { | ||
clients--; | ||
|
||
console.log(clients, "remote controls connected"); | ||
}, | ||
} | ||
); | ||
|
||
const server = new WebSocketServer({ | ||
host: "localhost", | ||
port: 1337, | ||
}); | ||
|
||
server.on("connection", (socket) => { | ||
socket.addEventListener("error", (e) => { | ||
console.error("Remote control disconnected with error:", e); | ||
}); | ||
|
||
const encoder = new WritableStream({ | ||
write(chunk) { | ||
socket.send(JSON.stringify(chunk)); | ||
}, | ||
}); | ||
|
||
const parser = new JSONParser({ | ||
paths: ["$"], | ||
separator: "", | ||
}); | ||
const parserWriter = parser.writable.getWriter(); | ||
const parserReader = parser.readable.getReader(); | ||
const decoder = new ReadableStream({ | ||
start(controller) { | ||
parserReader | ||
.read() | ||
.then(async function process({ done, value }) { | ||
if (done) { | ||
controller.close(); | ||
|
||
return; | ||
} | ||
|
||
controller.enqueue(value?.value); | ||
|
||
parserReader | ||
.read() | ||
.then(process) | ||
.catch((e) => controller.error(e)); | ||
}) | ||
.catch((e) => controller.error(e)); | ||
}, | ||
}); | ||
socket.addEventListener("message", (m) => | ||
parserWriter.write(m.data as string) | ||
); | ||
socket.addEventListener("close", () => { | ||
parserReader.cancel(); | ||
parserWriter.abort(); | ||
}); | ||
|
||
registry.linkStream( | ||
encoder, | ||
decoder, | ||
|
||
(v) => v, | ||
(v) => v | ||
); | ||
}); | ||
|
||
console.log("Listening on localhost:1337"); |