From 8a1c0cd6d42120246d27eb264a4c13856030e5c8 Mon Sep 17 00:00:00 2001 From: Christophe Rosset Date: Sat, 2 Mar 2024 20:39:12 +0100 Subject: [PATCH] refactor(*): feedback review from @Mouvedia https://github.com/Mouvedia/snake-pipe-rust/pull/1 --- .gitignore | 4 ++++ CONTRIBUTING.md | 2 +- LICENSE | 7 +++++++ README.md | 20 ++++++++++---------- RECORDING_NOTES.md | 2 +- node-helpers/dev-server-sse/index.ts | 27 +++++++++++++++++---------- node-helpers/dev-server-sse/server.ts | 2 +- node-helpers/package.json | 4 ++-- package-lock.json | 2 +- package.json | 2 +- src/common.rs | 4 ++-- src/main.rs | 6 +++--- 12 files changed, 50 insertions(+), 32 deletions(-) create mode 100644 LICENSE diff --git a/.gitignore b/.gitignore index 9dcad34..cc2647d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# rust /target render.out + +# nodejs node_modules +dist diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e0f79cc..8b9c48e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,7 +20,7 @@ To run: ## JavaScript -The [`snakepipe render-browser`](./README.md#-you-can-mirror-your-playing-terminal-into-another-one-through-http) command launches a rust http server that serves some JavaScript code that connects to server-sent-events and renders the game inside the browser. +The [`snakepipe render-browser`](./README.md#-you-can-mirror-your-playing-terminal-into-another-one-through-http) command launches a rust http server that serves some JavaScript code that connects to server-sent events and renders the game inside the browser. The source code for the renderers is available at [`static/renderers`](static/renderers). diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ba01647 --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ +Copyright (C) 2024 Christophe Rosset + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index da1addc..1de1760 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ This one follows the [unix philosophy](https://en.wikipedia.org/wiki/Unix_philos - `snakepipe gamestate` accepts user inputs, calculates the state of the game and writes it to `stdout` - `snakepipe render` reads the state of the game from `stdin` and renders it on the terminal - `snakepipe throttle` reads a pre-recorded game from `stdin` and writes to `stdout` each tick so that `snakepipe render` can pick it up -- `snakepipe render-browser` spawns a server and sends `stdin` via server-sent-events to a JavaScript renderer in your browser -- `snakepipe stream-sse` connects to the server spawned by `render-browser` and streams server-sent-events back to the terminal +- `snakepipe render-browser` spawns a server and sends `stdin` via server-sent events to a JavaScript renderer in your browser +- `snakepipe stream-sse` connects to the server spawned by `render-browser` and streams server-sent events back to the terminal - `snakepipe pipeline ` prints out the most common pipelines (combinations of commands), so that you could directly `pbcopy`/paste them That way: @@ -24,7 +24,7 @@ That way: ## Motivation -I've already done [a few rust projects](http://labs.topheman.com) (with WebAssembly or bevy), however, I wanted something that needs to deal directly with: +I've already done [a few rust projects](http://labs.topheman.com) (with WebAssembly or [bevy](https://github.com/topheman/bevy-rust-wasm-experiments)), however, I wanted something that needs to deal directly with: - I/O - parsing @@ -86,7 +86,7 @@ snakepipe gamestate|tee /tmp/snakepipe.sock|snakepipe render snakepipe gamestate|snakepipe render-browser|snakepipe render ``` -Then open [http://localhost:8080](http://localhost:8080). You'll be able to switch between renderers in your browser as you are playing in your terminal (thanks to server-sent-events). +Then open [http://localhost:8080](http://localhost:8080). You'll be able to switch between renderers in your browser as you are playing in your terminal (thanks to server-sent events). ### 🖼 You can mirror your playing terminal into another one, through http @@ -95,14 +95,14 @@ Open two terminals: ```sh # main terminal: # - accepts user inputs -# - spawns an http server that streams stdin to server-sent-events +# - spawns an http server that streams stdin to server-sent events # - renders the game to the terminal so you can play snakepipe gamestate|snakepipe render-browser|snakepipe render ``` ```sh # mirroring terminal (not necessary the same device, only need to be on the same network): -# - connects to the http server and streams server-sent-events to sdout +# - connects to the http server and streams server-sent events to sdout # - render the gamestate retrieved from the server snakepipe stream-sse|snakepipe render ``` @@ -124,8 +124,8 @@ Commands: gamestate Accepts user inputs (arrow keys to control the snake) and outputs the state of the game to stdout render Reads gamestate from stdin and renders the game on your terminal throttle Reads stdin line by line and outputs each line on stdout each `frame_duration` ms (usefull for replaying a file) - render-browser Let's you render the game in your browser at http://localhost:8080 by spawning a server and sending stdin via server-sent-events to a JavaScript renderer - stream-sse Connects to the server spawned by `render-browser` and streams server-sent-events back to the terminal + render-browser Let's you render the game in your browser at http://localhost:8080 by spawning a server and sending stdin via server-sent events to a JavaScript renderer + stream-sse Connects to the server spawned by `render-browser` and streams server-sent events back to the terminal help Print this message or the help of the given subcommand(s) Options: @@ -174,7 +174,7 @@ Options:
snakepipe render-browser --help
-Let's you render the game in your browser at http://localhost:8080 by spawning a server and sending stdin via server-sent-events to a JavaScript renderer
+Let's you render the game in your browser at http://localhost:8080 by spawning a server and sending stdin via server-sent events to a JavaScript renderer
 
 Usage: snakepipe render-browser [OPTIONS]
 
