Commit f51e04d7 authored by nanahira's avatar nanahira

unfinished

parent 9182abd9
Pipeline #43129 passed with stages
in 2 minutes and 23 seconds
...@@ -9,12 +9,13 @@ ...@@ -9,12 +9,13 @@
"version": "1.0.0", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"aragami": "^1.2.10",
"axios": "^1.13.5", "axios": "^1.13.5",
"http-proxy-agent": "^7.0.2", "http-proxy-agent": "^7.0.2",
"https-proxy-agent": "^7.0.6", "https-proxy-agent": "^7.0.6",
"ipaddr.js": "^2.3.0", "ipaddr.js": "^2.3.0",
"koishipro-core.js": "^1.3.0", "koishipro-core.js": "^1.3.1",
"nfkit": "^1.0.22", "nfkit": "^1.0.24",
"pino": "^10.3.1", "pino": "^10.3.1",
"pino-pretty": "^13.1.3", "pino-pretty": "^13.1.3",
"rxjs": "^7.8.2", "rxjs": "^7.8.2",
...@@ -73,7 +74,6 @@ ...@@ -73,7 +74,6 @@
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.29.0", "@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0", "@babel/generator": "^7.29.0",
...@@ -776,6 +776,12 @@ ...@@ -776,6 +776,12 @@
"dev": true, "dev": true,
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/@ioredis/commands": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.0.tgz",
"integrity": "sha512-eUgLqrMf8nJkZxT24JvVRrQya1vZkQh8BBeYNwGDqa5I0VUi8ACx7uFvAaLxintokpTenkK6DASvo/bvNbBGow==",
"license": "MIT"
},
"node_modules/@isaacs/cliui": { "node_modules/@isaacs/cliui": {
"version": "8.0.2", "version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
...@@ -1422,6 +1428,18 @@ ...@@ -1422,6 +1428,18 @@
"url": "https://opencollective.com/pkgr" "url": "https://opencollective.com/pkgr"
} }
}, },
"node_modules/@sesamecare-oss/redlock": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@sesamecare-oss/redlock/-/redlock-1.4.0.tgz",
"integrity": "sha512-2z589R+yxKLN4CgKxP1oN4dsg6Y548SE4bVYam/R0kHk7Q9VrQ9l66q+k1ehhSLLY4or9hcchuF9/MhuuZdjJg==",
"license": "UNLICENSED",
"engines": {
"node": ">=16"
},
"peerDependencies": {
"ioredis": ">=5"
}
},
"node_modules/@sinclair/typebox": { "node_modules/@sinclair/typebox": {
"version": "0.34.48", "version": "0.34.48",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz",
...@@ -1582,7 +1600,6 @@ ...@@ -1582,7 +1600,6 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz",
"integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"undici-types": "~7.16.0" "undici-types": "~7.16.0"
} }
...@@ -1666,7 +1683,6 @@ ...@@ -1666,7 +1683,6 @@
"integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==", "integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/scope-manager": "8.55.0",
"@typescript-eslint/types": "8.55.0", "@typescript-eslint/types": "8.55.0",
...@@ -2147,7 +2163,6 @@ ...@@ -2147,7 +2163,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
...@@ -2273,6 +2288,31 @@ ...@@ -2273,6 +2288,31 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/aragami": {
"version": "1.2.10",
"resolved": "https://registry.npmjs.org/aragami/-/aragami-1.2.10.tgz",
"integrity": "sha512-rYfuqDEkVSffse2ncDIg2FEFPbbP/z8T4/RuZj/qQOTJtgddFSKnbI9U4zSYXVZkQR7LtsbjfMnG+y1wAFBFbQ==",
"license": "MIT",
"dependencies": {
"@sesamecare-oss/redlock": "^1.4.0",
"better-lock": "^2.0.3",
"class-transformer": "^0.5.1",
"encoded-buffer": "^0.2.6",
"generic-pool": "^3.9.0",
"ioredis": "^5.2.3",
"lru-cache": "^7.13.1",
"typed-reflector": "^1.0.12"
}
},
"node_modules/aragami/node_modules/lru-cache": {
"version": "7.18.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/arg": { "node_modules/arg": {
"version": "4.1.3", "version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
...@@ -2302,6 +2342,21 @@ ...@@ -2302,6 +2342,21 @@
"node": ">=8.0.0" "node": ">=8.0.0"
} }
}, },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
"license": "MIT",
"dependencies": {
"possible-typed-array-names": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/axios": { "node_modules/axios": {
"version": "1.13.5", "version": "1.13.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
...@@ -2449,6 +2504,12 @@ ...@@ -2449,6 +2504,12 @@
"baseline-browser-mapping": "dist/cli.js" "baseline-browser-mapping": "dist/cli.js"
} }
}, },
"node_modules/better-lock": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/better-lock/-/better-lock-2.0.3.tgz",
"integrity": "sha512-3bCaToLrmEXZcIOOVWgi1STvp3/6EpoZAmlWBeuX2MvDB0Ql2ctl/vQ0CbhQIJYQiptdGypllP3ez+TeEmdnKQ==",
"license": "MIT"
},
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
...@@ -2492,7 +2553,6 @@ ...@@ -2492,7 +2553,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.9.0", "baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759", "caniuse-lite": "^1.0.30001759",
...@@ -2561,6 +2621,24 @@ ...@@ -2561,6 +2621,24 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/call-bind": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.0",
"es-define-property": "^1.0.0",
"get-intrinsic": "^1.2.4",
"set-function-length": "^1.2.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/call-bind-apply-helpers": { "node_modules/call-bind-apply-helpers": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
...@@ -2574,6 +2652,22 @@ ...@@ -2574,6 +2652,22 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/call-bound": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/callsites": { "node_modules/callsites": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
...@@ -2665,6 +2759,12 @@ ...@@ -2665,6 +2759,12 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/class-transformer": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
"license": "MIT"
},
"node_modules/cliui": { "node_modules/cliui": {
"version": "8.0.1", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
...@@ -2720,6 +2820,15 @@ ...@@ -2720,6 +2820,15 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1" "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
} }
}, },
"node_modules/cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/co": { "node_modules/co": {
"version": "4.6.0", "version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
...@@ -2876,6 +2985,23 @@ ...@@ -2876,6 +2985,23 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delayed-stream": { "node_modules/delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
...@@ -2885,6 +3011,15 @@ ...@@ -2885,6 +3011,15 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10"
}
},
"node_modules/detect-newline": { "node_modules/detect-newline": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
...@@ -2966,6 +3101,24 @@ ...@@ -2966,6 +3101,24 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/encoded-buffer": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/encoded-buffer/-/encoded-buffer-0.2.6.tgz",
"integrity": "sha512-zEskqXs0FbF9HcwZkumyAoiB3NN23yAoJvPmLP0NuWQLXTeCDMeVRYK1kjIsZPkoXE2cIBS0iht95pqf8UKyog==",
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
"license": "MIT",
"dependencies": {
"lodash": "^4.17.10",
"to-buffer": "^1.1.1",
"tslib": "^1.9.3"
}
},
"node_modules/encoded-buffer/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"license": "0BSD"
},
"node_modules/end-of-stream": { "node_modules/end-of-stream": {
"version": "1.4.5", "version": "1.4.5",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
...@@ -3060,7 +3213,6 @@ ...@@ -3060,7 +3213,6 @@
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
...@@ -3117,7 +3269,6 @@ ...@@ -3117,7 +3269,6 @@
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"eslint-config-prettier": "bin/cli.js" "eslint-config-prettier": "bin/cli.js"
}, },
...@@ -3505,6 +3656,21 @@ ...@@ -3505,6 +3656,21 @@
} }
} }
}, },
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
"license": "MIT",
"dependencies": {
"is-callable": "^1.2.7"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/foreground-child": { "node_modules/foreground-child": {
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
...@@ -3569,6 +3735,15 @@ ...@@ -3569,6 +3735,15 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/generic-pool": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
"integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==",
"license": "MIT",
"engines": {
"node": ">= 4"
}
},
"node_modules/gensync": { "node_modules/gensync": {
"version": "1.0.0-beta.2", "version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
...@@ -3758,6 +3933,18 @@ ...@@ -3758,6 +3933,18 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/has-property-descriptors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": { "node_modules/has-symbols": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
...@@ -3947,6 +4134,30 @@ ...@@ -3947,6 +4134,30 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/ioredis": {
"version": "5.9.2",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.2.tgz",
"integrity": "sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==",
"license": "MIT",
"dependencies": {
"@ioredis/commands": "1.5.0",
"cluster-key-slot": "^1.1.0",
"debug": "^4.3.4",
"denque": "^2.1.0",
"lodash.defaults": "^4.2.0",
"lodash.isarguments": "^3.1.0",
"redis-errors": "^1.2.0",
"redis-parser": "^3.0.0",
"standard-as-callback": "^2.1.0"
},
"engines": {
"node": ">=12.22.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/ioredis"
}
},
"node_modules/ipaddr.js": { "node_modules/ipaddr.js": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz",
...@@ -3963,6 +4174,18 @@ ...@@ -3963,6 +4174,18 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-extglob": { "node_modules/is-extglob": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
...@@ -4039,6 +4262,21 @@ ...@@ -4039,6 +4262,21 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/is-typed-array": {
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
"license": "MIT",
"dependencies": {
"which-typed-array": "^1.1.16"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/isarray": { "node_modules/isarray": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
...@@ -4145,7 +4383,6 @@ ...@@ -4145,7 +4383,6 @@
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@jest/core": "30.2.0", "@jest/core": "30.2.0",
"@jest/types": "30.2.0", "@jest/types": "30.2.0",
...@@ -4839,9 +5076,9 @@ ...@@ -4839,9 +5076,9 @@
} }
}, },
"node_modules/koishipro-core.js": { "node_modules/koishipro-core.js": {
"version": "1.3.0", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/koishipro-core.js/-/koishipro-core.js-1.3.0.tgz", "resolved": "https://registry.npmjs.org/koishipro-core.js/-/koishipro-core.js-1.3.1.tgz",
"integrity": "sha512-4OTcPmA/xDVw3Mr0nfWPQbTCWgMsk6ehBNWX6eMqLz8KcgNMYICtSzvV+cUdauPEr1bwIyskiOIiWz3dZQ0IDw==", "integrity": "sha512-XI02RzvWuAbPyHYGlhezo3B+bc/h2cTyUp/HJtiYXrUHyrW9OcoZmau/v451BJgdHC/BB/vZwpTV+h+GUtGuzw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/emscripten": "^1.41.5", "@types/emscripten": "^1.41.5",
...@@ -4911,6 +5148,24 @@ ...@@ -4911,6 +5148,24 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/lodash": {
"version": "4.17.23",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
"license": "MIT"
},
"node_modules/lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
"license": "MIT"
},
"node_modules/lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
"license": "MIT"
},
"node_modules/lodash.memoize": { "node_modules/lodash.memoize": {
"version": "4.1.2", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
...@@ -5101,9 +5356,9 @@ ...@@ -5101,9 +5356,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/nfkit": { "node_modules/nfkit": {
"version": "1.0.22", "version": "1.0.24",
"resolved": "https://registry.npmjs.org/nfkit/-/nfkit-1.0.22.tgz", "resolved": "https://registry.npmjs.org/nfkit/-/nfkit-1.0.24.tgz",
"integrity": "sha512-w0voG3JpSM2WSxv4rkncwQkY2EdQmSADC7qorduy4JHvO2FWkJnoX+GYYJrihjYWQIRCe8t+vDJ1oa14+eG3NA==", "integrity": "sha512-Av73fUWuEU2rF8Lyng/Y8YIDUDHjeDHqInyKsS0Me+hWlW0TvqIhmK/DMpFS7aXxBf+Fp0btecIVoxXYUmAlnQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/node-int64": { "node_modules/node-int64": {
...@@ -5508,6 +5763,15 @@ ...@@ -5508,6 +5763,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/prelude-ls": { "node_modules/prelude-ls": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
...@@ -5524,7 +5788,6 @@ ...@@ -5524,7 +5788,6 @@
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"
}, },
...@@ -5699,6 +5962,27 @@ ...@@ -5699,6 +5962,27 @@
"node": ">= 12.13.0" "node": ">= 12.13.0"
} }
}, },
"node_modules/redis-errors": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/redis-parser": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
"license": "MIT",
"dependencies": {
"redis-errors": "^1.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/reflect-metadata": { "node_modules/reflect-metadata": {
"version": "0.1.14", "version": "0.1.14",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz",
...@@ -5899,6 +6183,23 @@ ...@@ -5899,6 +6183,23 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/setimmediate": { "node_modules/setimmediate": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
...@@ -6026,6 +6327,12 @@ ...@@ -6026,6 +6327,12 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/standard-as-callback": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
"license": "MIT"
},
"node_modules/string_decoder": { "node_modules/string_decoder": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
...@@ -6329,7 +6636,6 @@ ...@@ -6329,7 +6636,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
...@@ -6344,6 +6650,46 @@ ...@@ -6344,6 +6650,46 @@
"dev": true, "dev": true,
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/to-buffer": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz",
"integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==",
"license": "MIT",
"dependencies": {
"isarray": "^2.0.5",
"safe-buffer": "^5.2.1",
"typed-array-buffer": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/to-buffer/node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
"license": "MIT"
},
"node_modules/to-buffer/node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/to-regex-range": { "node_modules/to-regex-range": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
...@@ -6442,7 +6788,6 @@ ...@@ -6442,7 +6788,6 @@
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@cspotcode/source-map-support": "^0.8.0", "@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7", "@tsconfig/node10": "^1.0.7",
...@@ -6523,6 +6868,20 @@ ...@@ -6523,6 +6868,20 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/typed-array-buffer": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
"is-typed-array": "^1.1.14"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/typed-reflector": { "node_modules/typed-reflector": {
"version": "1.0.14", "version": "1.0.14",
"resolved": "https://registry.npmjs.org/typed-reflector/-/typed-reflector-1.0.14.tgz", "resolved": "https://registry.npmjs.org/typed-reflector/-/typed-reflector-1.0.14.tgz",
...@@ -6538,7 +6897,6 @@ ...@@ -6538,7 +6897,6 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
...@@ -6697,6 +7055,27 @@ ...@@ -6697,6 +7055,27 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/which-typed-array": {
"version": "1.1.20",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz",
"integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==",
"license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"for-each": "^0.3.5",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/word-wrap": { "node_modules/word-wrap": {
"version": "1.2.5", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
......
...@@ -56,12 +56,13 @@ ...@@ -56,12 +56,13 @@
"typescript": "^5.9.3" "typescript": "^5.9.3"
}, },
"dependencies": { "dependencies": {
"aragami": "^1.2.10",
"axios": "^1.13.5", "axios": "^1.13.5",
"http-proxy-agent": "^7.0.2", "http-proxy-agent": "^7.0.2",
"https-proxy-agent": "^7.0.6", "https-proxy-agent": "^7.0.6",
"ipaddr.js": "^2.3.0", "ipaddr.js": "^2.3.0",
"koishipro-core.js": "^1.3.0", "koishipro-core.js": "^1.3.1",
"nfkit": "^1.0.22", "nfkit": "^1.0.24",
"pino": "^10.3.1", "pino": "^10.3.1",
"pino-pretty": "^13.1.3", "pino-pretty": "^13.1.3",
"rxjs": "^7.8.2", "rxjs": "^7.8.2",
......
...@@ -12,6 +12,10 @@ import { YGOProCtosJoinGame } from 'ygopro-msg-encode'; ...@@ -12,6 +12,10 @@ import { YGOProCtosJoinGame } from 'ygopro-msg-encode';
import { TcpServer } from './transport/tcp/server'; import { TcpServer } from './transport/tcp/server';
import { WsServer } from './transport/ws/server'; import { WsServer } from './transport/ws/server';
import { ClientVersionCheck } from './services/client-version-check'; import { ClientVersionCheck } from './services/client-version-check';
import { AragamiService } from './services/aragami';
import { RoomManager } from './room/room-manager';
import { DefaultHostInfoProvider } from './room/default-hostinfo-provder';
import { YGOProResourceLoader } from './services/ygopro-resource-loader';
const core = createAppContext() const core = createAppContext()
.provide(ConfigService, { .provide(ConfigService, {
...@@ -20,6 +24,7 @@ const core = createAppContext() ...@@ -20,6 +24,7 @@ const core = createAppContext()
.provide(Logger, { merge: ['createLogger'] }) .provide(Logger, { merge: ['createLogger'] })
.provide(Emitter, { merge: ['dispatch', 'middleware', 'removeMiddleware'] }) .provide(Emitter, { merge: ['dispatch', 'middleware', 'removeMiddleware'] })
.provide(HttpClient, { merge: ['http'] }) .provide(HttpClient, { merge: ['http'] })
.provide(AragamiService, { merge: ['aragami'] })
.define(); .define();
export type Context = typeof core; export type Context = typeof core;
...@@ -33,6 +38,9 @@ export const app = core ...@@ -33,6 +38,9 @@ export const app = core
.provide(TcpServer) .provide(TcpServer)
.provide(WsServer) .provide(WsServer)
.provide(ClientVersionCheck) .provide(ClientVersionCheck)
.provide(DefaultHostInfoProvider)
.provide(YGOProResourceLoader)
.provide(RoomManager)
.define(); .define();
app.middleware(YGOProCtosJoinGame, async (msg, client, _next) => { app.middleware(YGOProCtosJoinGame, async (msg, client, _next) => {
......
...@@ -8,10 +8,15 @@ import { ...@@ -8,10 +8,15 @@ import {
YGOProStocChat, YGOProStocChat,
ChatColor, ChatColor,
YGOProStocErrorMsg, YGOProStocErrorMsg,
YGOProStocTypeChange,
YGOProStocHsPlayerEnter,
YGOProStocHsPlayerChange,
PlayerChangeState,
} from 'ygopro-msg-encode'; } from 'ygopro-msg-encode';
import { YGOProProtoPipe } from './utility/ygopro-proto-pipe'; import { YGOProProtoPipe } from './utility/ygopro-proto-pipe';
import { I18nService } from './services/i18n'; import { I18nService } from './services/i18n';
import { Chnroute } from './services/chnroute'; import { Chnroute } from './services/chnroute';
import YGOProDeck from 'ygopro-deck-encode';
export abstract class Client { export abstract class Client {
protected abstract _send(data: Buffer): Promise<void>; protected abstract _send(data: Buffer): Promise<void>;
...@@ -20,6 +25,7 @@ export abstract class Client { ...@@ -20,6 +25,7 @@ export abstract class Client {
protected abstract _onDisconnect(): Observable<void>; protected abstract _onDisconnect(): Observable<void>;
abstract physicalIp(): string; abstract physicalIp(): string;
// in handshake
ip = ''; ip = '';
isLocal = false; isLocal = false;
...@@ -29,12 +35,14 @@ export abstract class Client { ...@@ -29,12 +35,14 @@ export abstract class Client {
constructor(protected ctx: Context) {} constructor(protected ctx: Context) {}
receive$!: Observable<YGOProCtosBase>; receive$!: Observable<YGOProCtosBase>;
disconnect$!: Observable<void>; disconnect$!: Observable<{ bySystem: boolean }>;
init() { init() {
this.disconnect$ = merge( this.disconnect$ = merge(
this.disconnectSubject.asObservable(), this.disconnectSubject
this._onDisconnect(), .asObservable()
.pipe(map(() => ({ bySystem: true }))),
this._onDisconnect().pipe(map(() => ({ bySystem: false }))),
).pipe(take(1), share()); ).pipe(take(1), share());
this.receive$ = this._receive().pipe( this.receive$ = this._receive().pipe(
YGOProProtoPipe(YGOProCtos, { YGOProProtoPipe(YGOProCtos, {
...@@ -62,7 +70,7 @@ export abstract class Client { ...@@ -62,7 +70,7 @@ export abstract class Client {
return this; return this;
} }
disconnect() { disconnect(): undefined {
this.disconnectSubject.next(); this.disconnectSubject.next();
this.disconnectSubject.complete(); this.disconnectSubject.complete();
this._disconnect().then(); this._disconnect().then();
...@@ -84,8 +92,8 @@ export abstract class Client { ...@@ -84,8 +92,8 @@ export abstract class Client {
return this.send( return this.send(
new YGOProStocChat().fromPartial({ new YGOProStocChat().fromPartial({
msg: await this.ctx msg: await this.ctx
.get(I18nService) .get(() => I18nService)
.translate(this.ctx.get(Chnroute).getLocale(this.ip), msg), .translate(this.ctx.get(() => Chnroute).getLocale(this.ip), msg),
player_type: type, player_type: type,
}), }),
); );
...@@ -108,10 +116,40 @@ export abstract class Client { ...@@ -108,10 +116,40 @@ export abstract class Client {
return this.ip || this.physicalIp() || 'unknown'; return this.ip || this.physicalIp() || 'unknown';
} }
// in handshake
hostname = ''; hostname = '';
name = ''; name = '';
vpass = ''; vpass = '';
name_vpass = ''; name_vpass = '';
established = false; established = false;
// in room
isHost = false;
pos = -1;
deck?: YGOProDeck;
async sendTypeChange() {
return this.send(
new YGOProStocTypeChange().fromPartial({
isHost: this.isHost,
playerPosition: this.pos,
}),
);
}
prepareEnterPacket() {
return new YGOProStocHsPlayerEnter().fromPartial({
name: this.name,
pos: this.pos,
});
}
prepareChangePacket(state?: PlayerChangeState) {
return new YGOProStocHsPlayerChange().fromPartial({
playerPosition: this.pos,
playerState:
state ??
(this.deck ? PlayerChangeState.READY : PlayerChangeState.NOTREADY),
});
}
} }
import yaml from 'yaml'; import yaml from 'yaml';
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import { DefaultHostinfo } from './room/default-hostinfo';
import { Prettify } from 'nfkit';
export type HostinfoOptions = {
[K in keyof typeof DefaultHostinfo as `HOSTINFO_${Uppercase<K>}`]: string;
};
export const defaultConfig = { export const defaultConfig = {
HOST: '::', HOST: '::',
...@@ -13,9 +19,17 @@ export const defaultConfig = { ...@@ -13,9 +19,17 @@ export const defaultConfig = {
NO_CONNECT_COUNT_LIMIT: '', NO_CONNECT_COUNT_LIMIT: '',
ALT_VERSIONS: '', ALT_VERSIONS: '',
USE_PROXY: '', USE_PROXY: '',
YGOPRO_PATH: './ygopro',
EXTRA_SCRIPT_PATH: '',
...(Object.fromEntries(
Object.entries(DefaultHostinfo).map(([key, value]) => [
`HOSTINFO_${key.toUpperCase()}`,
value.toString(),
]),
) as HostinfoOptions),
}; };
export type Config = typeof defaultConfig; export type Config = Prettify<typeof defaultConfig & HostinfoOptions>;
export function loadConfig(): Config { export function loadConfig(): Config {
let readConfig: Partial<Config> = {}; let readConfig: Partial<Config> = {};
......
import { HostInfo } from 'ygopro-msg-encode';
import { Context } from '../app';
import { DefaultHostinfo } from './default-hostinfo';
export class DefaultHostInfoProvider {
constructor(private ctx: Context) {}
getHostinfo(): HostInfo {
const hostinfo = { ...DefaultHostinfo };
for (const key of Object.keys(hostinfo)) {
const configKey = `HOSTINFO_${key.toUpperCase()}`;
const value = this.ctx.getConfig(configKey as any) as string;
if (value) {
const num = Number(value);
if (!isNaN(num)) {
(hostinfo as any)[key] = num;
}
}
}
return hostinfo;
}
parseHostinfo(name: string, partial: Partial<HostInfo> = {}): HostInfo {
const defaultHostinfo = this.getHostinfo();
const hostinfo: HostInfo = {
...defaultHostinfo,
...partial,
};
if (name.startsWith('M#')) {
hostinfo.mode = 1;
return hostinfo;
}
if (name.startsWith('T#')) {
hostinfo.mode = 2;
hostinfo.start_lp = defaultHostinfo.start_lp * 2;
return hostinfo;
}
if (name.startsWith('AI#')) {
hostinfo.rule = 5;
hostinfo.lflist = -1;
hostinfo.time_limit = 0;
return hostinfo;
}
const compactParam = name.match(
/^(\d)(\d)([12345TF])(T|F)(T|F)(\d+),(\d+),(\d+)/i,
);
if (compactParam) {
hostinfo.rule = Number.parseInt(compactParam[1], 10);
hostinfo.mode = Number.parseInt(compactParam[2], 10);
const duelRuleNumber = Number.parseInt(compactParam[3], 10);
hostinfo.duel_rule = Number.isNaN(duelRuleNumber)
? compactParam[3].toUpperCase() === 'T'
? 3
: 5
: duelRuleNumber;
hostinfo.no_check_deck = compactParam[4].toUpperCase() === 'T' ? 1 : 0;
hostinfo.no_shuffle_deck = compactParam[5].toUpperCase() === 'T' ? 1 : 0;
hostinfo.start_lp = Number.parseInt(compactParam[6], 10);
hostinfo.start_hand = Number.parseInt(compactParam[7], 10);
hostinfo.draw_count = Number.parseInt(compactParam[8], 10);
return hostinfo;
}
const rulePrefix = name.match(/(.+)#/);
if (!rulePrefix) {
return hostinfo;
}
const rule = rulePrefix[1].toUpperCase();
if (/(^|,|,)(M|MATCH)(,|,|$)/.test(rule)) {
hostinfo.mode = 1;
}
if (/(^|,|,)(T|TAG)(,|,|$)/.test(rule)) {
hostinfo.mode = 2;
hostinfo.start_lp = defaultHostinfo.start_lp * 2;
}
if (/(^|,|,)(OOR|OCGONLYRANDOM)(,|,|$)/.test(rule)) {
hostinfo.rule = 0;
hostinfo.lflist = 0;
}
if (/(^|,|,)(OR|OCGRANDOM)(,|,|$)/.test(rule)) {
hostinfo.rule = 5;
hostinfo.lflist = 0;
}
if (/(^|,|,)(CR|CCGRANDOM)(,|,|$)/.test(rule)) {
hostinfo.rule = 2;
hostinfo.lflist = -1;
}
if (/(^|,|,)(TOR|TCGONLYRANDOM)(,|,|$)/.test(rule)) {
hostinfo.rule = 1;
}
if (/(^|,|,)(TR|TCGRANDOM)(,|,|$)/.test(rule)) {
hostinfo.rule = 5;
}
if (/(^|,|,)(OOMR|OCGONLYMATCHRANDOM)(,|,|$)/.test(rule)) {
hostinfo.rule = 0;
hostinfo.lflist = 0;
hostinfo.mode = 1;
}
if (/(^|,|,)(OMR|OCGMATCHRANDOM)(,|,|$)/.test(rule)) {
hostinfo.rule = 5;
hostinfo.lflist = 0;
hostinfo.mode = 1;
}
if (/(^|,|,)(CMR|CCGMATCHRANDOM)(,|,|$)/.test(rule)) {
hostinfo.rule = 2;
hostinfo.lflist = -1;
hostinfo.mode = 1;
}
if (/(^|,|,)(TOMR|TCGONLYMATCHRANDOM)(,|,|$)/.test(rule)) {
hostinfo.rule = 1;
hostinfo.mode = 1;
}
if (/(^|,|,)(TMR|TCGMATCHRANDOM)(,|,|$)/.test(rule)) {
hostinfo.rule = 5;
hostinfo.mode = 1;
}
if (/(^|,|,)(TCGONLY|TO)(,|,|$)/.test(rule)) {
hostinfo.rule = 1;
}
if (/(^|,|,)(OCGONLY|OO)(,|,|$)/.test(rule)) {
hostinfo.rule = 0;
hostinfo.lflist = 0;
}
if (/(^|,|,)(OT|TCG)(,|,|$)/.test(rule)) {
hostinfo.rule = 5;
}
if (/(^|,|,)(SC|CN|CCG|CHINESE)(,|,|$)/.test(rule)) {
hostinfo.rule = 2;
hostinfo.lflist = -1;
}
const lpParam = rule.match(/(^|,|,)LP(\d+)(,|,|$)/);
if (lpParam) {
let startLp = Number.parseInt(lpParam[2], 10);
if (startLp <= 0) startLp = 1;
if (startLp >= 99999) startLp = 99999;
hostinfo.start_lp = startLp;
}
const timeLimitParam = rule.match(/(^|,|,)(TIME|TM|TI)(\d+)(,|,|$)/);
if (timeLimitParam) {
let timeLimit = Number.parseInt(timeLimitParam[3], 10);
if (timeLimit < 0) timeLimit = 180;
if (timeLimit >= 1 && timeLimit <= 60) timeLimit *= 60;
if (timeLimit >= 999) timeLimit = 999;
hostinfo.time_limit = timeLimit;
}
const startHandParam = rule.match(/(^|,|,)(START|ST)(\d+)(,|,|$)/);
if (startHandParam) {
let startHand = Number.parseInt(startHandParam[3], 10);
if (startHand <= 0) startHand = 1;
if (startHand >= 40) startHand = 40;
hostinfo.start_hand = startHand;
}
const drawCountParam = rule.match(/(^|,|,)(DRAW|DR)(\d+)(,|,|$)/);
if (drawCountParam) {
let drawCount = Number.parseInt(drawCountParam[3], 10);
if (drawCount >= 35) drawCount = 35;
hostinfo.draw_count = drawCount;
}
const lflistParam = rule.match(/(^|,|,)(LFLIST|LF)(\d+)(,|,|$)/);
if (lflistParam) {
hostinfo.lflist = Number.parseInt(lflistParam[3], 10) - 1;
}
if (/(^|,|,)(NOLFLIST|NF)(,|,|$)/.test(rule)) {
hostinfo.lflist = -1;
}
if (/(^|,|,)(NOUNIQUE|NU)(,|,|$)/.test(rule)) {
hostinfo.rule = 4;
}
if (/(^|,|,)(CUSTOM|DIY)(,|,|$)/.test(rule)) {
hostinfo.rule = 3;
}
if (/(^|,|,)(NOCHECK|NC)(,|,|$)/.test(rule)) {
hostinfo.no_check_deck = 1;
}
if (/(^|,|,)(NOSHUFFLE|NS)(,|,|$)/.test(rule)) {
hostinfo.no_shuffle_deck = 1;
}
if (/(^|,|,)(IGPRIORITY|PR)(,|,|$)/.test(rule)) {
hostinfo.duel_rule = 4;
}
const duelRuleParam = rule.match(/(^|,|,)(DUELRULE|MR)(\d+)(,|,|$)/);
if (duelRuleParam) {
const duelRule = Number.parseInt(duelRuleParam[3], 10);
if (duelRule > 0 && duelRule <= 5) {
hostinfo.duel_rule = duelRule;
}
}
return hostinfo;
}
}
import { HostInfo } from 'ygopro-msg-encode';
export const DefaultHostinfo: HostInfo = {
lflist: 0, // lflist index
rule: 0, // 0: OCG, 1: TCG, 2: SC, 3: NOUNIQUE, 4: CUSTOM, 5: ALL
mode: 0, // 0: single, 1: match, 2: tag
duel_rule: 5, // 1-5
no_check_deck: 0,
no_shuffle_deck: 0,
start_lp: 8000,
start_hand: 5,
draw_count: 1,
time_limit: 240,
};
import { Context } from '../app';
import { Room } from './room';
export class RoomManager {
constructor(private ctx: Context) {}
private rooms = new Map<string, Room>();
findByName(name: string) {
return this.rooms.get(name);
}
allRooms() {
return Array.from(this.rooms.values());
}
async findOrCreateByName(name: string) {
const existing = this.findByName(name);
if (existing) return existing;
return this.ctx.aragami.lock(`room_create:${name}`, async () => {
const existing = this.findByName(name);
if (existing) return existing;
const room = await new Room(this.ctx, name)
.addFinalizor((r) => {
this.rooms.delete(r.name);
})
.init();
this.rooms.set(name, room);
return room;
});
}
}
import { Awaitable } from 'nfkit';
import { Context } from '../app';
import {
HostInfo,
NetPlayerType,
YGOProStocHsWatchChange,
YGOProStocJoinGame,
} from 'ygopro-msg-encode';
import { DefaultHostInfoProvider } from './default-hostinfo-provder';
import { CardReaderFinalized } from 'koishipro-core.js';
import { YGOProResourceLoader } from '../services/ygopro-resource-loader';
import { blankLFList } from '../utility/blank-lflist';
import { Client } from '../client';
export type RoomFinalizor = (self: Room) => Awaitable<any>;
export class Room {
constructor(
private ctx: Context,
public name: string,
private partialHostinfo: Partial<HostInfo> = {},
) {}
hostinfo = this.ctx
.get(() => DefaultHostInfoProvider)
.parseHostinfo(this.name, this.partialHostinfo);
players = new Array<Client>(this.hostinfo.mode === 2 ? 4 : 2);
watchers = new Set<Client>();
get allPlayers() {
return [...this.players.filter((p) => p), ...this.watchers];
}
private get resourceLoader() {
return this.ctx.get(() => YGOProResourceLoader);
}
private cardReader!: CardReaderFinalized;
private lflist = blankLFList;
private async findLFList() {
const isTCG = this.hostinfo.rule === 1 && this.hostinfo.lflist === 0;
let index = 0;
for await (const lflist of this.resourceLoader.getLFLists()) {
if (isTCG) {
if (lflist.name?.includes(' TCG')) {
return lflist;
}
} else {
if (index === this.hostinfo.lflist) {
return lflist;
} else if (index > this.hostinfo.lflist) {
return undefined;
}
}
++index;
}
}
async init() {
this.cardReader = await this.resourceLoader.getCardReader();
if (this.hostinfo.lflist >= 0) {
this.lflist = (await this.findLFList()) || blankLFList;
}
return this;
}
private finalizors: RoomFinalizor[] = [];
addFinalizor(finalizor: RoomFinalizor) {
this.finalizors.push(finalizor);
return this;
}
async finalize() {
while (this.finalizors.length) {
const finalizor = this.finalizors.pop()!;
await finalizor(this);
}
}
get joinGameMessage() {
return new YGOProStocJoinGame().fromPartial({
info: {
...this.hostinfo,
lflist: this.lflist === blankLFList ? 0 : this.lflist.getHash(),
},
});
}
get watcherSizeMessage() {
return new YGOProStocHsWatchChange().fromPartial({
watch_count: this.watchers.size,
});
}
async join(client: Client) {
client.disconnect$.subscribe(({ bySystem }) =>
this.onPlayerDisconnect(client, bySystem),
);
client.isHost = !this.allPlayers.length;
const firstEmptyPlayerSlot = this.players.findIndex((p) => !p);
if (firstEmptyPlayerSlot >= 0) {
this.players[firstEmptyPlayerSlot] = client;
client.pos = firstEmptyPlayerSlot;
} else {
this.watchers.add(client);
client.pos = NetPlayerType.OBSERVER;
}
await client.send(this.joinGameMessage);
await client.sendTypeChange();
for (let i = 0; i < this.players.length; ++i) {
const p = this.players[i];
if (p) {
await client.send(p.prepareEnterPacket());
await p.send(client.prepareEnterPacket());
if (p.deck) {
await client.send(p.prepareChangePacket());
}
}
}
if (this.watchers.size) {
await client.send(this.watcherSizeMessage);
}
}
async onPlayerDisconnect(client: Client, bySystem: boolean) {
if (client.pos === NetPlayerType.OBSERVER) {
this.watchers.delete(client);
for (const p of this.allPlayers) {
p.send(this.watcherSizeMessage).then();
}
return;
}
}
}
import { Aragami } from 'aragami';
import { AppContext } from 'nfkit';
export class AragamiService {
constructor(private ctx: AppContext) {}
aragami = new Aragami();
}
...@@ -2,6 +2,7 @@ import { ...@@ -2,6 +2,7 @@ import {
YGOProCtosBase, YGOProCtosBase,
YGOProCtosExternalAddress, YGOProCtosExternalAddress,
YGOProCtosJoinGame, YGOProCtosJoinGame,
YGOProCtosLeaveGame,
YGOProCtosPlayerInfo, YGOProCtosPlayerInfo,
} from 'ygopro-msg-encode'; } from 'ygopro-msg-encode';
import { Context } from '../app'; import { Context } from '../app';
...@@ -12,45 +13,53 @@ import { forkJoin, filter, takeUntil, timeout, firstValueFrom } from 'rxjs'; ...@@ -12,45 +13,53 @@ import { forkJoin, filter, takeUntil, timeout, firstValueFrom } from 'rxjs';
export class ClientHandler { export class ClientHandler {
constructor(private ctx: Context) { constructor(private ctx: Context) {
this.ctx.middleware( this.ctx
YGOProCtosExternalAddress, .middleware(YGOProCtosExternalAddress, async (msg, client, next) => {
async (msg, client, next) => {
if (client instanceof WsClient || client.ip) { if (client instanceof WsClient || client.ip) {
// ws should tell real IP and hostname in http headers, so we skip this step for ws clients // ws should tell real IP and hostname in http headers, so we skip this step for ws clients
return next(); return next();
} }
this.ctx this.ctx
.get(IpResolver) .get(() => IpResolver)
.setClientIp( .setClientIp(
client, client,
msg.real_ip === '0.0.0.0' ? undefined : msg.real_ip, msg.real_ip === '0.0.0.0' ? undefined : msg.real_ip,
); );
client.hostname = msg.hostname?.split(':')[0] || ''; client.hostname = msg.hostname?.split(':')[0] || '';
return next(); return next();
}, })
); .middleware(YGOProCtosPlayerInfo, async (msg, client, next) => {
if (!client.ip) {
this.ctx.middleware(YGOProCtosPlayerInfo, async (msg, client, next) => { this.ctx.get(() => IpResolver).setClientIp(client);
if (!client.ip) { }
this.ctx.get(IpResolver).setClientIp(client); const [name, vpass] = msg.name.split('$');
} client.name = name;
const [name, vpass] = msg.name.split('$'); client.vpass = vpass || '';
client.name = name; return next();
client.vpass = vpass || ''; })
return next(); .middleware(
}); YGOProCtosBase,
this.ctx.middleware(YGOProCtosBase, async (msg, client, next) => { async (msg, client, next) => {
const isPreHandshakeMsg = [ const isPreHandshakeMsg = [
YGOProCtosExternalAddress, YGOProCtosExternalAddress,
YGOProCtosPlayerInfo, YGOProCtosPlayerInfo,
YGOProCtosJoinGame, YGOProCtosJoinGame,
].some((allowed) => msg instanceof allowed); ].some((allowed) => msg instanceof allowed);
if (client.established !== isPreHandshakeMsg) { if (client.established !== isPreHandshakeMsg) {
// disallow any messages before handshake is complete, except for the ones needed for handshake // disallow any messages before handshake is complete, except for the ones needed for handshake
return undefined; return undefined;
} }
return next(); return next();
}); },
true,
)
.middleware(
YGOProCtosLeaveGame, // this means immediately disconnect the client when they send leave game message, which is what official server does
async (msg, client, next) => {
return client.disconnect();
},
true,
);
} }
private logger = this.ctx.createLogger('ClientHandler'); private logger = this.ctx.createLogger('ClientHandler');
......
...@@ -4,15 +4,12 @@ import { ...@@ -4,15 +4,12 @@ import {
YGOProStocErrorMsg, YGOProStocErrorMsg,
} from 'ygopro-msg-encode'; } from 'ygopro-msg-encode';
import { Context } from '../app'; import { Context } from '../app';
import { convertNumberArray } from '../utility/convert-string-array';
const YGOPRO_VERSION = 0x1362; const YGOPRO_VERSION = 0x1362;
export class ClientVersionCheck { export class ClientVersionCheck {
private altVersions = this.ctx private altVersions = convertNumberArray(this.ctx.getConfig('ALT_VERSIONS'));
.getConfig('ALT_VERSIONS', '')
.split(',')
.map((v) => parseInt(v.trim()))
.filter((v) => v);
constructor(private ctx: Context) { constructor(private ctx: Context) {
this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => { this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => {
......
...@@ -6,6 +6,6 @@ import { ConfigService } from './config'; ...@@ -6,6 +6,6 @@ import { ConfigService } from './config';
export class HttpClient { export class HttpClient {
constructor(private ctx: AppContext) {} constructor(private ctx: AppContext) {}
http = axios.create({ http = axios.create({
...useProxy(this.ctx.get(ConfigService).getConfig('USE_PROXY', '')), ...useProxy(this.ctx.get(() => ConfigService).getConfig('USE_PROXY', '')),
}); });
} }
import { Context } from '../app'; import { Context } from '../app';
import { Client } from '../client'; import { Client } from '../client';
import * as ipaddr from 'ipaddr.js'; import * as ipaddr from 'ipaddr.js';
import { convertStringArray } from '../utility/convert-string-array';
export class IpResolver { export class IpResolver {
private logger = this.ctx.createLogger('IpResolver'); private logger = this.ctx.createLogger('IpResolver');
...@@ -9,16 +10,10 @@ export class IpResolver { ...@@ -9,16 +10,10 @@ export class IpResolver {
private trustedProxies: Array<[ipaddr.IPv4 | ipaddr.IPv6, number]> = []; private trustedProxies: Array<[ipaddr.IPv4 | ipaddr.IPv6, number]> = [];
constructor(private ctx: Context) { constructor(private ctx: Context) {
// Parse trusted proxies configuration const proxies = convertStringArray(
const trustedProxiesConfig = this.ctx.getConfig( this.ctx.getConfig('TRUSTED_PROXIES', '127.0.0.0/8,::1/128'),
'TRUSTED_PROXIES',
'127.0.0.0/8,::1/128',
); );
const proxies = trustedProxiesConfig
.split(',')
.map((s) => s.trim())
.filter(Boolean);
for (const trusted of proxies) { for (const trusted of proxies) {
try { try {
this.trustedProxies.push(ipaddr.parseCIDR(trusted)); this.trustedProxies.push(ipaddr.parseCIDR(trusted));
......
...@@ -5,7 +5,7 @@ import { ConfigService } from './config'; ...@@ -5,7 +5,7 @@ import { ConfigService } from './config';
export class Logger { export class Logger {
constructor(private ctx: AppContext) {} constructor(private ctx: AppContext) {}
private readonly logger = pino({ private readonly logger = pino({
level: this.ctx.get(ConfigService).getConfig('LOG_LEVEL') || 'info', level: this.ctx.get(() => ConfigService).getConfig('LOG_LEVEL') || 'info',
transport: { transport: {
target: 'pino-pretty', target: 'pino-pretty',
options: { options: {
......
import initSqlJs, { SqlJsStatic } from 'sql.js';
import { Context } from '../app';
import { loadPaths } from '../utility/load-path';
import { DirCardReader, searchYGOProResource } from 'koishipro-core.js';
import { YGOProLFList, YGOProLFListItem } from 'ygopro-lflist-encode';
import path from 'node:path';
export class YGOProResourceLoader {
constructor(private ctx: Context) {}
ygoproPaths = loadPaths(this.ctx.getConfig('YGOPRO_PATH')).flatMap((p) => [
path.join(p, 'expansions'),
p,
]);
extraScriptPaths = loadPaths(this.ctx.getConfig('EXTRA_SCRIPT_PATH'));
private SQL!: SqlJsStatic;
async init() {
this.SQL = await initSqlJs();
}
async getCardReader() {
return DirCardReader(this.SQL, ...this.ygoproPaths);
}
async *getLFLists() {
for await (const file of searchYGOProResource(...this.ygoproPaths)) {
const filename = path.basename(file.path);
if (filename !== 'lflist.conf') {
continue;
}
const buf = await file.read();
const lflist = new YGOProLFList().fromText(
Buffer.from(buf).toString('utf-8'),
);
for (const item of lflist.items) {
yield item;
}
}
}
}
...@@ -38,7 +38,7 @@ export class TcpServer { ...@@ -38,7 +38,7 @@ export class TcpServer {
private handleConnection(socket: Socket): void { private handleConnection(socket: Socket): void {
const client = new TcpClient(this.ctx, socket); const client = new TcpClient(this.ctx, socket);
const handler = this.ctx.get(ClientHandler); const handler = this.ctx.get(() => ClientHandler);
handler.handleClient(client).catch((err) => { handler.handleClient(client).catch((err) => {
this.logger.error({ err }, 'Error handling client'); this.logger.error({ err }, 'Error handling client');
}); });
......
...@@ -30,7 +30,7 @@ export class WsServer { ...@@ -30,7 +30,7 @@ export class WsServer {
const portNum = parseInt(wsPort, 10); const portNum = parseInt(wsPort, 10);
// Try to get SSL configuration // Try to get SSL configuration
const sslFinder = this.ctx.get(SSLFinder); const sslFinder = this.ctx.get(() => SSLFinder);
const sslOptions = sslFinder.findSSL(); const sslOptions = sslFinder.findSSL();
if (sslOptions) { if (sslOptions) {
...@@ -67,9 +67,9 @@ export class WsServer { ...@@ -67,9 +67,9 @@ export class WsServer {
private handleConnection(ws: WebSocket, req: IncomingMessage): void { private handleConnection(ws: WebSocket, req: IncomingMessage): void {
const client = new WsClient(this.ctx, ws, req); const client = new WsClient(this.ctx, ws, req);
if (this.ctx.get(IpResolver).setClientIp(client, client.xffIp())) return; if (this.ctx.get(() => IpResolver).setClientIp(client, client.xffIp())) return;
client.hostname = req.headers.host?.split(':')[0] || ''; client.hostname = req.headers.host?.split(':')[0] || '';
const handler = this.ctx.get(ClientHandler); const handler = this.ctx.get(() => ClientHandler);
handler.handleClient(client).catch((err) => { handler.handleClient(client).catch((err) => {
this.logger.error({ err }, 'Error handling client'); this.logger.error({ err }, 'Error handling client');
}); });
......
import { YGOProLFListItem } from 'ygopro-lflist-encode';
export const blankLFList = new YGOProLFListItem({
name: 'N/A',
});
export const convertStringArray = (str: string) =>
str
?.split(',')
.map((s) => s.trim())
.filter((s) => s) || [];
export const convertNumberArray = (str: string) =>
str
?.split(',')
.map((s) => parseInt(s.trim()))
.filter((n) => !isNaN(n)) || [];
import path from 'path';
import { convertStringArray } from './convert-string-array';
export const loadPaths = (pathStr: string) =>
convertStringArray(pathStr).map((p) => path.resolve(process.cwd(), p)) || [];
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment