global chat via socket.io
authorxangelo <git@xangelo.ca>
Wed, 25 May 2022 18:54:42 +0000 (14:54 -0400)
committerxangelo <git@xangelo.ca>
Wed, 25 May 2022 18:54:42 +0000 (14:54 -0400)
All users in game are now part of the global chat system allowing them
to talk to each other.

package-lock.json
package.json
public/game.html
public/scifi.css
src/api.ts
src/lib/server.ts
src/render/chat-message.ts [new file with mode: 0644]

index b9e071942d97e02367df8ddd652bc30d14e758dd..1ebd7be36c34a7cccd9fbed3a0e26f76b3eec9cb 100644 (file)
@@ -1,10 +1,10 @@
 {
-       "name": "tick-city",
+       "name": "antares",
        "lockfileVersion": 2,
        "requires": true,
        "packages": {
                "": {
-                       "name": "tick-city",
+                       "name": "antares",
                        "dependencies": {
                                "@bull-board/api": "^3.11.0",
                                "@bull-board/express": "^3.11.0",
@@ -18,6 +18,7 @@
                                "knex": "^2.0.0",
                                "lodash": "^4.17.21",
                                "luxon": "^1.28.0",
+                               "socket.io": "^4.5.1",
                                "sqlite3": "^5.0.6",
                                "uuid": "^8.3.2"
                        },
                                "@types/redis": "^2.8.0"
                        }
                },
+               "node_modules/@types/component-emitter": {
+                       "version": "1.2.11",
+                       "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz",
+                       "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ=="
+               },
                "node_modules/@types/connect": {
                        "version": "3.4.35",
                        "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
                                "@types/node": "*"
                        }
                },
+               "node_modules/@types/cookie": {
+                       "version": "0.4.1",
+                       "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
+                       "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
+               },
+               "node_modules/@types/cors": {
+                       "version": "2.8.12",
+                       "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz",
+                       "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw=="
+               },
                "node_modules/@types/express": {
                        "version": "4.17.13",
                        "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
                                }
                        ]
                },
+               "node_modules/base64id": {
+                       "version": "2.0.0",
+                       "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
+                       "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
+                       "engines": {
+                               "node": "^4.5.0 || >= 5.9"
+                       }
+               },
                "node_modules/bcrypt": {
                        "version": "5.0.1",
                        "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz",
                                "node": "^12.20.0 || >=14"
                        }
                },
+               "node_modules/component-emitter": {
+                       "version": "1.3.0",
+                       "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+                       "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
+               },
                "node_modules/concat-map": {
                        "version": "0.0.1",
                        "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
                        "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
                        "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
                },
+               "node_modules/cors": {
+                       "version": "2.8.5",
+                       "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+                       "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+                       "dependencies": {
+                               "object-assign": "^4",
+                               "vary": "^1"
+                       },
+                       "engines": {
+                               "node": ">= 0.10"
+                       }
+               },
                "node_modules/create-require": {
                        "version": "1.1.1",
                        "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
                                "once": "^1.4.0"
                        }
                },
+               "node_modules/engine.io": {
+                       "version": "6.2.0",
+                       "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz",
+                       "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==",
+                       "dependencies": {
+                               "@types/cookie": "^0.4.1",
+                               "@types/cors": "^2.8.12",
+                               "@types/node": ">=10.0.0",
+                               "accepts": "~1.3.4",
+                               "base64id": "2.0.0",
+                               "cookie": "~0.4.1",
+                               "cors": "~2.8.5",
+                               "debug": "~4.3.1",
+                               "engine.io-parser": "~5.0.3",
+                               "ws": "~8.2.3"
+                       },
+                       "engines": {
+                               "node": ">=10.0.0"
+                       }
+               },
+               "node_modules/engine.io-parser": {
+                       "version": "5.0.4",
+                       "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
+                       "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==",
+                       "engines": {
+                               "node": ">=10.0.0"
+                       }
+               },
+               "node_modules/engine.io/node_modules/cookie": {
+                       "version": "0.4.2",
+                       "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+                       "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
+                       "engines": {
+                               "node": ">= 0.6"
+                       }
+               },
+               "node_modules/engine.io/node_modules/debug": {
+                       "version": "4.3.4",
+                       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+                       "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+                       "dependencies": {
+                               "ms": "2.1.2"
+                       },
+                       "engines": {
+                               "node": ">=6.0"
+                       },
+                       "peerDependenciesMeta": {
+                               "supports-color": {
+                                       "optional": true
+                               }
+                       }
+               },
+               "node_modules/engine.io/node_modules/ms": {
+                       "version": "2.1.2",
+                       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+                       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+               },
                "node_modules/env-paths": {
                        "version": "2.2.1",
                        "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
                                "npm": ">= 3.0.0"
                        }
                },
