Add channels and migrate to bun
This commit is contained in:
parent
c068545958
commit
99609bf2ef
|
@ -6,9 +6,20 @@ lobbySettings:
|
||||||
lobby: true
|
lobby: true
|
||||||
chat: true
|
chat: true
|
||||||
crownsolo: false
|
crownsolo: false
|
||||||
|
color: "#eeeeee"
|
||||||
|
color2: "#888888"
|
||||||
|
visible: true
|
||||||
|
|
||||||
|
defaultSettings:
|
||||||
|
chat: true
|
||||||
|
crownsolo: false
|
||||||
|
color: "#480505"
|
||||||
|
color2: "#000000"
|
||||||
|
visible: true
|
||||||
|
|
||||||
lobbyRegexes:
|
lobbyRegexes:
|
||||||
- "^lobby\\d\\d$"
|
- "^lobby[1-9]?[1-9]?$"
|
||||||
- "^test/.*$"
|
- "^test/.+$"
|
||||||
|
|
||||||
lobbyBackdoor: "lolwutsecretlobbybackdoor"
|
lobbyBackdoor: "lolwutsecretlobbybackdoor"
|
||||||
|
fullChannel: "test/awkward"
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
"description": "Hri7566's MPP Server",
|
"description": "Hri7566's MPP Server",
|
||||||
"main": "out/index.js",
|
"main": "out/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node .",
|
"start": "bun .",
|
||||||
"build": "npx tsc",
|
"build": "bun build ./src/index.ts --outdir=out",
|
||||||
"dev": "pnpm build && pnpm start"
|
"dev": "bun run src/index.ts"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "Hri7566",
|
"author": "Hri7566",
|
||||||
|
@ -14,13 +14,14 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "5.2.0",
|
"@prisma/client": "5.2.0",
|
||||||
"@t3-oss/env-core": "^0.6.1",
|
"@t3-oss/env-core": "^0.6.1",
|
||||||
|
"bun": "^1.0.0",
|
||||||
|
"bun-types": "^1.0.1",
|
||||||
"date-holidays": "^3.21.5",
|
"date-holidays": "^3.21.5",
|
||||||
"dotenv": "^8.6.0",
|
"dotenv": "^8.6.0",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
"fancy-text-converter": "^1.0.9",
|
"fancy-text-converter": "^1.0.9",
|
||||||
"keccak": "^2.1.0",
|
"keccak": "^2.1.0",
|
||||||
"mppclone-client": "^1.1.3",
|
"mppclone-client": "^1.1.3",
|
||||||
"uWebSockets.js": "uNetworking/uWebSockets.js#v20.31.0",
|
|
||||||
"unique-names-generator": "^4.7.1",
|
"unique-names-generator": "^4.7.1",
|
||||||
"yaml": "^2.3.2",
|
"yaml": "^2.3.2",
|
||||||
"zod": "^3.22.2"
|
"zod": "^3.22.2"
|
||||||
|
|
292
pnpm-lock.yaml
292
pnpm-lock.yaml
|
@ -1,292 +0,0 @@
|
||||||
lockfileVersion: '6.0'
|
|
||||||
|
|
||||||
settings:
|
|
||||||
autoInstallPeers: true
|
|
||||||
excludeLinksFromLockfile: false
|
|
||||||
|
|
||||||
dependencies:
|
|
||||||
'@prisma/client':
|
|
||||||
specifier: 5.2.0
|
|
||||||
version: 5.2.0(prisma@5.2.0)
|
|
||||||
'@t3-oss/env-core':
|
|
||||||
specifier: ^0.6.1
|
|
||||||
version: 0.6.1(typescript@5.2.2)(zod@3.22.2)
|
|
||||||
date-holidays:
|
|
||||||
specifier: ^3.21.5
|
|
||||||
version: 3.21.5
|
|
||||||
dotenv:
|
|
||||||
specifier: ^8.6.0
|
|
||||||
version: 8.6.0
|
|
||||||
events:
|
|
||||||
specifier: ^3.3.0
|
|
||||||
version: 3.3.0
|
|
||||||
fancy-text-converter:
|
|
||||||
specifier: ^1.0.9
|
|
||||||
version: 1.0.9
|
|
||||||
keccak:
|
|
||||||
specifier: ^2.1.0
|
|
||||||
version: 2.1.0
|
|
||||||
mppclone-client:
|
|
||||||
specifier: ^1.1.3
|
|
||||||
version: 1.1.3
|
|
||||||
uWebSockets.js:
|
|
||||||
specifier: github:uNetworking/uWebSockets.js#v20.31.0
|
|
||||||
version: github.com/uNetworking/uWebSockets.js/809b99d2d7d12e2cbf89b7135041e9b41ff84084
|
|
||||||
unique-names-generator:
|
|
||||||
specifier: ^4.7.1
|
|
||||||
version: 4.7.1
|
|
||||||
yaml:
|
|
||||||
specifier: ^2.3.2
|
|
||||||
version: 2.3.2
|
|
||||||
zod:
|
|
||||||
specifier: ^3.22.2
|
|
||||||
version: 3.22.2
|
|
||||||
|
|
||||||
devDependencies:
|
|
||||||
'@types/node':
|
|
||||||
specifier: ^20.5.9
|
|
||||||
version: 20.5.9
|
|
||||||
prisma:
|
|
||||||
specifier: ^5.2.0
|
|
||||||
version: 5.2.0
|
|
||||||
typescript:
|
|
||||||
specifier: ^5.2.2
|
|
||||||
version: 5.2.2
|
|
||||||
|
|
||||||
packages:
|
|
||||||
|
|
||||||
/@prisma/client@5.2.0(prisma@5.2.0):
|
|
||||||
resolution: {integrity: sha512-AiTjJwR4J5Rh6Z/9ZKrBBLel3/5DzUNntMohOy7yObVnVoTNVFi2kvpLZlFuKO50d7yDspOtW6XBpiAd0BVXbQ==}
|
|
||||||
engines: {node: '>=16.13'}
|
|
||||||
requiresBuild: true
|
|
||||||
peerDependencies:
|
|
||||||
prisma: '*'
|
|
||||||
peerDependenciesMeta:
|
|
||||||
prisma:
|
|
||||||
optional: true
|
|
||||||
dependencies:
|
|
||||||
'@prisma/engines-version': 5.2.0-25.2804dc98259d2ea960602aca6b8e7fdc03c1758f
|
|
||||||
prisma: 5.2.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@prisma/engines-version@5.2.0-25.2804dc98259d2ea960602aca6b8e7fdc03c1758f:
|
|
||||||
resolution: {integrity: sha512-jsnKT5JIDIE01lAeCj2ghY9IwxkedhKNvxQeoyLs6dr4ZXynetD0vTy7u6wMJt8vVPv8I5DPy/I4CFaoXAgbtg==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@prisma/engines@5.2.0:
|
|
||||||
resolution: {integrity: sha512-dT7FOLUCdZmq+AunLqB1Iz+ZH/IIS1Fz2THmKZQ6aFONrQD/BQ5ecJ7g2wGS2OgyUFf4OaLam6/bxmgdOBDqig==}
|
|
||||||
requiresBuild: true
|
|
||||||
|
|
||||||
/@t3-oss/env-core@0.6.1(typescript@5.2.2)(zod@3.22.2):
|
|
||||||
resolution: {integrity: sha512-KQD7qEDJtkWIWWmTVjNvk0wnHpkvAQ6CRbUxbWMFNG/fiosBQDQvtRpBNu6USxBscJCoC4z6y7P9MN52/mLOzw==}
|
|
||||||
peerDependencies:
|
|
||||||
typescript: '>=4.7.2'
|
|
||||||
zod: ^3.0.0
|
|
||||||
dependencies:
|
|
||||||
typescript: 5.2.2
|
|
||||||
zod: 3.22.2
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@types/node@20.5.9:
|
|
||||||
resolution: {integrity: sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/argparse@2.0.1:
|
|
||||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/astronomia@4.1.1:
|
|
||||||
resolution: {integrity: sha512-TcJD9lUC5eAo0/Ji7rnQauX/yQbi0yZWM+JsNr77W3OA5fsrgvuFgubLMFwfw4VlZ29cu9dG/yfJbfvuTSftjg==}
|
|
||||||
engines: {node: '>=12.0.0'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/bindings@1.5.0:
|
|
||||||
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
|
|
||||||
dependencies:
|
|
||||||
file-uri-to-path: 1.0.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/caldate@2.0.5:
|
|
||||||
resolution: {integrity: sha512-JndhrUuDuE975KUhFqJaVR1OQkCHZqpOrJur/CFXEIEhWhBMjxO85cRSK8q4FW+B+yyPq6GYua2u4KvNzTcq0w==}
|
|
||||||
engines: {node: '>=12.0.0'}
|
|
||||||
dependencies:
|
|
||||||
moment-timezone: 0.5.43
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/date-bengali-revised@2.0.2:
|
|
||||||
resolution: {integrity: sha512-q9iDru4+TSA9k4zfm0CFHJj6nBsxP7AYgWC/qodK/i7oOIlj5K2z5IcQDtESfs/Qwqt/xJYaP86tkazd/vRptg==}
|
|
||||||
engines: {node: '>=12.0.0'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/date-chinese@2.1.4:
|
|
||||||
resolution: {integrity: sha512-WY+6+Qw92ZGWFvGtStmNQHEYpNa87b8IAQ5T8VKt4wqrn24lBXyyBnWI5jAIyy7h/KVwJZ06bD8l/b7yss82Ww==}
|
|
||||||
engines: {node: '>=12.0.0'}
|
|
||||||
dependencies:
|
|
||||||
astronomia: 4.1.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/date-easter@1.0.2:
|
|
||||||
resolution: {integrity: sha512-mpC1izx7lUSLYl4B88V2W57eNB4xS2ic+ahxK2AYUsaBTsCeHzT6K5ymUKzL9YPFf/GlygFqpiD4/NO1hxDsLw==}
|
|
||||||
engines: {node: '>=12.0.0'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/date-holidays-parser@3.4.4:
|
|
||||||
resolution: {integrity: sha512-R5aO4oT8H51ZKdvApqHrqYEiNBrqT6tRj2PFXNcZfqMI4nxY7KKKly0ZsmquR5gY+x9ldKR8SAMdozzIInaoXg==}
|
|
||||||
engines: {node: '>=12.0.0'}
|
|
||||||
dependencies:
|
|
||||||
astronomia: 4.1.1
|
|
||||||
caldate: 2.0.5
|
|
||||||
date-bengali-revised: 2.0.2
|
|
||||||
date-chinese: 2.1.4
|
|
||||||
date-easter: 1.0.2
|
|
||||||
deepmerge: 4.3.1
|
|
||||||
jalaali-js: 1.2.6
|
|
||||||
moment-timezone: 0.5.43
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/date-holidays@3.21.5:
|
|
||||||
resolution: {integrity: sha512-5X/UK7FunfIiM/q7CwepNfzh1XkkukdZNfTPyKlD5kx01MQzJ9DqKyTcFNzlQJ+HgpAxqUqSs3+F8mwV9bzo/w==}
|
|
||||||
engines: {node: '>=12.0.0'}
|
|
||||||
hasBin: true
|
|
||||||
dependencies:
|
|
||||||
date-holidays-parser: 3.4.4
|
|
||||||
js-yaml: 4.1.0
|
|
||||||
lodash.omit: 4.5.0
|
|
||||||
lodash.pick: 4.4.0
|
|
||||||
prepin: 1.0.3
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/deepmerge@4.3.1:
|
|
||||||
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/dotenv@8.6.0:
|
|
||||||
resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==}
|
|
||||||
engines: {node: '>=10'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/events@3.3.0:
|
|
||||||
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
|
||||||
engines: {node: '>=0.8.x'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/fancy-text-converter@1.0.9:
|
|
||||||
resolution: {integrity: sha512-tFUAWpEfZOYhdsjILVu7c0PL9Ud9pTQmonm/2mdvFC7WcEHIYi9NYS5irJYFdBJDIRSqi64XV+IhHPc/ngxtyw==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/file-uri-to-path@1.0.0:
|
|
||||||
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/inherits@2.0.4:
|
|
||||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/jalaali-js@1.2.6:
|
|
||||||
resolution: {integrity: sha512-io974va+Qyu+UfuVX3UIAgJlxLhAMx9Y8VMfh+IG00Js7hXQo1qNQuwSiSa0xxco0SVgx5HWNkaiCcV+aZ8WPw==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/js-yaml@4.1.0:
|
|
||||||
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
|
|
||||||
hasBin: true
|
|
||||||
dependencies:
|
|
||||||
argparse: 2.0.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/keccak@2.1.0:
|
|
||||||
resolution: {integrity: sha512-m1wbJRTo+gWbctZWay9i26v5fFnYkOn7D5PCxJ3fZUGUEb49dE1Pm4BREUYCt/aoO6di7jeoGmhvqN9Nzylm3Q==}
|
|
||||||
engines: {node: '>=5.12.0'}
|
|
||||||
requiresBuild: true
|
|
||||||
dependencies:
|
|
||||||
bindings: 1.5.0
|
|
||||||
inherits: 2.0.4
|
|
||||||
nan: 2.17.0
|
|
||||||
safe-buffer: 5.2.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/lodash.omit@4.5.0:
|
|
||||||
resolution: {integrity: sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/lodash.pick@4.4.0:
|
|
||||||
resolution: {integrity: sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/moment-timezone@0.5.43:
|
|
||||||
resolution: {integrity: sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==}
|
|
||||||
dependencies:
|
|
||||||
moment: 2.29.4
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/moment@2.29.4:
|
|
||||||
resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/mppclone-client@1.1.3:
|
|
||||||
resolution: {integrity: sha512-5DSkQmZOj823/BPwi6CQa4UWkoAX7itfNxf6L26NJS/qj9AljuKoqnIZxhtSKdak75qZd5Jgx+zD1aXflRNxHg==}
|
|
||||||
dependencies:
|
|
||||||
ws: 8.14.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- bufferutil
|
|
||||||
- utf-8-validate
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/nan@2.17.0:
|
|
||||||
resolution: {integrity: sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/prepin@1.0.3:
|
|
||||||
resolution: {integrity: sha512-0XL2hreherEEvUy0fiaGEfN/ioXFV+JpImqIzQjxk6iBg4jQ2ARKqvC4+BmRD8w/pnpD+lbxvh0Ub+z7yBEjvA==}
|
|
||||||
hasBin: true
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/prisma@5.2.0:
|
|
||||||
resolution: {integrity: sha512-FfFlpjVCkZwrqxDnP4smlNYSH1so+CbfjgdpioFzGGqlQAEm6VHAYSzV7jJgC3ebtY9dNOhDMS2+4/1DDSM7bQ==}
|
|
||||||
engines: {node: '>=16.13'}
|
|
||||||
hasBin: true
|
|
||||||
requiresBuild: true
|
|
||||||
dependencies:
|
|
||||||
'@prisma/engines': 5.2.0
|
|
||||||
|
|
||||||
/safe-buffer@5.2.1:
|
|
||||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/typescript@5.2.2:
|
|
||||||
resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==}
|
|
||||||
engines: {node: '>=14.17'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
/unique-names-generator@4.7.1:
|
|
||||||
resolution: {integrity: sha512-lMx9dX+KRmG8sq6gulYYpKWZc9RlGsgBR6aoO8Qsm3qvkSJ+3rAymr+TnV8EDMrIrwuFJ4kruzMWM/OpYzPoow==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/ws@8.14.0:
|
|
||||||
resolution: {integrity: sha512-WR0RJE9Ehsio6U4TuM+LmunEsjQ5ncHlw4sn9ihD6RoJKZrVyH9FWV3dmnwu8B2aNib1OvG2X6adUCyFpQyWcg==}
|
|
||||||
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
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/yaml@2.3.2:
|
|
||||||
resolution: {integrity: sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==}
|
|
||||||
engines: {node: '>= 14'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/zod@3.22.2:
|
|
||||||
resolution: {integrity: sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
github.com/uNetworking/uWebSockets.js/809b99d2d7d12e2cbf89b7135041e9b41ff84084:
|
|
||||||
resolution: {tarball: https://codeload.github.com/uNetworking/uWebSockets.js/tar.gz/809b99d2d7d12e2cbf89b7135041e9b41ff84084}
|
|
||||||
name: uWebSockets.js
|
|
||||||
version: 20.31.0
|
|
||||||
dev: false
|
|
|
@ -1,11 +1,218 @@
|
||||||
// TODO Load channel config file
|
import { Logger } from "../util/Logger";
|
||||||
|
import { loadConfig } from "../util/config";
|
||||||
|
import {
|
||||||
|
ChannelSettingValue,
|
||||||
|
ChannelSettings,
|
||||||
|
Participant
|
||||||
|
} from "../util/types";
|
||||||
|
import { Socket } from "../ws/Socket";
|
||||||
|
import { app, findSocketByPartID } from "../ws/server";
|
||||||
|
import { validateChannelSettings } from "./settings";
|
||||||
|
|
||||||
|
interface ChannelConfig {
|
||||||
|
forceLoad: string[];
|
||||||
|
lobbySettings: Partial<ChannelSettings>;
|
||||||
|
defaultSettings: Partial<ChannelSettings>;
|
||||||
|
lobbyRegexes: string[];
|
||||||
|
lobbyBackdoor: string;
|
||||||
|
fullChannel: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = loadConfig<ChannelConfig>("config/channels.yml", {
|
||||||
|
forceLoad: ["lobby", "test/awkward"],
|
||||||
|
lobbySettings: {
|
||||||
|
lobby: true,
|
||||||
|
chat: true,
|
||||||
|
crownsolo: false,
|
||||||
|
visible: true
|
||||||
|
},
|
||||||
|
defaultSettings: {
|
||||||
|
chat: true,
|
||||||
|
crownsolo: false,
|
||||||
|
color: "#480505",
|
||||||
|
color2: "#000000",
|
||||||
|
visible: true
|
||||||
|
},
|
||||||
|
// TODO Test this regex
|
||||||
|
lobbyRegexes: ["^lobby[1-9]?[1-9]?$", "^test/.+$"],
|
||||||
|
lobbyBackdoor: "lolwutsecretlobbybackdoor",
|
||||||
|
fullChannel: "test/awkward"
|
||||||
|
});
|
||||||
|
|
||||||
|
export const channelList = new Array<Channel>();
|
||||||
|
|
||||||
export class Channel {
|
export class Channel {
|
||||||
constructor(private _id: string) {}
|
private settings: Partial<ChannelSettings> = config.defaultSettings;
|
||||||
|
private ppl = new Array<Participant>();
|
||||||
|
|
||||||
getID() {
|
public logger: Logger;
|
||||||
|
|
||||||
|
// TODO Add the crown
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private _id: string,
|
||||||
|
set: Partial<ChannelSettings> = config.defaultSettings
|
||||||
|
) {
|
||||||
|
this.logger = new Logger("Channel - " + _id);
|
||||||
|
// Verify default settings just in case
|
||||||
|
this.changeSettings(this.settings, true);
|
||||||
|
|
||||||
|
if (this.isLobby()) {
|
||||||
|
set = config.lobbySettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.changeSettings(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getID() {
|
||||||
return this._id;
|
return this._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
isLobby() {}
|
public isLobby() {
|
||||||
|
for (const reg of config.lobbyRegexes) {
|
||||||
|
let exp = new RegExp(reg, "g");
|
||||||
|
|
||||||
|
if (this.getID().match(exp)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public changeSettings(
|
||||||
|
set: Partial<ChannelSettings>,
|
||||||
|
admin: boolean = false
|
||||||
|
) {
|
||||||
|
if (!admin) {
|
||||||
|
if (set.lobby) set.lobby = undefined;
|
||||||
|
if (set.owner_id) set.owner_id = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify settings
|
||||||
|
const validSettings = validateChannelSettings(set);
|
||||||
|
|
||||||
|
for (const key of Object.keys(validSettings)) {
|
||||||
|
// Setting is valid?
|
||||||
|
if ((validSettings as Record<string, boolean>)[key]) {
|
||||||
|
// Change setting
|
||||||
|
(this.settings as Record<string, ChannelSettingValue>)[key] = (
|
||||||
|
set as Record<string, ChannelSettingValue>
|
||||||
|
)[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public join(socket: Socket) {
|
||||||
|
const part = socket.getParticipant();
|
||||||
|
|
||||||
|
// Unknown side-effects, but for type safety...
|
||||||
|
if (!part) return;
|
||||||
|
|
||||||
|
let hasChangedChannel = false;
|
||||||
|
|
||||||
|
this.logger.debug("Has user?", this.hasUser(part));
|
||||||
|
|
||||||
|
// Is user in this channel?
|
||||||
|
if (this.hasUser(part)) {
|
||||||
|
// Alreay in channel, disconnect old
|
||||||
|
|
||||||
|
const oldSocket = findSocketByPartID(part.id);
|
||||||
|
|
||||||
|
if (oldSocket) {
|
||||||
|
oldSocket.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to channel
|
||||||
|
this.ppl.push(part);
|
||||||
|
hasChangedChannel = true;
|
||||||
|
} else {
|
||||||
|
// Are we full?
|
||||||
|
if (!this.isFull()) {
|
||||||
|
// Add to channel
|
||||||
|
this.ppl.push(part);
|
||||||
|
hasChangedChannel = true;
|
||||||
|
} else {
|
||||||
|
// Put us in full channel
|
||||||
|
socket.setChannel(config.fullChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasChangedChannel) {
|
||||||
|
// Is user in any channel that isn't this one?
|
||||||
|
for (const ch of channelList) {
|
||||||
|
if (ch == this) continue;
|
||||||
|
if (ch.hasUser(part)) {
|
||||||
|
ch.leave(socket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.debug("Participant list:", this.ppl);
|
||||||
|
|
||||||
|
// Send our data back
|
||||||
|
socket.sendArray([
|
||||||
|
{
|
||||||
|
m: "ch",
|
||||||
|
ch: this.getInfo(),
|
||||||
|
p: part.id,
|
||||||
|
ppl: this.getParticipantList()
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// TODO Broadcast channel update
|
||||||
|
}
|
||||||
|
|
||||||
|
public leave(socket: Socket) {
|
||||||
|
this.logger.debug("Leave called");
|
||||||
|
const part = socket.getParticipant();
|
||||||
|
|
||||||
|
// Same as above...
|
||||||
|
if (!part) return;
|
||||||
|
|
||||||
|
if (this.hasUser(part)) {
|
||||||
|
this.ppl.splice(this.ppl.indexOf(part), 1);
|
||||||
|
}
|
||||||
|
// TODO Broadcast channel update
|
||||||
|
}
|
||||||
|
|
||||||
|
public isFull() {
|
||||||
|
// TODO Use limit setting
|
||||||
|
|
||||||
|
if (this.isLobby() && this.ppl.length >= 20) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getInfo() {
|
||||||
|
return {
|
||||||
|
_id: this.getID(),
|
||||||
|
id: this.getID(),
|
||||||
|
count: this.ppl.length,
|
||||||
|
settings: this.settings
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public getParticipantList() {
|
||||||
|
return this.ppl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasUser(part: Participant) {
|
||||||
|
const foundPart = this.ppl.find(p => p._id == part._id);
|
||||||
|
return !!foundPart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forceloader
|
||||||
|
let hasFullChannel = false;
|
||||||
|
|
||||||
|
for (const id of config.forceLoad) {
|
||||||
|
channelList.push(new Channel(id));
|
||||||
|
if (id == config.fullChannel) hasFullChannel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasFullChannel) {
|
||||||
|
channelList.push(new Channel(config.fullChannel));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
import env from "./util/env";
|
import env from "./util/env";
|
||||||
import { app } from "./ws/server";
|
// import { app } from "./ws/server";
|
||||||
|
import "./ws/server";
|
||||||
import { Logger } from "./util/Logger";
|
import { Logger } from "./util/Logger";
|
||||||
|
|
||||||
const logger = new Logger("Main");
|
const logger = new Logger("Main");
|
||||||
|
|
||||||
// No IPv6 (yet)
|
|
||||||
app.listen("0.0.0.0", env.PORT, () => {
|
|
||||||
logger.info("Listening on :" + env.PORT);
|
|
||||||
});
|
|
||||||
|
|
|
@ -100,9 +100,10 @@ declare interface ChannelInfo {
|
||||||
id: string;
|
id: string;
|
||||||
_id: string;
|
_id: string;
|
||||||
crown?: Crown;
|
crown?: Crown;
|
||||||
settings: ChannelSettings;
|
settings: Partial<ChannelSettings>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Events copied from Hri7566/mppclone-client typedefs
|
||||||
declare interface ServerEvents {
|
declare interface ServerEvents {
|
||||||
a: {
|
a: {
|
||||||
m: "a";
|
m: "a";
|
||||||
|
@ -246,6 +247,7 @@ declare interface ClientEvents {
|
||||||
m: "ch";
|
m: "ch";
|
||||||
p: string;
|
p: string;
|
||||||
ch: ChannelInfo;
|
ch: ChannelInfo;
|
||||||
|
ppl: Participant[];
|
||||||
};
|
};
|
||||||
|
|
||||||
custom: {
|
custom: {
|
||||||
|
@ -284,6 +286,7 @@ declare interface ClientEvents {
|
||||||
};
|
};
|
||||||
|
|
||||||
notification: {
|
notification: {
|
||||||
|
m: "notification";
|
||||||
duration?: number;
|
duration?: number;
|
||||||
class?: string;
|
class?: string;
|
||||||
id?: string;
|
id?: string;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { WebSocket } from "uWebSockets.js";
|
|
||||||
import { createColor, createID, createUserID } from "../util/id";
|
import { createColor, createID, createUserID } from "../util/id";
|
||||||
import { decoder, encoder } from "../util/helpers";
|
import { decoder, encoder } from "../util/helpers";
|
||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
|
@ -8,6 +7,8 @@ import { createUser, readUser } from "../data/user";
|
||||||
import { eventGroups } from "./events";
|
import { eventGroups } from "./events";
|
||||||
import { loadConfig } from "../util/config";
|
import { loadConfig } from "../util/config";
|
||||||
import { Gateway } from "./Gateway";
|
import { Gateway } from "./Gateway";
|
||||||
|
import { Channel, channelList } from "../channel/Channel";
|
||||||
|
import { ServerWebSocket } from "bun";
|
||||||
|
|
||||||
interface UsersConfig {
|
interface UsersConfig {
|
||||||
defaultName: string;
|
defaultName: string;
|
||||||
|
@ -31,17 +32,17 @@ export class Socket extends EventEmitter {
|
||||||
|
|
||||||
public desiredChannel: {
|
public desiredChannel: {
|
||||||
_id: string | undefined;
|
_id: string | undefined;
|
||||||
set: Partial<ChannelSettings>;
|
set: Partial<ChannelSettings> | undefined;
|
||||||
} = {
|
} = {
|
||||||
_id: undefined,
|
_id: undefined,
|
||||||
set: {}
|
set: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private ws: WebSocket<unknown>) {
|
public currentChannelID: string | undefined;
|
||||||
super();
|
|
||||||
this.ip = decoder.decode(this.ws.getRemoteAddressAsText());
|
|
||||||
|
|
||||||
// Participant ID
|
constructor(private ws: ServerWebSocket<unknown>) {
|
||||||
|
super();
|
||||||
|
this.ip = ws.remoteAddress; // Participant ID
|
||||||
this.id = createID();
|
this.id = createID();
|
||||||
|
|
||||||
// User ID
|
// User ID
|
||||||
|
@ -61,9 +62,40 @@ export class Socket extends EventEmitter {
|
||||||
return this._id;
|
return this._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setChannel(_id: string, set: Partial<ChannelSettings>) {
|
public getParticipantID() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setChannel(_id: string, set?: Partial<ChannelSettings>) {
|
||||||
|
if (this.isDestroyed()) return;
|
||||||
|
|
||||||
this.desiredChannel._id = _id;
|
this.desiredChannel._id = _id;
|
||||||
this.desiredChannel.set = set;
|
this.desiredChannel.set = set;
|
||||||
|
|
||||||
|
let channel;
|
||||||
|
try {
|
||||||
|
for (const ch of channelList.values()) {
|
||||||
|
if (ch.getID() == this.desiredChannel._id) {
|
||||||
|
channel = ch;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {}
|
||||||
|
|
||||||
|
// Does channel exist?
|
||||||
|
if (channel) {
|
||||||
|
// Exists, join normally
|
||||||
|
channel.join(this);
|
||||||
|
} else {
|
||||||
|
// Doesn't exist, join with crown
|
||||||
|
channel = new Channel(
|
||||||
|
this.desiredChannel._id,
|
||||||
|
this.desiredChannel.set
|
||||||
|
);
|
||||||
|
|
||||||
|
channel.join(this);
|
||||||
|
// TODO Give the crown upon joining
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bindEventListeners() {
|
private bindEventListeners() {
|
||||||
|
@ -80,7 +112,8 @@ export class Socket extends EventEmitter {
|
||||||
public sendArray<EventID extends keyof ClientEvents>(
|
public sendArray<EventID extends keyof ClientEvents>(
|
||||||
arr: ClientEvents[EventID][]
|
arr: ClientEvents[EventID][]
|
||||||
) {
|
) {
|
||||||
this.ws.send(encoder.encode(JSON.stringify(arr)));
|
if (this.isDestroyed()) return;
|
||||||
|
this.ws.send(JSON.stringify(arr));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async loadUser() {
|
private async loadUser() {
|
||||||
|
@ -142,7 +175,27 @@ export class Socket extends EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getParticipantID() {
|
private destroyed = false;
|
||||||
return this.id;
|
|
||||||
|
public destroy() {
|
||||||
|
// Socket was closed or should be closed, clear data
|
||||||
|
|
||||||
|
// Simulate closure
|
||||||
|
try {
|
||||||
|
this.ws.close();
|
||||||
|
} catch (err) {}
|
||||||
|
|
||||||
|
if (this.currentChannelID) {
|
||||||
|
const foundCh = channelList.find(
|
||||||
|
ch => ch.getID() == this.currentChannelID
|
||||||
|
);
|
||||||
|
if (foundCh) foundCh.leave(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.destroyed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public isDestroyed() {
|
||||||
|
return this.destroyed == true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
import "./events/user";
|
// Bun hoists import, but not require?
|
||||||
import "./events/admin";
|
require("./events/user");
|
||||||
|
require("./events/admin");
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { ServerEventListener } from "../../../../util/types";
|
||||||
|
import { eventGroups } from "../../../events";
|
||||||
|
|
||||||
|
export const ch: ServerEventListener<"ch"> = {
|
||||||
|
id: "ch",
|
||||||
|
callback: (msg, socket) => {
|
||||||
|
// Switch channel
|
||||||
|
if (!msg._id) return;
|
||||||
|
socket.setChannel(msg._id, msg.set);
|
||||||
|
}
|
||||||
|
};
|
|
@ -12,7 +12,7 @@ export const hi: ServerEventListener<"hi"> = {
|
||||||
_id: socket.getUserID(),
|
_id: socket.getUserID(),
|
||||||
name: "Anonymous",
|
name: "Anonymous",
|
||||||
color: "#777",
|
color: "#777",
|
||||||
id: socket.getParticipantID()
|
id: socket.getUserID()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,10 @@ export const EVENTGROUP_USER = new EventGroup("user");
|
||||||
|
|
||||||
import { hi } from "./handlers/hi";
|
import { hi } from "./handlers/hi";
|
||||||
import { devices } from "./handlers/devices";
|
import { devices } from "./handlers/devices";
|
||||||
|
import { ch } from "./handlers/ch";
|
||||||
|
|
||||||
EVENTGROUP_USER.add(hi);
|
EVENTGROUP_USER.add(hi);
|
||||||
EVENTGROUP_USER.add(devices);
|
EVENTGROUP_USER.add(devices);
|
||||||
|
EVENTGROUP_USER.add(ch);
|
||||||
|
|
||||||
eventGroups.push(EVENTGROUP_USER);
|
eventGroups.push(EVENTGROUP_USER);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { WebSocket } from "uWebSockets.js";
|
|
||||||
import { Logger } from "../util/Logger";
|
import { Logger } from "../util/Logger";
|
||||||
import { Socket } from "./Socket";
|
import { Socket } from "./Socket";
|
||||||
import { hasOwn } from "../util/helpers";
|
import { hasOwn } from "../util/helpers";
|
||||||
|
|
218
src/ws/server.ts
218
src/ws/server.ts
|
@ -1,97 +1,165 @@
|
||||||
import {
|
// import {
|
||||||
App,
|
// App,
|
||||||
DEDICATED_COMPRESSOR_8KB,
|
// DEDICATED_COMPRESSOR_8KB,
|
||||||
HttpRequest,
|
// HttpRequest,
|
||||||
HttpResponse,
|
// HttpResponse,
|
||||||
WebSocket
|
// WebSocket
|
||||||
} from "uWebSockets.js";
|
// } from "uWebSockets.js";
|
||||||
import { Logger } from "../util/Logger";
|
import { Logger } from "../util/Logger";
|
||||||
import { createUserID } from "../util/id";
|
import { createUserID } from "../util/id";
|
||||||
import { readFileSync, lstatSync } from "fs";
|
import fs from "fs";
|
||||||
import { join } from "path/posix";
|
// import { join } from "path";
|
||||||
|
import path from "path";
|
||||||
import { handleMessage } from "./message";
|
import { handleMessage } from "./message";
|
||||||
import { decoder } from "../util/helpers";
|
import { decoder } from "../util/helpers";
|
||||||
import { Socket } from "./Socket";
|
import { Socket } from "./Socket";
|
||||||
|
import { serve, file } from "bun";
|
||||||
|
import env from "../util/env";
|
||||||
|
|
||||||
const logger = new Logger("WebSocket Server");
|
const logger = new Logger("WebSocket Server");
|
||||||
|
|
||||||
export const app = App()
|
const usersByPartID = new Map<string, Socket>();
|
||||||
.get("/*", async (res, req) => {
|
|
||||||
const url = req.getUrl();
|
export function findSocketByPartID(id: string) {
|
||||||
const ip = decoder.decode(res.getRemoteAddressAsText());
|
for (const key of usersByPartID.keys()) {
|
||||||
|
if (key == id) return usersByPartID.get(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Original uWebSockets code
|
||||||
|
// export const app = App()
|
||||||
|
// .get("/*", async (res, req) => {
|
||||||
|
// const url = req.getUrl();
|
||||||
|
// const ip = decoder.decode(res.getRemoteAddressAsText());
|
||||||
|
// // logger.debug(`${req.getMethod()} ${url} ${ip}`);
|
||||||
|
// // res.writeStatus(`200 OK`).end("HI!");
|
||||||
|
// const file = join("./public/", url);
|
||||||
|
|
||||||
|
// // TODO Cleaner file serving
|
||||||
|
// try {
|
||||||
|
// const stats = lstatSync(file);
|
||||||
|
|
||||||
|
// let data;
|
||||||
|
// if (!stats.isDirectory()) {
|
||||||
|
// data = readFileSync(file);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // logger.debug(filename);
|
||||||
|
|
||||||
|
// if (!data) {
|
||||||
|
// const index = readFileSync("./public/index.html");
|
||||||
|
|
||||||
|
// if (!index) {
|
||||||
|
// return void res
|
||||||
|
// .writeStatus(`404 Not Found`)
|
||||||
|
// .end("uh oh :(");
|
||||||
|
// } else {
|
||||||
|
// return void res.writeStatus(`200 OK`).end(index);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// res.writeStatus(`200 OK`).end(data);
|
||||||
|
// } catch (err) {
|
||||||
|
// logger.warn("Unable to serve file at", file);
|
||||||
|
// logger.error(err);
|
||||||
|
// const index = readFileSync("./public/index.html");
|
||||||
|
|
||||||
|
// if (!index) {
|
||||||
|
// return void res.writeStatus(`404 Not Found`).end("uh oh :(");
|
||||||
|
// } else {
|
||||||
|
// return void res.writeStatus(`200 OK`).end(index);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// .ws("/*", {
|
||||||
|
// idleTimeout: 25,
|
||||||
|
// maxBackpressure: 1024,
|
||||||
|
// maxPayloadLength: 8192,
|
||||||
|
// compression: DEDICATED_COMPRESSOR_8KB,
|
||||||
|
|
||||||
|
// open: ((ws: WebSocket<unknown> & { socket: Socket }) => {
|
||||||
|
// ws.socket = new Socket(ws);
|
||||||
|
// // logger.debug("Connection at " + ws.socket.getIP());
|
||||||
|
|
||||||
|
// usersByPartID.set(ws.socket.getParticipantID(), ws.socket);
|
||||||
|
// }) as (ws: WebSocket<unknown>) => void,
|
||||||
|
|
||||||
|
// message: ((
|
||||||
|
// ws: WebSocket<unknown> & { socket: Socket },
|
||||||
|
// message,
|
||||||
|
// isBinary
|
||||||
|
// ) => {
|
||||||
|
// const msg = decoder.decode(message);
|
||||||
|
// handleMessage(ws.socket, msg);
|
||||||
|
// }) as (
|
||||||
|
// ws: WebSocket<unknown>,
|
||||||
|
// message: ArrayBuffer,
|
||||||
|
// isBinary: boolean
|
||||||
|
// ) => void,
|
||||||
|
|
||||||
|
// close: ((
|
||||||
|
// ws: WebSocket<unknown> & { socket: Socket },
|
||||||
|
// code: number,
|
||||||
|
// message: ArrayBuffer
|
||||||
|
// ) => {
|
||||||
|
// logger.debug("Close called");
|
||||||
|
// ws.socket.destroy();
|
||||||
|
// usersByPartID.delete(ws.socket.getParticipantID());
|
||||||
|
// }) as (
|
||||||
|
// ws: WebSocket<unknown>,
|
||||||
|
// code: number,
|
||||||
|
// message: ArrayBuffer
|
||||||
|
// ) => void
|
||||||
|
// });
|
||||||
|
|
||||||
|
export const app = Bun.serve({
|
||||||
|
port: env.PORT,
|
||||||
|
fetch: (req, server) => {
|
||||||
|
if (server.upgrade(req)) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const url = new URL(req.url).pathname;
|
||||||
|
// const ip = decoder.decode(res.getRemoteAddressAsText());
|
||||||
// logger.debug(`${req.getMethod()} ${url} ${ip}`);
|
// logger.debug(`${req.getMethod()} ${url} ${ip}`);
|
||||||
// res.writeStatus(`200 OK`).end("HI!");
|
// res.writeStatus(`200 OK`).end("HI!");
|
||||||
const file = join("./public/", url);
|
const file = path.join("./public/", url);
|
||||||
|
|
||||||
// TODO Cleaner file serving
|
|
||||||
try {
|
try {
|
||||||
const stats = lstatSync(file);
|
if (fs.lstatSync(file).isFile()) {
|
||||||
|
const data = Bun.file(file);
|
||||||
|
|
||||||
let data;
|
if (data) {
|
||||||
if (!stats.isDirectory()) {
|
return new Response(data);
|
||||||
data = readFileSync(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// logger.debug(filename);
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
const index = readFileSync("./public/index.html");
|
|
||||||
|
|
||||||
if (!index) {
|
|
||||||
return void res
|
|
||||||
.writeStatus(`404 Not Found`)
|
|
||||||
.end("uh oh :(");
|
|
||||||
} else {
|
} else {
|
||||||
return void res.writeStatus(`200 OK`).end(index);
|
return new Response(Bun.file("./public/index.html"));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return new Response(Bun.file("./public/index.html"));
|
||||||
}
|
}
|
||||||
|
|
||||||
res.writeStatus(`200 OK`).end(data);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.warn("Unable to serve file at", file);
|
return new Response(Bun.file("./public/index.html"));
|
||||||
logger.error(err);
|
|
||||||
const index = readFileSync("./public/index.html");
|
|
||||||
|
|
||||||
if (!index) {
|
|
||||||
return void res.writeStatus(`404 Not Found`).end("uh oh :(");
|
|
||||||
} else {
|
|
||||||
return void res.writeStatus(`200 OK`).end(index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
.ws("/*", {
|
websocket: {
|
||||||
idleTimeout: 180,
|
open: ws => {
|
||||||
maxBackpressure: 1024,
|
const socket = new Socket(ws);
|
||||||
maxPayloadLength: 8192,
|
(ws as unknown as any).socket = socket;
|
||||||
compression: DEDICATED_COMPRESSOR_8KB,
|
logger.debug("Connection at " + socket.getIP());
|
||||||
|
|
||||||
open: ((ws: WebSocket<unknown> & { socket: Socket }) => {
|
usersByPartID.set(socket.getParticipantID(), socket);
|
||||||
ws.socket = new Socket(ws);
|
},
|
||||||
// logger.debug("Connection at " + ws.socket.getIP());
|
|
||||||
}) as (ws: WebSocket<unknown>) => void,
|
|
||||||
|
|
||||||
message: ((
|
message: (ws, message) => {
|
||||||
ws: WebSocket<unknown> & { socket: Socket },
|
const msg = message.toString();
|
||||||
message,
|
handleMessage((ws as unknown as any).socket, msg);
|
||||||
isBinary
|
},
|
||||||
) => {
|
|
||||||
const msg = decoder.decode(message);
|
|
||||||
handleMessage(ws.socket, msg);
|
|
||||||
}) as (
|
|
||||||
ws: WebSocket<unknown>,
|
|
||||||
message: ArrayBuffer,
|
|
||||||
isBinary: boolean
|
|
||||||
) => void,
|
|
||||||
|
|
||||||
close: ((
|
close: (ws, code, message) => {
|
||||||
ws: WebSocket<unknown> & { socket: Socket },
|
logger.debug("Close called");
|
||||||
code: number,
|
const socket = (ws as unknown as any).socket as Socket;
|
||||||
message: ArrayBuffer
|
socket.destroy();
|
||||||
) => {
|
usersByPartID.delete(socket.getParticipantID());
|
||||||
// TODO handle close event
|
}
|
||||||
}) as (
|
}
|
||||||
ws: WebSocket<unknown>,
|
});
|
||||||
code: number,
|
|
||||||
message: ArrayBuffer
|
|
||||||
) => void
|
|
||||||
});
|
|
||||||
|
|
|
@ -11,8 +11,10 @@
|
||||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||||
|
|
||||||
/* Language and Environment */
|
/* Language and Environment */
|
||||||
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
// "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||||
|
"target": "ESNext",
|
||||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||||
|
"lib": ["ESNext"],
|
||||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||||
|
@ -23,20 +25,25 @@
|
||||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||||
|
"moduleDetection": "force",
|
||||||
|
|
||||||
/* Modules */
|
/* Modules */
|
||||||
"module": "commonjs" /* Specify what module code is generated. */,
|
// "module": "commonjs" /* Specify what module code is generated. */,
|
||||||
|
"module": "ESNext",
|
||||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||||
"rootDir": "./src/",
|
"rootDir": "./src/",
|
||||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||||
|
"moduleResolution": "Bundler",
|
||||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||||
|
"types": ["bun-types"],
|
||||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||||
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
||||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
||||||
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||||
|
@ -60,6 +67,7 @@
|
||||||
"outDir": "./out/",
|
"outDir": "./out/",
|
||||||
// "removeComments": true, /* Disable emitting comments. */
|
// "removeComments": true, /* Disable emitting comments. */
|
||||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||||
|
"noEmit": true,
|
||||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||||
|
|
Loading…
Reference in New Issue