@@ -186,7 +186,7 @@ Options:
 
snakepipe stream-sse --help
-Connects to the server spawned by `render-browser` and streams server-sent-events back to the terminal
+Connects to the server spawned by `render-browser` and streams server-sent events back to the terminal
 
 Usage: snakepipe stream-sse [OPTIONS]
 
diff --git a/RECORDING_NOTES.md b/RECORDING_NOTES.md
index b6f0c8e..d0d3a96 100644
--- a/RECORDING_NOTES.md
+++ b/RECORDING_NOTES.md
@@ -55,7 +55,7 @@ snakepipe gamestate|snakepipe render
 ---
 
 ```sh
-# Record a party by saving the output of gamestate command to a file with the built-in tee utility
+# Record a party by saving the output of the gamestate command to a file with the built-in tee utility
 
 snakepipe gamestate|tee /tmp/snake-output|snakepipe render
 ```
diff --git a/node-helpers/dev-server-sse/index.ts b/node-helpers/dev-server-sse/index.ts
index b4e37a0..6628021 100644
--- a/node-helpers/dev-server-sse/index.ts
+++ b/node-helpers/dev-server-sse/index.ts
@@ -1,21 +1,32 @@
 import path from 'node:path';
 import fs from 'node:fs/promises';
-import url from 'url';
+import { setTimeout } from 'node:timers/promises';
+import url from 'node:url';
+
 import localIpUrl from 'local-ip-url';
 import { parseGameStateFromAsyncIterator, InitOptions } from 'snakepipe';
 
 import { makeServer } from './server.js'
 
-
+/**
+ * `__dirname` doesn't exist in esm, you need to create it.
+ *
+ * We could improve the code bellow with just `import.meta.dirname` - it needs at least node 20.11.
+ * For the moment keeping retrocompatibility with all node 20 versions.
+ *
+ * Source: https://nodejs.org/docs/v20.11.0/api/esm.html#importmetadirname
+ */
 const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); // __dirname for esm
 
+const ExitCodeUsageError = 64; // The command was used incorrectly, e.g., with the wrong number of arguments, a bad flag, a bad syntax in a parameter, etc.
+
 if (process.argv.length < 3) {
   console.log("You must pass the path of the file containing the recording of a game.");
-  process.exit(64);
+  process.exit(ExitCodeUsageError);
 }
 if (process.argv.length > 3) {
-  console.log("Too much arguments passed");
-  process.exit(64);
+  console.log("Too many arguments passed");
+  process.exit(ExitCodeUsageError);
 }
 
 const [filePathOfGameRecording] = process.argv.slice(2, 3);