+               "node_modules/socket.io": {
+                       "version": "4.5.1",
+                       "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.1.tgz",
+                       "integrity": "sha512-0y9pnIso5a9i+lJmsCdtmTTgJFFSvNQKDnPQRz28mGNnxbmqYg2QPtJTLFxhymFZhAIn50eHAKzJeiNaKr+yUQ==",
+                       "dependencies": {
+                               "accepts": "~1.3.4",
+                               "base64id": "~2.0.0",
+                               "debug": "~4.3.2",
+                               "engine.io": "~6.2.0",
+                               "socket.io-adapter": "~2.4.0",
+                               "socket.io-parser": "~4.0.4"
+                       },
+                       "engines": {
+                               "node": ">=10.0.0"
+                       }
+               },
+               "node_modules/socket.io-adapter": {
+                       "version": "2.4.0",
+                       "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz",
+                       "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg=="
+               },
+               "node_modules/socket.io-parser": {
+                       "version": "4.0.4",
+                       "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz",
+                       "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==",
+                       "dependencies": {
+                               "@types/component-emitter": "^1.2.10",
+                               "component-emitter": "~1.3.0",
+                               "debug": "~4.3.1"
+                       },
+                       "engines": {
+                               "node": ">=10.0.0"
+                       }
+               },
+               "node_modules/socket.io-parser/node_modules/debug": {
+                       "version": "4.3.4",
+                       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+                       "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+                       "dependencies": {
+                               "ms": "2.1.2"
+                       },
+                       "engines": {
+                               "node": ">=6.0"
+                       },
+                       "peerDependenciesMeta": {
+                               "supports-color": {
+                                       "optional": true
+                               }
+                       }
+               },
+               "node_modules/socket.io-parser/node_modules/ms": {
+                       "version": "2.1.2",
+                       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+                       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+               },
+               "node_modules/socket.io/node_modules/debug": {
+                       "version": "4.3.4",
+                       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+                       "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+                       "dependencies": {
+                               "ms": "2.1.2"
+                       },
+                       "engines": {
+                               "node": ">=6.0"
+                       },
+                       "peerDependenciesMeta": {
+                               "supports-color": {
+                                       "optional": true
+                               }
+                       }
+               },
+               "node_modules/socket.io/node_modules/ms": {
+                       "version": "2.1.2",
+                       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+                       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+               },
                "node_modules/socks": {
                        "version": "2.6.2",
                        "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz",
                                "typedarray-to-buffer": "^3.1.5"
                        }
                },
+               "node_modules/ws": {
+                       "version": "8.2.3",
+                       "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
+                       "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
+                       "engines": {
+                               "node": ">=10.0.0"
+                       },
+                       "peerDependencies": {
+                               "bufferutil": "^4.0.1",
+                               "utf-8-validate": "^5.0.2"
+                       },
+                       "peerDependenciesMeta": {
+                               "bufferutil": {
+                                       "optional": true
+                               },
+                               "utf-8-validate": {
+                                       "optional": true
+                               }
+                       }
+               },
                "node_modules/xdg-basedir": {
                        "version": "4.0.0",
                        "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
                                "@types/redis": "^2.8.0"
                        }
                },
+               "@types/component-emitter": {
+                       "version": "1.2.11",
+                       "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz",
+                       "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ=="
+               },
                "@types/connect": {
                        "version": "3.4.35",
                        "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
                                "@types/node": "*"
                        }
                },
+               "@types/cookie": {
+                       "version": "0.4.1",
+                       "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
+                       "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
+               },
+               "@types/cors": {
+                       "version": "2.8.12",
+                       "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz",
+                       "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw=="
+               },
                "@types/express": {
                        "version": "4.17.13",
                        "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
                        "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
                        "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
                },
+               "base64id": {
+                       "version": "2.0.0",
+                       "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
+                       "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
+               },
                "bcrypt": {
                        "version": "5.0.1",
                        "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz",
                        "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz",
                        "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w=="
                },
