HttpServer working with GET routes
This commit is contained in:
24
Web/WebSocket/websocket/.gitignore
vendored
Normal file
24
Web/WebSocket/websocket/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
135
Web/WebSocket/websocket/frontend/bun.lock
Normal file
135
Web/WebSocket/websocket/frontend/bun.lock
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "websocket",
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "~5.8.3",
|
||||||
|
"vite": "^7.1.7",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.10", "", { "os": "aix", "cpu": "ppc64" }, "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw=="],
|
||||||
|
|
||||||
|
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.10", "", { "os": "android", "cpu": "arm" }, "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w=="],
|
||||||
|
|
||||||
|
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.10", "", { "os": "android", "cpu": "arm64" }, "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg=="],
|
||||||
|
|
||||||
|
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.10", "", { "os": "android", "cpu": "x64" }, "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg=="],
|
||||||
|
|
||||||
|
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA=="],
|
||||||
|
|
||||||
|
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg=="],
|
||||||
|
|
||||||
|
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.10", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg=="],
|
||||||
|
|
||||||
|
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.10", "", { "os": "freebsd", "cpu": "x64" }, "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.10", "", { "os": "linux", "cpu": "arm" }, "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.10", "", { "os": "linux", "cpu": "ia32" }, "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.10", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.10", "", { "os": "linux", "cpu": "s390x" }, "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.10", "", { "os": "linux", "cpu": "x64" }, "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA=="],
|
||||||
|
|
||||||
|
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.10", "", { "os": "none", "cpu": "arm64" }, "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A=="],
|
||||||
|
|
||||||
|
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.10", "", { "os": "none", "cpu": "x64" }, "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig=="],
|
||||||
|
|
||||||
|
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.10", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw=="],
|
||||||
|
|
||||||
|
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.10", "", { "os": "openbsd", "cpu": "x64" }, "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw=="],
|
||||||
|
|
||||||
|
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.10", "", { "os": "none", "cpu": "arm64" }, "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag=="],
|
||||||
|
|
||||||
|
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.10", "", { "os": "sunos", "cpu": "x64" }, "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.10", "", { "os": "win32", "cpu": "ia32" }, "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.10", "", { "os": "win32", "cpu": "x64" }, "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.52.3", "", { "os": "android", "cpu": "arm" }, "sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.52.3", "", { "os": "android", "cpu": "arm64" }, "sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.52.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.52.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.52.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.52.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.52.3", "", { "os": "linux", "cpu": "arm" }, "sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.52.3", "", { "os": "linux", "cpu": "arm" }, "sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.52.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.52.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.52.3", "", { "os": "linux", "cpu": "none" }, "sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.52.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.52.3", "", { "os": "linux", "cpu": "none" }, "sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.52.3", "", { "os": "linux", "cpu": "none" }, "sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.52.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.52.3", "", { "os": "linux", "cpu": "x64" }, "sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.52.3", "", { "os": "linux", "cpu": "x64" }, "sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.52.3", "", { "os": "none", "cpu": "arm64" }, "sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.52.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.52.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.52.3", "", { "os": "win32", "cpu": "x64" }, "sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.52.3", "", { "os": "win32", "cpu": "x64" }, "sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA=="],
|
||||||
|
|
||||||
|
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||||
|
|
||||||
|
"esbuild": ["esbuild@0.25.10", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.10", "@esbuild/android-arm": "0.25.10", "@esbuild/android-arm64": "0.25.10", "@esbuild/android-x64": "0.25.10", "@esbuild/darwin-arm64": "0.25.10", "@esbuild/darwin-x64": "0.25.10", "@esbuild/freebsd-arm64": "0.25.10", "@esbuild/freebsd-x64": "0.25.10", "@esbuild/linux-arm": "0.25.10", "@esbuild/linux-arm64": "0.25.10", "@esbuild/linux-ia32": "0.25.10", "@esbuild/linux-loong64": "0.25.10", "@esbuild/linux-mips64el": "0.25.10", "@esbuild/linux-ppc64": "0.25.10", "@esbuild/linux-riscv64": "0.25.10", "@esbuild/linux-s390x": "0.25.10", "@esbuild/linux-x64": "0.25.10", "@esbuild/netbsd-arm64": "0.25.10", "@esbuild/netbsd-x64": "0.25.10", "@esbuild/openbsd-arm64": "0.25.10", "@esbuild/openbsd-x64": "0.25.10", "@esbuild/openharmony-arm64": "0.25.10", "@esbuild/sunos-x64": "0.25.10", "@esbuild/win32-arm64": "0.25.10", "@esbuild/win32-ia32": "0.25.10", "@esbuild/win32-x64": "0.25.10" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ=="],
|
||||||
|
|
||||||
|
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
||||||
|
|
||||||
|
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||||
|
|
||||||
|
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||||
|
|
||||||
|
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||||
|
|
||||||
|
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
||||||
|
|
||||||
|
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
||||||
|
|
||||||
|
"rollup": ["rollup@4.52.3", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.52.3", "@rollup/rollup-android-arm64": "4.52.3", "@rollup/rollup-darwin-arm64": "4.52.3", "@rollup/rollup-darwin-x64": "4.52.3", "@rollup/rollup-freebsd-arm64": "4.52.3", "@rollup/rollup-freebsd-x64": "4.52.3", "@rollup/rollup-linux-arm-gnueabihf": "4.52.3", "@rollup/rollup-linux-arm-musleabihf": "4.52.3", "@rollup/rollup-linux-arm64-gnu": "4.52.3", "@rollup/rollup-linux-arm64-musl": "4.52.3", "@rollup/rollup-linux-loong64-gnu": "4.52.3", "@rollup/rollup-linux-ppc64-gnu": "4.52.3", "@rollup/rollup-linux-riscv64-gnu": "4.52.3", "@rollup/rollup-linux-riscv64-musl": "4.52.3", "@rollup/rollup-linux-s390x-gnu": "4.52.3", "@rollup/rollup-linux-x64-gnu": "4.52.3", "@rollup/rollup-linux-x64-musl": "4.52.3", "@rollup/rollup-openharmony-arm64": "4.52.3", "@rollup/rollup-win32-arm64-msvc": "4.52.3", "@rollup/rollup-win32-ia32-msvc": "4.52.3", "@rollup/rollup-win32-x64-gnu": "4.52.3", "@rollup/rollup-win32-x64-msvc": "4.52.3", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A=="],
|
||||||
|
|
||||||
|
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||||
|
|
||||||
|
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
||||||
|
|
||||||
|
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||||
|
|
||||||
|
"vite": ["vite@7.1.7", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Web/WebSocket/websocket/frontend/index.html
Normal file
13
Web/WebSocket/websocket/frontend/index.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>websocket</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
324
Web/WebSocket/websocket/frontend/package-lock.json
generated
Normal file
324
Web/WebSocket/websocket/frontend/package-lock.json
generated
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
{
|
||||||
|
"name": "websocket",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "websocket",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "~5.8.3",
|
||||||
|
"vite": "^7.1.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
|
"version": "0.25.10",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||||
|
"version": "4.52.3",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@types/estree": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/esbuild": {
|
||||||
|
"version": "0.25.10",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"esbuild": "bin/esbuild"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@esbuild/aix-ppc64": "0.25.10",
|
||||||
|
"@esbuild/android-arm": "0.25.10",
|
||||||
|
"@esbuild/android-arm64": "0.25.10",
|
||||||
|
"@esbuild/android-x64": "0.25.10",
|
||||||
|
"@esbuild/darwin-arm64": "0.25.10",
|
||||||
|
"@esbuild/darwin-x64": "0.25.10",
|
||||||
|
"@esbuild/freebsd-arm64": "0.25.10",
|
||||||
|
"@esbuild/freebsd-x64": "0.25.10",
|
||||||
|
"@esbuild/linux-arm": "0.25.10",
|
||||||
|
"@esbuild/linux-arm64": "0.25.10",
|
||||||
|
"@esbuild/linux-ia32": "0.25.10",
|
||||||
|
"@esbuild/linux-loong64": "0.25.10",
|
||||||
|
"@esbuild/linux-mips64el": "0.25.10",
|
||||||
|
"@esbuild/linux-ppc64": "0.25.10",
|
||||||
|
"@esbuild/linux-riscv64": "0.25.10",
|
||||||
|
"@esbuild/linux-s390x": "0.25.10",
|
||||||
|
"@esbuild/linux-x64": "0.25.10",
|
||||||
|
"@esbuild/netbsd-arm64": "0.25.10",
|
||||||
|
"@esbuild/netbsd-x64": "0.25.10",
|
||||||
|
"@esbuild/openbsd-arm64": "0.25.10",
|
||||||
|
"@esbuild/openbsd-x64": "0.25.10",
|
||||||
|
"@esbuild/openharmony-arm64": "0.25.10",
|
||||||
|
"@esbuild/sunos-x64": "0.25.10",
|
||||||
|
"@esbuild/win32-arm64": "0.25.10",
|
||||||
|
"@esbuild/win32-ia32": "0.25.10",
|
||||||
|
"@esbuild/win32-x64": "0.25.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fdir": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"picomatch": "^3 || ^4"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"picomatch": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "3.3.11",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/picocolors": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/picomatch": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss": {
|
||||||
|
"version": "8.5.6",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^3.3.11",
|
||||||
|
"picocolors": "^1.1.1",
|
||||||
|
"source-map-js": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rollup": {
|
||||||
|
"version": "4.52.3",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/estree": "1.0.8"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rollup": "dist/bin/rollup"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0",
|
||||||
|
"npm": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@rollup/rollup-android-arm-eabi": "4.52.3",
|
||||||
|
"@rollup/rollup-android-arm64": "4.52.3",
|
||||||
|
"@rollup/rollup-darwin-arm64": "4.52.3",
|
||||||
|
"@rollup/rollup-darwin-x64": "4.52.3",
|
||||||
|
"@rollup/rollup-freebsd-arm64": "4.52.3",
|
||||||
|
"@rollup/rollup-freebsd-x64": "4.52.3",
|
||||||
|
"@rollup/rollup-linux-arm-gnueabihf": "4.52.3",
|
||||||
|
"@rollup/rollup-linux-arm-musleabihf": "4.52.3",
|
||||||
|
"@rollup/rollup-linux-arm64-gnu": "4.52.3",
|
||||||
|
"@rollup/rollup-linux-arm64-musl": "4.52.3",
|
||||||
|
"@rollup/rollup-linux-loong64-gnu": "4.52.3",
|
||||||
|
"@rollup/rollup-linux-ppc64-gnu": "4.52.3",
|
||||||
|
"@rollup/rollup-linux-riscv64-gnu": "4.52.3",
|
||||||
|
"@rollup/rollup-linux-riscv64-musl": "4.52.3",
|
||||||
|
"@rollup/rollup-linux-s390x-gnu": "4.52.3",
|
||||||
|
"@rollup/rollup-linux-x64-gnu": "4.52.3",
|
||||||
|
"@rollup/rollup-linux-x64-musl": "4.52.3",
|
||||||
|
"@rollup/rollup-openharmony-arm64": "4.52.3",
|
||||||
|
"@rollup/rollup-win32-arm64-msvc": "4.52.3",
|
||||||
|
"@rollup/rollup-win32-ia32-msvc": "4.52.3",
|
||||||
|
"@rollup/rollup-win32-x64-gnu": "4.52.3",
|
||||||
|
"@rollup/rollup-win32-x64-msvc": "4.52.3",
|
||||||
|
"fsevents": "~2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/source-map-js": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tinyglobby": {
|
||||||
|
"version": "0.2.15",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fdir": "^6.5.0",
|
||||||
|
"picomatch": "^4.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"version": "5.8.3",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vite": {
|
||||||
|
"version": "7.1.7",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"esbuild": "^0.25.0",
|
||||||
|
"fdir": "^6.5.0",
|
||||||
|
"picomatch": "^4.0.3",
|
||||||
|
"postcss": "^8.5.6",
|
||||||
|
"rollup": "^4.43.0",
|
||||||
|
"tinyglobby": "^0.2.15"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"vite": "bin/vite.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/node": "^20.19.0 || >=22.12.0",
|
||||||
|
"jiti": ">=1.21.0",
|
||||||
|
"less": "^4.0.0",
|
||||||
|
"lightningcss": "^1.21.0",
|
||||||
|
"sass": "^1.70.0",
|
||||||
|
"sass-embedded": "^1.70.0",
|
||||||
|
"stylus": ">=0.54.8",
|
||||||
|
"sugarss": "^5.0.0",
|
||||||
|
"terser": "^5.16.0",
|
||||||
|
"tsx": "^4.8.1",
|
||||||
|
"yaml": "^2.4.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/node": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"jiti": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"less": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"lightningcss": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sass": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sass-embedded": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"stylus": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sugarss": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"terser": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"tsx": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"yaml": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Web/WebSocket/websocket/frontend/package.json
Normal file
15
Web/WebSocket/websocket/frontend/package.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "websocket",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc && vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "~5.8.3",
|
||||||
|
"vite": "^7.1.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Web/WebSocket/websocket/frontend/src/main.ts
Normal file
2
Web/WebSocket/websocket/frontend/src/main.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
const websocket = new WebSocket('ws://localhost:3000/ws');
|
||||||
26
Web/WebSocket/websocket/frontend/tsconfig.json
Normal file
26
Web/WebSocket/websocket/frontend/tsconfig.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||||
|
"types": ["vite/client"],
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"erasableSyntaxOnly": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedSideEffectImports": true
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
1032
Web/WebSocket/websocket/package-lock.json
generated
Normal file
1032
Web/WebSocket/websocket/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
11
Web/WebSocket/websocket/package.json
Normal file
11
Web/WebSocket/websocket/package.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"body-parser": "^2.2.0",
|
||||||
|
"compression": "^1.8.1",
|
||||||
|
"express": "^5.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/compression": "^1.8.1",
|
||||||
|
"@types/express": "^5.0.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,11 @@
|
|||||||
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
{
|
||||||
|
"name": "",
|
||||||
|
"short_name": "",
|
||||||
|
"icons": [
|
||||||
|
{"src": "/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png"},
|
||||||
|
{"src": "/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png"}
|
||||||
|
],
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"display": "standalone"
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"@types/on-headers": "1.0.4",
|
"@types/on-headers": "1.0.4",
|
||||||
"@types/response-time": "2.3.9",
|
"@types/response-time": "2.3.9",
|
||||||
"@types/serve-favicon": "2.5.7",
|
"@types/serve-favicon": "2.5.7",
|
||||||
|
"@types/ws": "8.18.1",
|
||||||
"eslint": "9.36.0",
|
"eslint": "9.36.0",
|
||||||
"globals": "16.4.0",
|
"globals": "16.4.0",
|
||||||
"jiti": "2.6.0",
|
"jiti": "2.6.0",
|
||||||
@@ -48,7 +49,10 @@
|
|||||||
"morgan": "1.10.1",
|
"morgan": "1.10.1",
|
||||||
"multer": "2.0.2",
|
"multer": "2.0.2",
|
||||||
"on-headers": "1.1.0",
|
"on-headers": "1.1.0",
|
||||||
|
"permessage-deflate": "0.1.7",
|
||||||
"response-time": "2.3.4",
|
"response-time": "2.3.4",
|
||||||
"serve-favicon": "2.5.1"
|
"serve-favicon": "2.5.1",
|
||||||
|
"websocket-extensions": "0.1.4",
|
||||||
|
"ws": "8.18.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export default class WebSocketServer {}
|
|
||||||
13
Web/WebSocket/websocket/server/src/health/HealthCheck.ts
Normal file
13
Web/WebSocket/websocket/server/src/health/HealthCheck.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import type {HealthStatus} from './IHealthCheck';
|
||||||
|
|
||||||
|
export default class HealthCheck {
|
||||||
|
public checkHealth(): HealthStatus {
|
||||||
|
return {
|
||||||
|
status: 'ok',
|
||||||
|
environment: 'development',
|
||||||
|
app: 'websocket-server',
|
||||||
|
version: '0.0.1',
|
||||||
|
zone: 'us-central1'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import type {Request, Response} from 'express';
|
||||||
|
import type IRoute from '../net/http/IRoutes';
|
||||||
|
import IHealthCheck from './IHealthCheck';
|
||||||
|
|
||||||
|
export default class HealthCheckRoute implements IRoute {
|
||||||
|
private readonly _healthCheck: IHealthCheck;
|
||||||
|
|
||||||
|
constructor(healthCheck: IHealthCheck) {
|
||||||
|
this._healthCheck = healthCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getGETRoutes() {
|
||||||
|
console.log('[HealthCheckRoute] getGETRoutes called');
|
||||||
|
const routes = {
|
||||||
|
'/ok.html': (req, res) => this.externalReadiness.call(this, req, res),
|
||||||
|
'/ping': (req, res) => this.ping.call(this, req, res)
|
||||||
|
};
|
||||||
|
console.log('[HealthCheckRoute] returning routes:', Object.keys(routes));
|
||||||
|
return routes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPOSTRoutes() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPUTRoutes() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPATCHRoutes() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDELETERoutes() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
private externalReadiness(_req: Request, res: Response) {
|
||||||
|
console.log('[HealthCheckRoute] External readiness');
|
||||||
|
res.setHeader('Cache-Control', 'public, max-age=0, no-cache, no-store');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = this._healthCheck.checkHealth();
|
||||||
|
|
||||||
|
if (!result || !result.status) {
|
||||||
|
return res.status(500).end();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (result.status) {
|
||||||
|
case 'ok':
|
||||||
|
case 'draining':
|
||||||
|
case 'draining2':
|
||||||
|
case 'disabled':
|
||||||
|
return res.status(200).json(result);
|
||||||
|
case 'starting':
|
||||||
|
case 'drained':
|
||||||
|
case 'stopped':
|
||||||
|
return res.status(503).json(result);
|
||||||
|
default:
|
||||||
|
return res.status(500).json(result);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return res.status(500).end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ping(_req: Request, res: Response) {
|
||||||
|
console.log('[HealthCheckRoute] Ping handler called from [%s]', _req.ip);
|
||||||
|
|
||||||
|
res.status(200).send({status: 'pong'}).end();
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Web/WebSocket/websocket/server/src/health/IHealthCheck.ts
Normal file
11
Web/WebSocket/websocket/server/src/health/IHealthCheck.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export type HealthStatus = {
|
||||||
|
status: 'ok' | 'draining' | 'draining2' | 'disabled' | 'starting' | 'drained' | 'stopped';
|
||||||
|
environment: string;
|
||||||
|
app: string;
|
||||||
|
version: string;
|
||||||
|
zone: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default interface IHealthCheck {
|
||||||
|
checkHealth(): HealthStatus;
|
||||||
|
}
|
||||||
@@ -1,28 +1,24 @@
|
|||||||
|
import path from 'node:path';
|
||||||
import {LoggerFactory} from '@techniker-me/logger';
|
import {LoggerFactory} from '@techniker-me/logger';
|
||||||
import HttpServer from './net/http/HttpServer';
|
import HttpServer from './net/http/HttpServer';
|
||||||
import path from 'node:path';
|
import HealthCheckRoute from './health/HealthCheckRoute';
|
||||||
const logger = LoggerFactory.getLogger('Server');
|
import HealthCheck from './health/HealthCheck';
|
||||||
|
|
||||||
const httpServer = new HttpServer(
|
const logger = LoggerFactory.getLogger('Server');
|
||||||
'http',
|
const healthCheck = new HealthCheck();
|
||||||
3000,
|
const healthCheckRoute = new HealthCheckRoute(healthCheck);
|
||||||
{
|
|
||||||
getGETRoutes: () => ({}),
|
const httpServer = new HttpServer('http', 3000, healthCheckRoute, {}, '', [], path.resolve(process.cwd(), 'assets', 'favicon', 'favicon.ico'), {});
|
||||||
getPOSTRoutes: () => ({}),
|
|
||||||
getPUTRoutes: () => ({}),
|
|
||||||
getPATCHRoutes: () => ({}),
|
|
||||||
getDELETERoutes: () => ({})
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
'',
|
|
||||||
[],
|
|
||||||
path.resolve(process.cwd(), 'assets', 'favicon', 'favicon.ico'),
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
|
|
||||||
httpServer.on('error', () => {
|
httpServer.on('error', () => {
|
||||||
|
console.log('[HttpServer] Error event');
|
||||||
logger.error('[HttpServer] Error');
|
logger.error('[HttpServer] Error');
|
||||||
});
|
});
|
||||||
|
httpServer.on('request', (method: string, url: string, statusCode: number, headers: Record<string, string>) => {
|
||||||
|
console.log(`[HttpServer] Request: ${method} ${url} -> ${statusCode}`);
|
||||||
|
});
|
||||||
|
|
||||||
httpServer.start();
|
httpServer
|
||||||
|
.start()
|
||||||
|
.then(() => console.log('[Server] Server started successfully'))
|
||||||
|
.catch(err => console.log('[Server] Server failed to start:', err));
|
||||||
|
|||||||
@@ -163,4 +163,8 @@ export default class Assert {
|
|||||||
private static _isNumberInRange(value: unknown, lowerBound: number, upperBound: number): value is number {
|
private static _isNumberInRange(value: unknown, lowerBound: number, upperBound: number): value is number {
|
||||||
return Assert._isNumber(value) && value >= lowerBound && value <= upperBound;
|
return Assert._isNumber(value) && value >= lowerBound && value <= upperBound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
throw new Error('Assert is a static class that may not be instantiated');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
Web/WebSocket/websocket/server/src/lang/Strings.ts
Normal file
9
Web/WebSocket/websocket/server/src/lang/Strings.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export default class Strings {
|
||||||
|
public static randomString(length: number): string {
|
||||||
|
return (Date.now().toString(36) + Math.random().toString(36).substring(2)).substring(0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
throw new Error('Strings is a static class that may not be instantiated');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ import type {ILogger} from '@techniker-me/logger';
|
|||||||
import {LoggerFactory} from '@techniker-me/logger';
|
import {LoggerFactory} from '@techniker-me/logger';
|
||||||
import IRoutes from './IRoutes';
|
import IRoutes from './IRoutes';
|
||||||
import {Subject} from '@techniker-me/tools';
|
import {Subject} from '@techniker-me/tools';
|
||||||
import express from 'express';
|
import express, { RequestHandler } from 'express';
|
||||||
import morgan from 'morgan';
|
import morgan from 'morgan';
|
||||||
import favicon from 'serve-favicon';
|
import favicon from 'serve-favicon';
|
||||||
import bodyParser from 'body-parser';
|
import bodyParser from 'body-parser';
|
||||||
@@ -32,7 +32,6 @@ export default class HttpServer {
|
|||||||
private readonly _eventEmitter: EventEmitter;
|
private readonly _eventEmitter: EventEmitter;
|
||||||
private readonly _protocol: 'http' | 'https';
|
private readonly _protocol: 'http' | 'https';
|
||||||
private readonly _port: number;
|
private readonly _port: number;
|
||||||
// @ts-expect-error - unused parameter for future functionality
|
|
||||||
private readonly _routes: IRoutes;
|
private readonly _routes: IRoutes;
|
||||||
// @ts-expect-error - unused parameter for future functionality
|
// @ts-expect-error - unused parameter for future functionality
|
||||||
private readonly _viewsPath: object;
|
private readonly _viewsPath: object;
|
||||||
@@ -47,6 +46,7 @@ export default class HttpServer {
|
|||||||
ttl: tlsSessionTimeout.asMilliseconds(),
|
ttl: tlsSessionTimeout.asMilliseconds(),
|
||||||
max: maxCachedTlsSessions
|
max: maxCachedTlsSessions
|
||||||
});
|
});
|
||||||
|
private _jsonHandler: Nullable<express.RequestHandler>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protocol: 'https' | 'http',
|
protocol: 'https' | 'http',
|
||||||
@@ -78,11 +78,13 @@ export default class HttpServer {
|
|||||||
this._app = new Subject<Nullable<express.Application>>(null);
|
this._app = new Subject<Nullable<express.Application>>(null);
|
||||||
this._eventEmitter = new EventEmitter();
|
this._eventEmitter = new EventEmitter();
|
||||||
this._server = new Subject<Nullable<Server>>(null);
|
this._server = new Subject<Nullable<Server>>(null);
|
||||||
|
this._jsonHandler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public start() {
|
public start() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const app = (this._app.value = express());
|
const app = (this._app.value = express());
|
||||||
|
this._jsonHandler = bodyParser.json({limit: requestSizeLimit});
|
||||||
|
|
||||||
this.configureListener();
|
this.configureListener();
|
||||||
this.configureMiddleware();
|
this.configureMiddleware();
|
||||||
@@ -113,6 +115,10 @@ export default class HttpServer {
|
|||||||
server.once('error', onError);
|
server.once('error', onError);
|
||||||
server.once('listening', onListen);
|
server.once('listening', onListen);
|
||||||
|
|
||||||
|
server.on('request', (req, res) => {
|
||||||
|
this._eventEmitter.emit('request', req.method, req.url, res.statusCode, req.headers);
|
||||||
|
});
|
||||||
|
|
||||||
server.on('newSession', (sessionId, sessionData, callback) => {
|
server.on('newSession', (sessionId, sessionData, callback) => {
|
||||||
const cacheId = sessionId.toString('hex');
|
const cacheId = sessionId.toString('hex');
|
||||||
|
|
||||||
@@ -142,7 +148,7 @@ export default class HttpServer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public on(event: string, handler: () => void): void {
|
public on(event: string, handler: (...args: unknown[]) => void): void {
|
||||||
Assert.isNonEmptyString('event', event);
|
Assert.isNonEmptyString('event', event);
|
||||||
Assert.isFunction('handler', handler);
|
Assert.isFunction('handler', handler);
|
||||||
|
|
||||||
@@ -310,9 +316,6 @@ export default class HttpServer {
|
|||||||
for (const resourcePath of this._resourcesPaths) {
|
for (const resourcePath of this._resourcesPaths) {
|
||||||
app.use(express.static(resourcePath));
|
app.use(express.static(resourcePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use(this.errorHandler);
|
|
||||||
app.use(this.genericNotFoundHandler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
@@ -325,6 +328,8 @@ export default class HttpServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private genericNotFoundHandler(_req: express.Request, res: express.Response) {
|
private genericNotFoundHandler(_req: express.Request, res: express.Response) {
|
||||||
|
console.log('Generic not found handler');
|
||||||
|
|
||||||
res.status(404).send({status: 'not-found'});
|
res.status(404).send({status: 'not-found'});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -335,26 +340,40 @@ export default class HttpServer {
|
|||||||
throw new Error('Unable to configure routes, no app instance found');
|
throw new Error('Unable to configure routes, no app instance found');
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement routes
|
const app = this._app.value;
|
||||||
// const app = this._app.value;
|
|
||||||
|
let catchAllHandler: Nullable<RequestHandler> = null;
|
||||||
|
|
||||||
|
const registerRoutes = (routes: Record<string, RequestHandler>): void => {
|
||||||
|
for (const route of Object.entries(routes)) {
|
||||||
|
const [name, handler] = route;
|
||||||
|
|
||||||
// let catchAllHandler = null;
|
console.log(`[${name}] registering [%o]`, handler);
|
||||||
|
if (name === '*') {
|
||||||
|
console.log('Catch-all handler', name, handler);
|
||||||
|
if (catchAllHandler) {
|
||||||
|
throw new Error(`Only one catch-all handler can ber registered per server, ignoring conflicting catch-all`);
|
||||||
|
}
|
||||||
|
|
||||||
// for (const route of this._routes.getGETRoutes().entries()) {
|
catchAllHandler = handler;
|
||||||
// const [handler, name] = route;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// if (name === '*') {
|
this._logger.debug(`Registering [GET] route [${name}] with [%o]`, handler);
|
||||||
// if (catchAllHandler) {
|
app.get(name, handler);
|
||||||
// throw new Error(`Only one catch-all handler can ber registered per server, ignoring conflicting catch-all`);
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// catchAllHandler = handler;
|
const getRoutes = this._routes.getGETRoutes();
|
||||||
|
const postRoutes = this._routes.getPOSTRoutes();
|
||||||
|
const putRoutes = this._routes.getPUTRoutes();
|
||||||
|
const patchRoutes = this._routes.getPATCHRoutes();
|
||||||
|
const deleteRoutes = this._routes.getDELETERoutes();
|
||||||
|
|
||||||
// continue;
|
registerRoutes(getRoutes);
|
||||||
// }
|
registerRoutes(postRoutes);
|
||||||
|
registerRoutes(putRoutes);
|
||||||
// this._logger.debug(`Registering [GET] route [${name}]`);
|
registerRoutes(patchRoutes);
|
||||||
// // app.get(name, this._json);
|
registerRoutes(deleteRoutes);
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import type {RequestHandler} from 'express';
|
||||||
|
|
||||||
export default interface IRoutes {
|
export default interface IRoutes {
|
||||||
getGETRoutes(): Record<string, () => void | Promise<void>>;
|
getGETRoutes(): Record<string, RequestHandler>;
|
||||||
getPOSTRoutes(): Record<string, () => void | Promise<void>>;
|
getPOSTRoutes(): Record<string, RequestHandler>;
|
||||||
getPUTRoutes(): Record<string, () => void | Promise<void>>;
|
getPUTRoutes(): Record<string, RequestHandler>;
|
||||||
getPATCHRoutes(): Record<string, () => void | Promise<void>>;
|
getPATCHRoutes(): Record<string, RequestHandler>;
|
||||||
getDELETERoutes(): Record<string, () => void | Promise<void>>;
|
getDELETERoutes(): Record<string, RequestHandler>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,177 @@
|
|||||||
|
import {LoggerFactory} from '@techniker-me/logger';
|
||||||
|
import {Server as HttpServer} from 'node:http';
|
||||||
|
import {IncomingMessage} from 'node:http';
|
||||||
|
import ws, {WebSocketServer as WSServer, WebSocket} from 'ws';
|
||||||
|
import Assert from '../../lang/Assert';
|
||||||
|
import Strings from '../../lang/Strings';
|
||||||
|
import WebsocketExtensions from 'websocket-extensions';
|
||||||
|
import deflate from 'permessage-deflate';
|
||||||
|
|
||||||
|
interface ExtendedWebSocket extends WebSocket {
|
||||||
|
id: string;
|
||||||
|
remoteAddress: string;
|
||||||
|
isOpen(): boolean;
|
||||||
|
isClosed(): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deepClone<T>(obj: T): T {
|
||||||
|
if (obj === null || typeof obj !== 'object') {
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj instanceof Date) {
|
||||||
|
return new Date(obj.getTime()) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj instanceof Array) {
|
||||||
|
return obj.map(item => deepClone(item)) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj instanceof Object) {
|
||||||
|
const copy = {} as T;
|
||||||
|
Object.keys(obj).forEach(key => {
|
||||||
|
copy[key as keyof T] = deepClone(obj[key as keyof T]);
|
||||||
|
});
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRemoteAddress(connection: ExtendedWebSocket, req: IncomingMessage): string {
|
||||||
|
// WebSocket doesn't expose socket directly, so we need to use the underlying socket
|
||||||
|
const socket = (connection as WebSocket & {_socket?: {remoteAddress?: string}})._socket;
|
||||||
|
const remoteAddress = socket?.remoteAddress || '::';
|
||||||
|
const xForwardedFor = req.headers['x-forwarded-for'];
|
||||||
|
|
||||||
|
let forwardingRemoteAddressChain: string[] = [];
|
||||||
|
if (typeof xForwardedFor === 'string') {
|
||||||
|
forwardingRemoteAddressChain = xForwardedFor.split(', ').filter(Boolean);
|
||||||
|
} else if (Array.isArray(xForwardedFor)) {
|
||||||
|
forwardingRemoteAddressChain = xForwardedFor.flatMap(addr => addr.split(', ')).filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
forwardingRemoteAddressChain.push(remoteAddress);
|
||||||
|
|
||||||
|
// For now, just return the first address (most direct)
|
||||||
|
// TODO: Implement proper proxy trust checking
|
||||||
|
return forwardingRemoteAddressChain[forwardingRemoteAddressChain.length - 1] || '::';
|
||||||
|
}
|
||||||
|
|
||||||
|
export type WebSovketServerOptions = {
|
||||||
|
path?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const connectionIdLength = 32;
|
||||||
|
|
||||||
|
export default class WebSocketServer {
|
||||||
|
private readonly _logger = LoggerFactory.getLogger('WebSocketServer');
|
||||||
|
private readonly _httpServer: HttpServer;
|
||||||
|
private readonly _parameters: Record<string, string>;
|
||||||
|
private _server?: WSServer;
|
||||||
|
private _extensions?: WebsocketExtensions;
|
||||||
|
|
||||||
|
constructor(httpServer: HttpServer, parameters: WebSovketServerOptions) {
|
||||||
|
this._httpServer = httpServer;
|
||||||
|
this._parameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public start(
|
||||||
|
connectDelegate: (connection: ExtendedWebSocket, req: IncomingMessage) => void,
|
||||||
|
requestDelegate: (connection: ExtendedWebSocket, message: Buffer) => void,
|
||||||
|
disconnectDelegate: (connection: ExtendedWebSocket, reasonCode: number, description: string) => void,
|
||||||
|
pongDelegate: (connection: ExtendedWebSocket, message: Buffer) => void
|
||||||
|
): void {
|
||||||
|
Assert.isFunction('connectDelegate', connectDelegate);
|
||||||
|
Assert.isFunction('requestDelegate', requestDelegate);
|
||||||
|
Assert.isFunction('disconnectDelegate', disconnectDelegate);
|
||||||
|
Assert.isFunction('pongDelegate', pongDelegate);
|
||||||
|
|
||||||
|
const serverOptions = deepClone(this._parameters);
|
||||||
|
|
||||||
|
const address = this._httpServer.address();
|
||||||
|
const port = typeof address === 'string' ? address : address?.port?.toString() || 'unknown';
|
||||||
|
const path = serverOptions['path'] || '/';
|
||||||
|
|
||||||
|
this._logger.info(`Listening on port [${port}] and bound to [${path}]`);
|
||||||
|
|
||||||
|
(serverOptions as Record<string, unknown>)['noServer'] = true;
|
||||||
|
|
||||||
|
this._server = new WSServer(serverOptions);
|
||||||
|
this._extensions = new WebsocketExtensions();
|
||||||
|
|
||||||
|
this._extensions.add(deflate());
|
||||||
|
(this._server as WSServer & {_server?: HttpServer})._server = this._httpServer;
|
||||||
|
this._httpServer.on('error', this._server.emit.bind(this._server, 'error'));
|
||||||
|
this._httpServer.on('listening', this._server.emit.bind(this._server, 'listening'));
|
||||||
|
this._httpServer.on('upgrade', (req, socket, head) => {
|
||||||
|
if (!req.url?.startsWith(path)) {
|
||||||
|
this._logger.debug(`Skipping upgrade of http request due to incorrect path [${req.url}]`);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._server!.handleUpgrade(req, socket, head, (ws: WebSocket) => {
|
||||||
|
this._server!.emit('connection', ws, req as IncomingMessage);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this._httpServer.on('request', (req, res) => {
|
||||||
|
this._logger.debug(`[HttpServer] Request: ${req.method} ${req.url} -> ${res.statusCode}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._server.on('error', err => this._logger.error('An error occurred with WebSocket', err));
|
||||||
|
this._server.on('connection', (connection: WebSocket, req: IncomingMessage) => {
|
||||||
|
let closed = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const extendedConnection = connection as ExtendedWebSocket;
|
||||||
|
extendedConnection.id = Strings.randomString(connectionIdLength);
|
||||||
|
extendedConnection.remoteAddress = getRemoteAddress(extendedConnection, req);
|
||||||
|
extendedConnection.isOpen = () => connection.readyState === ws.OPEN;
|
||||||
|
extendedConnection.isClosed = () => connection.readyState === ws.CLOSED;
|
||||||
|
|
||||||
|
connection.on('error', (e: Error) => {
|
||||||
|
this._logger.error('An error occurred on websocket', e);
|
||||||
|
});
|
||||||
|
|
||||||
|
connection.on('message', (message: Buffer) => {
|
||||||
|
try {
|
||||||
|
requestDelegate(extendedConnection, message);
|
||||||
|
} catch (e) {
|
||||||
|
this._logger.error('Request handler failed for message [%s]', message, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connection.on('close', (reasonCode: number, description: string) => {
|
||||||
|
if (closed) {
|
||||||
|
this._logger.warn('[%s] Multiple close events [%s] [%s] [%s]', extendedConnection.id, extendedConnection.remoteAddress, reasonCode, description);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
closed = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
disconnectDelegate(extendedConnection, reasonCode, description);
|
||||||
|
} catch (e) {
|
||||||
|
this._logger.error('Disconnect handler failed', e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connection.on('pong', (message: Buffer) => {
|
||||||
|
try {
|
||||||
|
pongDelegate(extendedConnection, message);
|
||||||
|
} catch (e) {
|
||||||
|
this._logger.error('Pong handler failed', e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connectDelegate(extendedConnection, req);
|
||||||
|
} catch (e) {
|
||||||
|
this._logger.error('Accept/connect handler failed', e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public stop() {}
|
||||||
|
}
|
||||||
32
Web/WebSocket/websocket/server/src/types/modules.d.ts
vendored
Normal file
32
Web/WebSocket/websocket/server/src/types/modules.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
declare module 'websocket-extensions' {
|
||||||
|
interface Extension {
|
||||||
|
name: string;
|
||||||
|
params?: Record<string, string | number | boolean>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WebSocketExtensions {
|
||||||
|
constructor();
|
||||||
|
add(extension: {name: string; [key: string]: unknown}): void;
|
||||||
|
negotiate(protocol: string, extensions: string[]): string | false;
|
||||||
|
parse(extensions: string): Extension[];
|
||||||
|
generate(extensions: Extension[]): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export = WebSocketExtensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'permessage-deflate' {
|
||||||
|
interface DeflateOptions {
|
||||||
|
serverNoContextTakeover?: boolean;
|
||||||
|
clientNoContextTakeover?: boolean;
|
||||||
|
serverMaxWindowBits?: number;
|
||||||
|
clientMaxWindowBits?: number;
|
||||||
|
level?: number;
|
||||||
|
memLevel?: number;
|
||||||
|
strategy?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deflate(options?: DeflateOptions): {name: string; [key: string]: unknown};
|
||||||
|
|
||||||
|
export = deflate;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user