@@ -30,17 +41,13 @@ if (path.isAbsolute(filePathOfGameRecording)) {
 
 main(resolvedFilePathOfGameRecording);
 
-function timeout(ms: number) {
-  return new Promise(resolve => setTimeout(resolve, ms));
-}
-
 async function* infiniteAsyncGeneratorFromArrayString(input: Array, delay = 120) {
   let currentIndex = 0;
   yield input[currentIndex];
   while (true) {
     currentIndex++;
     if (input[currentIndex]?.trim()) {
-      await timeout(120);
+      await setTimeout(delay);
       yield input[currentIndex]
     }
     else {
diff --git a/node-helpers/dev-server-sse/server.ts b/node-helpers/dev-server-sse/server.ts
index 4292fd4..e042222 100644
--- a/node-helpers/dev-server-sse/server.ts
+++ b/node-helpers/dev-server-sse/server.ts
@@ -50,7 +50,7 @@ export function makeServer(input: Input, staticFolder: string) {
       res.sse({ data: JSON.stringify(line) });
     }
     req.raw.on('close', () => {
-      gameEvents.off("line", listener); // if used in production with eavy traffic, consider augment `emitter.setMaxListeners()` (currently up to 11 clients in parallel)
+      gameEvents.off("line", listener); // if used in production with eavy traffic, consider increasing `emitter.setMaxListeners()` (currently up to 11 clients in parallel)
       res.sseContext.source.end();
     })
     res.sse({ data: "connected" });
diff --git a/node-helpers/package.json b/node-helpers/package.json
index d58c407..ceec01a 100644
--- a/node-helpers/package.json
+++ b/node-helpers/package.json
@@ -1,7 +1,7 @@
 {
   "name": "node-helpers",
   "version": "0.1.0",
-  "description": "Set of tools for better development of JavaScript part.",
+  "description": "Set of tools for better development of JavaScript parts.",
   "type": "module",
   "scripts": {
     "build": "tsc",
@@ -19,6 +19,6 @@
     "@fastify/static": "^7.0.1",
     "fastify": "^4.26.1",
     "fastify-sse-v2": "^3.1.2",
-    "snakepipe": "^0.1.3"
+    "snakepipe": "latest"
   }
 }
diff --git a/package-lock.json b/package-lock.json
index 690734b..b379266 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1337,7 +1337,7 @@
         "@fastify/static": "^7.0.1",
         "fastify": "^4.26.1",
         "fastify-sse-v2": "^3.1.2",
-        "snakepipe": "^0.1.3"
+        "snakepipe": "latest"
       },
       "devDependencies": {
         "local-ip-url": "^1.0.10",
diff --git a/package.json b/package.json
index 697d4db..4fe3cf5 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "snake-pipe-rust",
   "version": "0.1.0",
   "private": true,
-  "description": "You only need this part for better experience with js development, not mandadtory.",
+  "description": "You only need this part for a better experience with js development, not mandadtory.",
   "scripts": {
     "build": "npm run --workspace=node-helpers build",
     "setup": "npm run --workspace=node-helpers setup",
diff --git a/src/common.rs b/src/common.rs
index 5d8876d..da29233 100644
--- a/src/common.rs
+++ b/src/common.rs
@@ -140,7 +140,7 @@ mod tests {
     }
 
     #[test]
-    fn should_have_as_many_versions_as_it_exist() {
+    fn should_extract_all_existing_versions() {
         let mut version = HashMap::new();
         version.insert("gamestate".to_string(), "snakepipe@1.0.0(rust)".to_string());
         version.insert("throttle".to_string(), "snakepipe@1.0.0(node)".to_string());
@@ -176,7 +176,7 @@ mod tests {
     }
 
     #[test]
-    fn should_show_features_if_they_have_different_version() {
+    fn should_show_features_if_version_differs() {
         let mut versions_with_features = IndexMap::new();
         versions_with_features.insert(
             "snakepipe@1.0.0(rust)".to_string(),
diff --git a/src/main.rs b/src/main.rs
index 708f64f..b46c8f1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -50,12 +50,12 @@ enum Commands {
         #[arg(long)]
         loop_infinite: bool,
     },
-    /// Let's you render the game in your browser at http://localhost:8080 by spawning a server and sending stdin via server-sent-events to a JavaScript renderer
+    /// Let's you render the game in your browser at http://localhost:8080 by spawning a server and sending stdin via server-sent events to a JavaScript renderer
     RenderBrowser {
         #[arg(long, default_value_t = 8080)]
         port: u16,
     },
-    /// Connects to the server spawned by `render-browser` and streams server-sent-events back to the terminal
+    /// Connects to the server spawned by `render-browser` and streams server-sent events back to the terminal
     StreamSse {
         #[arg(long, default_value = "http://localhost:8080")]
         address: String,
@@ -92,7 +92,7 @@ impl Into for CliOptions<'_> {
         } else if self.width.is_some() {
             size = SizeOption {
                 width: self.width.unwrap_or(DEFAULT_WIDTH),
-                height: self.width.unwrap_or(DEFAULT_HEIGHT),
+                height: self.height.unwrap_or(DEFAULT_HEIGHT),
             }
         } else if self.fit_terminal.eq(&true) {
             let (width, height) = crossterm::terminal::size()