+               "component-emitter": {
+                       "version": "1.3.0",
+                       "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+                       "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
+               },
                "concat-map": {
                        "version": "0.0.1",
                        "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
                        "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
                        "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
                },
+               "cors": {
+                       "version": "2.8.5",
+                       "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+                       "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+                       "requires": {
+                               "object-assign": "^4",
+                               "vary": "^1"
+                       }
+               },
                "create-require": {
                        "version": "1.1.1",
                        "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
                                "once": "^1.4.0"
                        }
                },
+               "engine.io": {
+                       "version": "6.2.0",
+                       "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz",
+                       "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==",
+                       "requires": {
+                               "@types/cookie": "^0.4.1",
+                               "@types/cors": "^2.8.12",
+                               "@types/node": ">=10.0.0",
+                               "accepts": "~1.3.4",
+                               "base64id": "2.0.0",
+                               "cookie": "~0.4.1",
+                               "cors": "~2.8.5",
+                               "debug": "~4.3.1",
+                               "engine.io-parser": "~5.0.3",
+                               "ws": "~8.2.3"
+                       },
+                       "dependencies": {
+                               "cookie": {
+                                       "version": "0.4.2",
+                                       "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+                                       "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
+                               },
+                               "debug": {
+                                       "version": "4.3.4",
+                                       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+                                       "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+                                       "requires": {
+                                               "ms": "2.1.2"
+                                       }
+                               },
+                               "ms": {
+                                       "version": "2.1.2",
+                                       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+                                       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+                               }
+                       }
+               },
+               "engine.io-parser": {
+                       "version": "5.0.4",
+                       "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
+                       "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg=="
+               },
                "env-paths": {
                        "version": "2.2.1",
                        "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
                        "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
                        "optional": true
                },
+               "socket.io": {
+                       "version": "4.5.1",
+                       "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.1.tgz",
+                       "integrity": "sha512-0y9pnIso5a9i+lJmsCdtmTTgJFFSvNQKDnPQRz28mGNnxbmqYg2QPtJTLFxhymFZhAIn50eHAKzJeiNaKr+yUQ==",
+                       "requires": {
+                               "accepts": "~1.3.4",
+                               "base64id": "~2.0.0",
+                               "debug": "~4.3.2",
+                               "engine.io": "~6.2.0",
+                               "socket.io-adapter": "~2.4.0",
+                               "socket.io-parser": "~4.0.4"
+                       },
+                       "dependencies": {
+                               "debug": {
+                                       "version": "4.3.4",
+                                       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+                                       "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+                                       "requires": {
+                                               "ms": "2.1.2"
+                                       }
+                               },
+                               "ms": {
+                                       "version": "2.1.2",
+                                       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+                                       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+                               }
+                       }
+               },
+               "socket.io-adapter": {
+                       "version": "2.4.0",
+                       "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz",
+                       "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg=="
+               },
+               "socket.io-parser": {
+                       "version": "4.0.4",
+                       "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz",
+                       "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==",
+                       "requires": {
+                               "@types/component-emitter": "^1.2.10",
+                               "component-emitter": "~1.3.0",
+                               "debug": "~4.3.1"
+                       },
+                       "dependencies": {
+                               "debug": {
+                                       "version": "4.3.4",
+                                       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+                                       "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+                                       "requires": {
+                                               "ms": "2.1.2"
+                                       }
+                               },
+                               "ms": {
+                                       "version": "2.1.2",
+                                       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+                                       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+                               }
+                       }
+               },
                "socks": {
                        "version": "2.6.2",
                        "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz",
                                "typedarray-to-buffer": "^3.1.5"
                        }
                },
+               "ws": {
+                       "version": "8.2.3",
+                       "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
+                       "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
+                       "requires": {}
+               },
                "xdg-basedir": {
                        "version": "4.0.0",
                        "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
index 7deac18c0431a220a5a6461300443c6938ff026e..75cb8546b985e10f7cf5e1487d220de7f9a97d39 100644 (file)
@@ -20,6 +20,7 @@
                "knex": "^2.0.0",
                "lodash": "^4.17.21",
                "luxon": "^1.28.0",
+               "socket.io": "^4.5.1",
                "sqlite3": "^5.0.6",
                "uuid": "^8.3.2"
        },
index 054be5f4d59ef6721bafb729803d22bced34f6d1..b288922779efdf977b856fb89516840fddf0104b 100644 (file)
@@ -11,6 +11,7 @@
     <script src="https://unpkg.com/htmx.org@1.7.0"
         integrity="sha384-EzBXYPt0/T6gxNp0nuPtLkmRpmDBbjg6WmCUZRLXBBwYYmwAUxzlSGej0ARHX0Bo" crossorigin="anonymous"
         defer></script>
+    <script src="/socket.io/socket.io.js"></script>
     <link rel="stylesheet" type="text/css" href="https://unpkg.com/augmented-ui@2/augmented-ui.min.css">
     <link rel="stylesheet" href="/scifi.css">
     <link rel="stylesheet" href="/stylesheet.css">
             <div id="main" data-augmented-ui="tl-clip tr-clip br-clip-x bl-clip border">
 
             </div>
+            <div id="chat" data-augmented-ui="tl-2-clip-y tr-clip-x border">
+              <div id="chat-messages"></div>
+              <form id="chat-form" hx-post="/chat" class="row">
+                <input type="text" name="message" id="chat-input" class="col">
+                <button type="submit" class="col">Send</button>
+              </form>
+            </div>
         </div>
     </div>
     <footer>
         A project by <a href="https://xangelo.ca">xangelo</a>
     </footer>
+    <script>
+      const ws= io();
+      ws.on('/chat-message', msg => {
+              document.querySelector('#chat-form').reset();
+              const $el = document.querySelector('#chat-messages');
+              $el.innerHTML = msg + $el.innerHTML;
+            });
+    </script>
 </body>
 </html>
index 3c6c0b732baf7b06f368ff20c397cc12b78a807f..4dc0085d4cdd56aa6f0de71c2e1b05449db8dc8a 100644 (file)
@@ -6,6 +6,7 @@
     --green-border: #32821c;
     --red-border: #821c1c;
     --red-bg: #381818;
+    --hl-text: #6ac9db;
 }
 
 input {
@@ -37,7 +38,7 @@ h1, h2, h3 {
     border-bottom-width: 2px;
     padding-left: 10px;
     margin-top: 0;
-    color :#6ac9db;
+    color: var(--hl-text);
     text-shadow: 0 0 2px #6ac9db;
 }
 h1 {
@@ -332,3 +333,43 @@ form > div {
 .rate-of-change.danger::before {
   content: '\25BC ';
 }
+
+#chat {
+  margin-top: 2rem;
+  background-color: var(--page-bg);
+  padding: 1rem;
+  --aug-border-all: 1px;
+  --aug-border-bg: var(--border);
+}
+
+#chat-messages {
+  height: 200px;
+  overflow: auto;
+  padding: 0 1rem;
+}
+.chat-message {
+  padding: 4px;
+}
+.chat-message:nth-child(even) {
+  background-color: #0d2329;
+}
+.chat-message .from {
+  color: var(--hl-text);
+}
+.chat-message .sent_at {
+  color: #444;
+  font-size: 0.6rem;
+}
+#chat-form {
+  margin: 0;
+}
+#chat-form .col {
+  margin: 0;
+}
+#chat-form input {
+    flex-grow: 3;
+    flex-basis: 100%;
+}
+#chat-form button {
+  max-width: 150px;
+}
index 2cca2896156d71946885de1af5dd6747b3b89dee..87569fe59f10a6935c679a69663432998fc7bbf8 100644 (file)
@@ -18,13 +18,16 @@ import _ from 'lodash';
 import { renderCost } from './render/costs';
 import {renderMailroom, renderMessage} from './render/mail';
 import {topbar} from './render/topbar';
+import {renderPublicChatMessage} from './render/chat-message';
 
-const server = new HttpServer(config.API_PORT);
 
+const server = new HttpServer(config.API_PORT);
 const accountRepo = new AccountRepository();
 const cityRepo = new CityRepository();
 const mailRepo = new MailRepository();
 
+const msgBuffer: string[] = [];
+
 createBullBoard({
        queues: [
                new BullAdapter(tick.queue),
@@ -348,6 +351,29 @@ server.get<void, string>('/attacks/outgoing', async req => {
        return listOperations(attacks);
 });
 
+server.post<{body: {message: string}}, void>('/chat', async req => {
+  const acct = await accountRepo.validate(req.authInfo.accountId, req.authInfo.token);
+  const now = Date.now();
+
+  console.log(acct.username, req.body.message, now);
+
+  const msg = renderPublicChatMessage(acct.username, req.body.message);
+  server.ws.emit('/chat-message', msg);
+  msgBuffer.unshift(msg);
+  while(msgBuffer.length > 30) {
+    msgBuffer.pop();
+  }
+});
+
+server.ws.on('connection', async socket => {
+  const auth = server.authFromUrl(socket.request.headers['referer']);
+  const acct = await accountRepo.validate(auth.authInfo.accountId, auth.authInfo.token);
+
+  server.ws.emit('/chat-message', msgBuffer.join("\n"));
+
+  server.ws.emit('/chat-message', renderPublicChatMessage('Server', `${acct.username} logged in`));
+
+});
 
 server.start();
 
index 00f41fa2b36da892f6e8b55bcaba1339d6a6d00a..e27981298d64701ae4a7fcff617c09fede624595 100644 (file)
@@ -1,10 +1,11 @@
 import express, { Request, Response } from 'express';
 import { join } from 'path';
 import { isString } from 'lodash';
-import { HttpError } from '../errors';
 import { merge } from 'lodash';
 import bodyParser from 'body-parser';
 import { ExpressAdapter } from '@bull-board/express';
+import http from 'http';
+import { Server } from 'socket.io';
 
 type AuthInfo = {
        authInfo: { 
@@ -17,13 +18,17 @@ export type HttpHandler<I, O> = (params: I & AuthInfo, rawReq: Request, rawRes:
 
 export class HttpServer {
        server: express.Application;
+  http: http.Server;
+  ws: Server;
        port: string | number;
        bullAdapter: ExpressAdapter;
        constructor(port: string | number) {
                this.port = port;
+    this.server = express();
                this.bullAdapter = new ExpressAdapter()
-               this.server = express();
                this.configureMiddleWare();
+    this.http = http.createServer(this.server);
+    this.ws = new Server(this.http);
        }
 
        configureMiddleWare() {
@@ -35,27 +40,33 @@ export class HttpServer {
                this.server.use('/admin/queues', this.bullAdapter.getRouter());
        }
 
+  authFromUrl(raw: string): {authInfo: {token: string, accountId: string}} {
+    let url = new URL('http://localhost.com?id=null&token=null');
+    try {
+      url = new URL(raw);
+      const authInfo = {
+        authInfo: {
+          token: url.searchParams.get('token'),
+          accountId: url.searchParams.get('id')
+        }
+      };
+
+      return authInfo;
+    }
+    catch(e) {
+      console.log(e);
+    }
+  }
+
        wrap<I, O>(handler: HttpHandler<I, O>, hxEvents: string) {
+    const self = this;
                return async function (req: Request, res: Response) {
                        try {
                                const start = Date.now();
                                console.log(`Req: ${req.method.toUpperCase()} ${req.path}`);
 
                                // extract hx game vars (token, id);
-                               let url = new URL('http://localhost.com?id=null&token=null');
-                               try {
-                                       url = new URL(req.headers['hx-current-url'].toString());
-                               }
-                               catch(e) {
-                                       console.log(e);
-                               }
-                               const headerData = {
-                                       authInfo: {
-                                               token: url.searchParams.get('token'),
-                                               accountId: url.searchParams.get('id')
-                                       }
-                               };
-
+        const headerData = self.authFromUrl(req.headers['hx-current-url'].toString());
                                const output: O = await handler(merge(req, headerData) as unknown as (I & AuthInfo), req, res);
                                console.log(`Runtime: ${Date.now() - start}ms`);
 
@@ -95,6 +106,6 @@ export class HttpServer {
 
        start(fn?: any): void {
                console.log(`Listening on port ${this.port}`);
-               this.server.listen(this.port, fn?.bind(this));
+               this.http.listen(this.port, fn?.bind(this));
        }
 }
diff --git a/src/render/chat-message.ts b/src/render/chat-message.ts
new file mode 100644 (file)
index 0000000..bf472de
--- /dev/null
@@ -0,0 +1,11 @@
+export function renderPublicChatMessage(from: string, message: string): string {
+  const date = new Date();
+  return `
+  <div class="chat-message">
+  <span class="from">${from}</span>
+  <span class="sent_at">${date.getHours()}:${date.getMinutes()}</span>
+  <span class="message">${message}</span>
+  </div>
+  `;
+
+}